-
2
require 'origen'
-
2
require_relative '../config/application.rb'
-
-
2
require 'active_support/concern'
-
2
require 'require_all'
-
2
require 'pathname'
-
2
require 'origen_testers/origen_ext/generator/pattern'
-
2
require 'origen_testers/origen_ext/generator/flow'
-
2
require 'origen_testers/origen_ext/generator/resources'
-
2
require 'origen_testers/origen_ext/application/runner'
-
2
require 'origen_testers/origen_ext/generator'
-
-
2
module OrigenTesters
-
2
autoload :CommandBasedTester, 'origen_testers/command_based_tester'
-
2
autoload :VectorBasedTester, 'origen_testers/vector_based_tester'
-
2
autoload :Vector, 'origen_testers/vector'
-
2
autoload :VectorPipeline, 'origen_testers/vector_pipeline'
-
2
autoload :Interface, 'origen_testers/interface'
-
2
autoload :Generator, 'origen_testers/generator'
-
2
autoload :Parser, 'origen_testers/parser'
-
2
autoload :BasicTestSetups, 'origen_testers/basic_test_setups'
-
2
autoload :ProgramGenerators, 'origen_testers/program_generators'
-
2
autoload :Flow, 'origen_testers/flow'
-
2
autoload :NoInterface, 'origen_testers/no_interface'
-
2
autoload :MemoryStyle, 'origen_testers/memory_style'
-
2
autoload :ATP, 'origen_testers/atp'
-
2
autoload :Charz, 'origen_testers/charz'
-
-
# not yet autoload :Time, 'origen_testers/time'
-
-
# The documentation tester model has been removed, but this keeps some
-
# legacy code working e.g. $tester.is_a?(OrigenTesters::Doc)
-
2
class Doc
-
end
-
-
2
def self.program
-
f = "#{Flow::PROGRAM_MODELS_DIR}/#{Origen.target.name}"
-
if File.exist?(f)
-
ATP::Program.load(f)
-
end
-
end
-
-
2
require 'origen_testers/decompiler'
-
2
extend Decompiler::API
-
end
-
2
autoload :ATP, 'origen_testers/atp_deprecation'
-
-
2
require 'origen_testers/igxl_based_tester'
-
2
require 'origen_testers/smartest_based_tester'
-
2
require 'origen_testers/stil_based_tester'
-
2
require 'origen_testers/labview_based_tester'
-
2
require 'origen_testers/pattern_compilers'
-
2
require 'origen_testers/pattern_compilers/runner'
-
-
2
require 'origen_testers/callback_handlers'
-
2
require 'origen_testers/origen_ext/pins/pin'
-
2
require 'origen_testers/origen_ext/pins/pin_collection'
-
2
require 'origen_testers/origen_ext/pins/timing'
-
2
require 'origen_testers/origen_ext/pins/timing/timeset'
-
2
module OrigenTesters
-
# This module implements the basic set of methods that a tester must have
-
# in order for Origen to talk to it.
-
#
-
# They can be overridden by tester specific classes and who may go on to add
-
# additional methods of their own.
-
#
-
# Essentially this API means that any class that includes Origen::Tester will
-
# function as a tester, although it might not do very much!
-
2
module API
-
2
attr_accessor :includes
-
2
attr_accessor :comment_level
-
2
attr_accessor :generating
-
-
# Get/Set the overlay style
-
#
-
# This method changes the way overlay is handled.
-
# The default value and possible settings is dependent on the individual tester.
-
#
-
# @example
-
# tester.overlay_style = :label
-
2
attr_accessor :overlay_style
-
-
# Get/Set the capture style
-
#
-
# This method changes the way tester.store() implements the store
-
# The default value and possible settings is dependent on the individual tester.
-
#
-
# @example
-
# tester.capture_style = :hram
-
2
attr_accessor :capture_style
-
-
2
def name
-
408
@name || self.class
-
end
-
-
2
def generate?
-
568
true
-
end
-
-
2
def generating_pattern?
-
@generating == :pattern
-
end
-
-
2
def generating_program?
-
@generating == :program
-
end
-
-
2
def pat_extension
-
2265
@pat_extension || 'txt'
-
end
-
2
alias_method :pattern_extension, :pat_extension
-
-
2
def comment_char=(val)
-
@comment_char = val
-
end
-
-
2
def comment_char
-
20799
@comment_char || '//'
-
end
-
-
2
def program_comment_char=(val)
-
@program_comment_char = val
-
end
-
-
2
def program_comment_char
-
194
@program_comment_char || comment_char
-
end
-
-
2
def pattern_header(*args)
-
end
-
-
2
def pattern_footer(*args)
-
end
-
-
2
def step_comment_prefix
-
3922
@step_comment_prefix || '##'
-
end
-
-
2
def is_vector_based?
-
39
return @vector_based if defined?(@vector_based)
-
39
true
-
end
-
-
2
def is_command_based?
-
!is_vector_based?
-
end
-
-
2
def j750?
-
3387
is_a?(OrigenTesters::IGXLBasedTester::J750)
-
end
-
-
2
def j750_hpt?
-
210
is_a?(OrigenTesters::IGXLBasedTester::J750_HPT)
-
end
-
-
2
def v93k?
-
33507
is_a?(OrigenTesters::SmartestBasedTester::V93K)
-
end
-
-
2
def ultraflex?
-
3110
is_a?(OrigenTesters::IGXLBasedTester::UltraFLEX)
-
end
-
2
alias_method :uflex?, :ultraflex?
-
-
2
def igxl?
-
6
j750? || j750_hpt? || ultraflex?
-
end
-
-
2
def stil?
-
10
is_a?(OrigenTesters::StilBasedTester::Base)
-
end
-
-
2
def d10?
-
is_a?(OrigenTesters::StilBasedTester::D10)
-
end
-
-
2
def link?
-
!!(self.class.to_s =~ /^OrigenLink::/)
-
end
-
-
2
def pxie6570?
-
10
is_a?(OrigenTesters::LabVIEWBasedTester::Pxie6570)
-
end
-
-
2
def doc?
-
2843
false
-
end
-
-
2
def smt7?
-
258
v93k? && smt_version.to_s[0] == '7'
-
end
-
-
2
def smt8?
-
21424
v93k? && smt_version.to_s[0] == '8'
-
end
-
-
2
def annotate(msg, options = {})
-
end
-
-
2
def diff_friendly_output=(value)
-
@diff_friendly_output = value
-
end
-
-
2
def diff_friendly_output?
-
2931
!!@diff_friendly_output
-
end
-
2
alias_method :diff_friendly_output, :diff_friendly_output?
-
-
# Ignore fails on the given pins for the duration of the given block, this
-
# has the effect of temporarily setting the states of the given pins to
-
# don't care.
-
2
def ignore_fails(*pins)
-
4
pins.each(&:suspend)
-
4
yield
-
4
pins.each(&:resume)
-
end
-
-
# Output a comment in the pattern, normally you would not call this directly
-
# and instead use these shorthand methods:
-
# cc "Some comment"
-
# ss "A single line step comment"
-
# step_comment do
-
# cc "A multi line"
-
# cc "step comment"
-
# end
-
2
def c1(msg, options = {})
-
9055
PatSeq.add_thread(msg) unless options[:no_thread_id]
-
9055
prefix = comment_char + ' '
-
9055
prefix += step_comment_prefix + ' ' if @step_comment_on
-
9055
if Origen.tester.generating == :program
-
33
cc_coms = OrigenTesters::Flow.cc_comments
-
# cc call must be on line directly before test method
-
33
line_number = caller_locations(2, 1)[0].lineno + 1
-
33
unless cc_coms[line_number]
-
2
cc_coms[line_number] = []
-
end
-
33
cc_coms[line_number] << msg
-
else
-
9022
push_comment(prefix + msg.to_s)
-
end
-
end
-
-
2
def c2(msg, options = {})
-
3124
c1(msg, options)
-
end
-
-
2
def pattern_section(msg)
-
if generating_program?
-
yield
-
else
-
step_comment(msg)
-
yield
-
end
-
end
-
-
2
def ss(msg = nil)
-
802
div = step_comment_prefix.length
-
802
div = 1 if div == 0
-
802
c1(step_comment_prefix * (70 / div), no_thread_id: true)
-
802
@step_comment_on = true
-
802
if block_given?
-
266
yield
-
else
-
536
c1(msg)
-
end
-
802
@step_comment_on = false
-
802
if $_testers_enable_vector_comments
-
timestamp = " #{execution_time_in_ns}ns #{step_comment_prefix}"
-
str = step_comment_prefix * (70 / div)
-
c1(str.sub(/#{step_comment_prefix}{#{timestamp.length - 1}}$/, timestamp), no_thread_id: true)
-
else
-
802
c1(step_comment_prefix * (70 / div), no_thread_id: true)
-
end
-
end
-
-
2
def snip(number, options = {})
-
yield
-
end
-
-
# Allows a section to be run without actually generating any vectors. This can be useful
-
# to ensure the pin states end up as they otherwise would have if the section had been run.
-
# Classic example of this is a subroutine pattern, wrap this around a call to the startup
-
# routine to ensure the pin states are as they would have been immediately after the startup.
-
# ==== Example
-
# # Setup state as if I had run startup without actually doing so
-
# $tester.inhibit_vectors_and_comments do
-
# $soc.startup
-
# $top.startup
-
# end
-
2
def inhibit_vectors_and_comments
-
11
inhibit_vectors = @inhibit_vectors
-
11
inhibit_comments = @inhibit_comments
-
11
@inhibit_vectors = true
-
11
@inhibit_comments = true
-
11
yield
-
11
@inhibit_vectors = inhibit_vectors # Restore to their initial state
-
11
@inhibit_comments = inhibit_comments
-
end
-
-
# Generate a vector.
-
# Calling this method will generate a vector in the output pattern based on the
-
# current pin states and timeset.
-
2
def cycle(options = {})
-
options = {
-
51882
microcode: '',
-
timeset: current_timeset,
-
pin_vals: current_pin_vals,
-
repeat: nil
-
}.merge(options)
-
-
51882
unless timeset.period_in_ns?
-
1
fail "You must supply a period_in_ns to timeset '#{timeset.name}' before you can cycle the tester!"
-
end
-
51881
timeset.cycled = true
-
51881
if PatSeq.thread
-
404
PatSeq.thread.cycle(options)
-
else
-
51477
if any_clocks_running?
-
update_running_clocks
-
if options[:repeat]
-
slice_repeats(options).each do |slice|
-
options[:repeat] = slice[0]
-
delay(options.delete(:repeat), options) do |options|
-
push_vector(options)
-
end
-
slice[1].each { |clock_pin_name| clocks_running[clock_pin_name].toggle_clock }
-
options[:pin_vals] = current_pin_vals
-
end
-
pins_need_toggling.each { |clock_pin_name| clocks_running[clock_pin_name].toggle_clock }
-
else
-
push_vector(options)
-
pins_need_toggling.each { |clock_pin_name| clocks_running[clock_pin_name].toggle_clock }
-
end
-
else
-
51477
if options[:repeat]
-
1607
delay(options.delete(:repeat), options) do |options|
-
1890
push_vector(options)
-
end
-
else
-
49870
push_vector(options)
-
end
-
end
-
end
-
end
-
-
2
def import_test_time(file, options = {})
-
puts "Sorry but an importer doesn't exist for: #{Origen.tester.class}"
-
end
-
-
2
def any_clocks_running?
-
51477
@clocks_running.nil? ? false : @clocks_running.count > 0
-
end
-
-
2
def clocks_running
-
@clocks_running
-
end
-
2
alias_method :running_clocks, :clocks_running
-
-
2
def push_running_clock(pin)
-
@clocks_running.nil? ? @clocks_running = { pin.name.to_s => pin } : @clocks_running[pin.name.to_s] = pin
-
end
-
-
2
def pop_running_clock(pin)
-
fail "ERROR: No clocks running, doesn't make sense to pop one" unless any_clocks_running?
-
@clocks_running.delete(pin.name.to_s)
-
end
-
-
2
def slice_repeats(options = {})
-
slices = {}
-
repeat_ary = []
-
clocks_running.each do |name, clock_pin|
-
if clock_pin.next_edge < (cycle_count + options[:repeat])
-
if clock_pin.respond_to?(:duty_cycles)
-
d0, d1 = clock_pin.duty_cycles
-
else
-
# keep legacy support for older pin_clock styling, supports only 50% duty-cycle
-
d0 = clock_pin.half_period
-
d1 = clock_pin.half_period
-
end
-
pin_slices = (clock_pin.next_edge..(cycle_count + options[:repeat])).step(d0 + d1).to_a
-
pin_slices += ((clock_pin.next_edge + d0)..(cycle_count + options[:repeat])).step(d0 + d1).to_a
-
pin_slices.sort!
-
pin_slices.insert(0, cycle_count)
-
else
-
pin_slices = [cycle_count]
-
end
-
pin_slices.each do |cycle|
-
slices[cycle].nil? ? slices[cycle] = name : slices[cycle] = "#{slices[cycle]},#{name}"
-
end
-
slices[cycle_count + options[:repeat]] = '' if pin_slices[-1] != cycle_count + options[:repeat]
-
end
-
slices.keys.sort.each do |edge_cycles|
-
# puts "Toggle #{slices[edge_cycles]} on #{edge_cycles}"
-
repeat_ary.push([edge_cycles, slices[edge_cycles].split(',')])
-
end
-
-
(repeat_ary.count - 1).downto(1).each { |i| repeat_ary[i][0] = repeat_ary[i][0] - repeat_ary[i - 1][0] }
-
repeat_ary[1..-1]
-
end
-
-
2
def pins_need_toggling
-
toggle_ary = []
-
clocks_running.each do |name, clock_pin|
-
toggle_ary.push("#{name}") if clock_pin.next_edge == cycle_count
-
end
-
toggle_ary
-
end
-
-
2
def update_running_clocks
-
clocks_running.each do |name, clock_pin|
-
clock_pin.update_clock
-
end
-
end
-
-
2
def transaction
-
yield
-
true
-
end
-
-
2
def source_memory_config
-
37
@source_memory_config ||= {}
-
end
-
-
2
def capture_memory_config
-
26
@capture_memory_config ||= {}
-
end
-
-
# Configure source memory to a non-default setting
-
#
-
# This method changes the way the instruments statement gets rendered
-
# if the tester's source memory is used.
-
#
-
# @example
-
# tester.source_memory :default do |mem|
-
# mem.pin :tdi, size: 32, format: :long
-
# end
-
#
-
# If called without a block, this method will return
-
# the instance of type OrigenTesters::MemoryStyle for
-
# the corresponding memory type
-
#
-
# @example
-
# mem_style = tester.source_memory(:default)
-
# mem_style.contained_pins.each do |pin|
-
# attributes_hash = mem_style.accumulate_attributes(pin)
-
#
-
# end
-
2
def source_memory(type = :default)
-
15
type = :subroutine if type == :default
-
15
source_memory_config[type] = OrigenTesters::MemoryStyle.new unless source_memory_config.key?(type)
-
15
if block_given?
-
7
yield source_memory_config[type]
-
else
-
8
source_memory_config[type]
-
end
-
end
-
-
# Configure capture memory to a non-default setting
-
#
-
# This method changes the way the instruments statement gets rendered
-
# if the tester's capture memory is used.
-
#
-
# @example
-
# tester.capture_memory :default do |mem|
-
# mem.pin :tdo, size: 32, format: :long
-
# end
-
#
-
# If called without a block, this method will return
-
# the instance of type OrigenTesters::MemoryStyle for
-
# the corresponding memory type
-
#
-
# @example
-
# mem_style = tester.capture_memory(:default)
-
# if mem_style.contains_pin?(:tdo)
-
# attributes_hash = mem_style.accumulate_attributes(:tdo)
-
#
-
# end
-
2
def capture_memory(type = :default)
-
10
type = :hram if type == :default
-
10
capture_memory_config[type] = OrigenTesters::MemoryStyle.new unless capture_memory_config.key?(type)
-
10
if block_given?
-
6
yield capture_memory_config[type]
-
else
-
4
capture_memory_config[type]
-
end
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
autoload :Program, 'origen_testers/atp/program'
-
2
autoload :Flow, 'origen_testers/atp/flow'
-
2
autoload :Processor, 'origen_testers/atp/processor'
-
2
autoload :Validator, 'origen_testers/atp/validator'
-
2
autoload :Runner, 'origen_testers/atp/runner'
-
2
autoload :Formatter, 'origen_testers/atp/formatter'
-
2
autoload :Parser, 'origen_testers/atp/parser'
-
2
autoload :FlowAPI, 'origen_testers/atp/flow_api'
-
-
2
module AST
-
2
autoload :Node, 'origen_testers/atp/ast/node'
-
2
autoload :Extractor, 'origen_testers/atp/ast/extractor'
-
-
# This is a shim to help backwards compatibility with ATP v0
-
2
module Builder
-
2
class LazyObject < ::BasicObject
-
2
def initialize(&callable)
-
2
@callable = callable
-
end
-
-
2
def __target_object__
-
@__target_object__ ||= @callable.call
-
end
-
-
2
def method_missing(method_name, *args, &block)
-
__target_object__.send(method_name, *args, &block)
-
end
-
end
-
-
# Some trickery to lazy load this to fire a deprecation warning if an app references it
-
2
CONDITION_KEYS ||= LazyObject.new do
-
Origen.log.deprecate 'ATP::AST::Builder::CONDITION_KEYS is frozen and is no longer maintained, consider switching to ATP::Flow::CONDITION_KEYS.keys for similar functionality'
-
[:if_enabled, :enabled, :enable_flag, :enable, :if_enable, :unless_enabled, :not_enabled,
-
:disabled, :disable, :unless_enable, :if_failed, :unless_passed, :failed, :if_passed,
-
:unless_failed, :passed, :if_ran, :if_executed, :unless_ran, :unless_executed, :job,
-
:jobs, :if_job, :if_jobs, :unless_job, :unless_jobs, :if_any_failed, :unless_all_passed,
-
:if_all_failed, :unless_any_passed, :if_any_passed, :unless_all_failed, :if_all_passed,
-
:unless_any_failed, :if_flag, :unless_flag, :whenever, :whenever_all, :whenever_any]
-
end
-
end
-
end
-
-
# Processors actually modify the AST to clean and optimize the user input
-
# and to implement the flow control API
-
2
module Processors
-
2
autoload :Condition, 'origen_testers/atp/processors/condition'
-
2
autoload :Relationship, 'origen_testers/atp/processors/relationship'
-
2
autoload :PreCleaner, 'origen_testers/atp/processors/pre_cleaner'
-
2
autoload :Marshal, 'origen_testers/atp/processors/marshal'
-
2
autoload :AddIDs, 'origen_testers/atp/processors/add_ids'
-
2
autoload :AddSetResult, 'origen_testers/atp/processors/add_set_result'
-
2
autoload :FlowID, 'origen_testers/atp/processors/flow_id'
-
2
autoload :EmptyBranchRemover, 'origen_testers/atp/processors/empty_branch_remover'
-
2
autoload :AppendTo, 'origen_testers/atp/processors/append_to'
-
2
autoload :Flattener, 'origen_testers/atp/processors/flattener'
-
2
autoload :RedundantConditionRemover, 'origen_testers/atp/processors/redundant_condition_remover'
-
2
autoload :ElseRemover, 'origen_testers/atp/processors/else_remover'
-
2
autoload :OnPassFailRemover, 'origen_testers/atp/processors/on_pass_fail_remover'
-
2
autoload :ApplyPostGroupActions, 'origen_testers/atp/processors/apply_post_group_actions'
-
2
autoload :OneFlagPerTest, 'origen_testers/atp/processors/one_flag_per_test'
-
2
autoload :FlagOptimizer, 'origen_testers/atp/processors/flag_optimizer'
-
2
autoload :AdjacentIfCombiner, 'origen_testers/atp/processors/adjacent_if_combiner'
-
2
autoload :ContinueImplementer, 'origen_testers/atp/processors/continue_implementer'
-
2
autoload :ExtractSetFlags, 'origen_testers/atp/processors/extract_set_flags'
-
2
autoload :SubFlowRemover, 'origen_testers/atp/processors/sub_flow_remover'
-
end
-
-
# Summarizers extract summary data from the given AST
-
2
module Summarizers
-
end
-
-
# Validators are run on the processed AST to check it for common errors or
-
# logical issues that will prevent it being rendered to a test program format
-
2
module Validators
-
2
autoload :DuplicateIDs, 'origen_testers/atp/validators/duplicate_ids'
-
2
autoload :MissingIDs, 'origen_testers/atp/validators/missing_ids'
-
2
autoload :Condition, 'origen_testers/atp/validators/condition'
-
2
autoload :Jobs, 'origen_testers/atp/validators/jobs'
-
2
autoload :Flags, 'origen_testers/atp/validators/flags'
-
end
-
-
# Formatters are run on the processed AST to display the flow or to render
-
# it to a different format
-
2
module Formatters
-
2
autoload :Basic, 'origen_testers/atp/formatters/basic'
-
2
autoload :Datalog, 'origen_testers/atp/formatters/datalog'
-
end
-
-
# Maintains a unique ID counter to ensure that all nodes get a unique ID
-
2
def self.next_id
-
17915
@next_id ||= 0
-
17915
@next_id += 1
-
end
-
end
-
2
require 'ast'
-
2
module OrigenTesters::ATP
-
2
module AST
-
2
class Extractor
-
2
include ::AST::Processor::Mixin
-
-
2
attr_reader :types
-
2
attr_reader :results
-
-
2
def process(node, types = nil)
-
9051
if types
-
26
@types = types
-
26
@results = []
-
# node = AST::Node.new(:wrapper, node) unless node.respond_to?(:to_ast)
-
end
-
9051
super(node) if node.respond_to?(:to_ast)
-
9051
results
-
end
-
-
2
def handler_missing(node)
-
4920
@results << node if types.include?(node.type)
-
4920
process_all(node.children)
-
end
-
end
-
end
-
end
-
2
require 'ast'
-
2
module OrigenTesters::ATP
-
2
module AST
-
2
class Node < ::AST::Node
-
2
attr_reader :file, :line_number, :description, :properties
-
2
attr_accessor :id
-
-
2
def initialize(type, children = [], properties = {})
-
66540
@properties = properties
-
# Always use strings instead of symbols in the AST, makes serializing
-
# back and forward to a string easier
-
435876
children = children.map { |c| c.is_a?(Symbol) ? c.to_s : c }
-
66540
super type, children, properties
-
end
-
-
2
def _dump(depth)
-
# this strips the @strip information from the instance
-
# d = { type: type, children: children, properties: properties }
-
18447
d = { klass: self.class,
-
id: id,
-
file: file,
-
line_number: line_number,
-
description: description,
-
type: type,
-
children: Processors::Marshal.new.process_all(children),
-
properties: properties
-
}
-
18447
Marshal.dump(d, depth)
-
end
-
-
2
def self._load(str)
-
13
d = Marshal.load(str)
-
13
p = d[:properties]
-
13
p[:id] = d[:id]
-
13
p[:file] = d[:file]
-
13
p[:line_number] = d[:line_number]
-
13
p[:description] = d[:description]
-
13
n = d[:klass].new(d[:type], d[:children], p)
-
13
n
-
end
-
-
2
def source
-
11
if file
-
11
"#{file}:#{line_number}"
-
else
-
'<Sorry, lost the source file info, please include an example if you report as a bug>'
-
end
-
end
-
-
# Returns true if the node carries source file data, retrieve it via the source method
-
2
def has_source?
-
!!file
-
end
-
-
# Create a new node from the given S-expression (a string)
-
2
def self.from_sexp(sexp)
-
2
@parser ||= Parser.new
-
2
@parser.string_to_ast(sexp)
-
end
-
-
# Adds an empty node of the given type to the children unless another
-
# node of the same type is already present
-
2
def ensure_node_present(type, *child_nodes)
-
19394
if children.any? { |n| n.type == type }
-
890
self
-
else
-
3677
if !child_nodes.empty?
-
51
node = updated(type, child_nodes)
-
else
-
3626
node = updated(type, [])
-
end
-
3677
updated(nil, children + [node])
-
end
-
end
-
-
# Returns the value at the root of an AST node like this:
-
#
-
# node # => (module-def
-
# (module-name
-
# (SCALAR-ID "Instrument"))
-
#
-
# node.value # => "Instrument"
-
#
-
# No error checking is done and the caller is responsible for calling
-
# this only on compatible nodes
-
2
def value
-
25599
val = children.first
-
25599
val = val.children.first while val.respond_to?(:children)
-
25599
val
-
end
-
-
# Add the given nodes to the children
-
2
def add(*nodes)
-
564
updated(nil, children + nodes)
-
end
-
-
# Remove the given nodes (or types) from the children
-
2
def remove(*nodes)
-
784
nodes = nodes.map do |node|
-
840
if node.is_a?(Symbol)
-
110
find_all(node)
-
else
-
730
node
-
end
-
end.flatten.compact
-
784
updated(nil, children - nodes)
-
end
-
-
# Returns the first child node of the given type(s) that is found
-
2
def find(*types)
-
156137
children.find { |c| types.include?(c.try(:type)) }
-
end
-
-
# Returns an array containing all child nodes of the given type(s), by default only considering
-
# the immediate children of the node on which this was called.
-
#
-
# To find all children of the given type by recursively searching through all child nodes, pass
-
# recursive: true when calling this method.
-
2
def find_all(*types)
-
3398
options = types.pop if types.last.is_a?(Hash)
-
3398
options ||= {}
-
3398
if options[:recursive]
-
15
Extractor.new.process(self, types)
-
else
-
15491
children.select { |c| types.include?(c.try(:type)) }
-
end
-
end
-
-
# Returns an array containing all flags which are set within the given node
-
2
def set_flags
-
84
Processors::ExtractSetFlags.new.run(self)
-
end
-
-
# Returns a copy of node with any sub-flow nodes removed
-
2
def excluding_sub_flows
-
85
Processors::SubFlowRemover.new.run(self)
-
end
-
-
# Returns true if the node contains any nodes of the given type(s) or if any
-
# of its children do.
-
# To consider only direct children of this node use: node.find_all(*types).empty?
-
2
def contains?(*types)
-
7
!Extractor.new.process(self, types).empty?
-
end
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
# Implements the main user API for building and interacting
-
# with an abstract test program
-
2
class Flow
-
2
attr_reader :program, :name
-
-
CONDITION_KEYS = {
-
2
if_enabled: :if_enabled,
-
if_enable: :if_enabled,
-
enabled: :if_enabled,
-
enable_flag: :if_enabled,
-
enable: :if_enabled,
-
-
unless_enabled: :unless_enabled,
-
not_enabled: :unless_enabled,
-
disabled: :unless_enabled,
-
disable: :unless_enabled,
-
unless_enable: :unless_enabled,
-
-
if_failed: :if_failed,
-
unless_passed: :if_failed,
-
failed: :if_failed,
-
-
if_passed: :if_passed,
-
unless_failed: :if_passed,
-
passed: :if_passed,
-
-
if_any_failed: :if_any_failed,
-
unless_all_passed: :if_any_failed,
-
-
if_all_failed: :if_all_failed,
-
unless_any_passed: :if_all_failed,
-
-
if_any_passed: :if_any_passed,
-
unless_all_failed: :if_any_passed,
-
-
if_all_passed: :if_all_passed,
-
unless_any_failed: :if_all_passed,
-
-
if_ran: :if_ran,
-
if_executed: :if_ran,
-
-
unless_ran: :unless_ran,
-
unless_executed: :unless_ran,
-
-
job: :if_job,
-
jobs: :if_job,
-
if_job: :if_job,
-
if_jobs: :if_job,
-
-
unless_job: :unless_job,
-
unless_jobs: :unless_job,
-
-
if_flag: :if_flag,
-
-
unless_flag: :unless_flag,
-
-
whenever: :whenever,
-
whenever_all: :whenever_all,
-
whenever_any: :whenever_any,
-
-
group: :group,
-
-
if_any_site_failed: :if_any_sites_failed,
-
if_any_sites_failed: :if_any_sites_failed,
-
unless_all_sites_passed: :if_any_sites_failed,
-
-
if_all_sites_failed: :if_all_sites_failed,
-
unless_any_sites_passed: :if_all_sites_failed,
-
unless_any_site_passed: :if_all_sites_failed,
-
-
if_any_site_passed: :if_any_sites_passed,
-
if_any_sites_passed: :if_any_sites_passed,
-
unless_all_sites_failed: :if_any_sites_passed,
-
-
if_all_sites_passed: :if_all_sites_passed,
-
unless_any_sites_failed: :if_all_sites_passed,
-
unless_any_site_failed: :if_all_sites_passed
-
}
-
-
2
CONDITION_NODE_TYPES = CONDITION_KEYS.values.uniq
-
-
2
RELATIONAL_OPERATORS = [:eq, :ne, :lt, :le, :gt, :ge]
-
-
2
def initialize(program, name = nil, options = {})
-
251
name, options = nil, name if name.is_a?(Hash)
-
251
@source_file = []
-
251
@source_line_number = []
-
251
@description = []
-
251
@program = program
-
251
@name = name
-
251
extract_meta!(options) do
-
251
@pipeline = [n1(:flow, n1(:name, name))]
-
end
-
end
-
-
# @api private
-
2
def marshal_dump
-
107
[@name, @program, Processors::Marshal.new.process(raw)]
-
end
-
-
# @api private
-
2
def marshal_load(array)
-
@name, @program, raw = array
-
@pipeline = [raw]
-
end
-
-
# Returns the raw AST
-
2
def raw
-
364
n = nil
-
364
@pipeline.reverse_each do |node|
-
364
if n
-
n = node.updated(nil, node.children + [n])
-
else
-
364
n = node
-
end
-
end
-
364
n
-
end
-
-
# Returns a processed/optimized AST, this is the one that should be
-
# used to build and represent the given test flow
-
2
def ast(options = {})
-
options = {
-
133
apply_relationships: true,
-
# Supply a unique ID to append to all IDs
-
unique_id: nil,
-
# Set to :smt, or :igxl
-
optimization: :runner,
-
# When true, will remove set_result nodes in an on_fail branch which contains a continue
-
implement_continue: true,
-
# When false, this will not optimize the use of a flag by nesting a dependent test within
-
# the parent test's on_fail branch if the on_fail contains a continue
-
optimize_flags_when_continue: true,
-
# These options are not intended for application use, but provide the ability to
-
# turn off certain processors during test cases
-
add_ids: true,
-
optimize_flags: true,
-
one_flag_per_test: true,
-
include_sub_flows: true
-
}.merge(options)
-
###############################################################################
-
## Common pre-processing and validation
-
###############################################################################
-
133
ast = Processors::PreCleaner.new.run(raw)
-
133
Validators::DuplicateIDs.new(self).run(ast)
-
132
Validators::MissingIDs.new(self).run(ast)
-
131
Validators::Jobs.new(self).run(ast)
-
128
Validators::Flags.new(self).run(ast)
-
# Ensure everything has an ID, this helps later if condition nodes need to be generated
-
127
ast = Processors::AddIDs.new.run(ast) if options[:add_ids]
-
127
ast = Processors::FlowID.new.run(ast, options[:unique_id]) if options[:unique_id]
-
127
ast = Processors::SubFlowRemover.new.run(ast) unless options[:include_sub_flows]
-
-
###############################################################################
-
## Optimization for a C-like flow target, e.g. V93K
-
###############################################################################
-
127
if options[:optimization] == :smt || options[:optimization] == :runner
-
# This applies all the relationships by setting flags in the referenced test and
-
# changing all if_passed/failed type nodes to if_flag type nodes
-
83
ast = Processors::Relationship.new.run(ast) if options[:apply_relationships]
-
83
ast = Processors::Condition.new.run(ast)
-
83
unless options[:optimization] == :runner
-
58
ast = Processors::ContinueImplementer.new.run(ast) if options[:implement_continue]
-
end
-
83
if options[:optimize_flags]
-
83
ast = Processors::FlagOptimizer.new.run(ast, optimize_when_continue: options[:optimize_flags_when_continue])
-
end
-
83
ast = Processors::AdjacentIfCombiner.new.run(ast)
-
-
###############################################################################
-
## Optimization for a row-based target, e.g. UltraFLEX
-
###############################################################################
-
44
elsif options[:optimization] == :igxl
-
# Un-nest everything embedded in else nodes
-
26
ast = Processors::ElseRemover.new.run(ast)
-
# Un-nest everything embedded in on_pass/fail nodes except for binning and
-
# flag setting
-
26
ast = Processors::OnPassFailRemover.new.run(ast)
-
# This applies all the relationships by setting flags in the referenced test and
-
# changing all if_passed/failed type nodes to if_flag type nodes
-
26
ast = Processors::Relationship.new.run(ast) if options[:apply_relationships]
-
26
ast = Processors::Condition.new.run(ast)
-
26
ast = Processors::ApplyPostGroupActions.new.run(ast)
-
26
ast = Processors::OneFlagPerTest.new.run(ast) if options[:one_flag_per_test]
-
26
ast = Processors::RedundantConditionRemover.new.run(ast)
-
-
###############################################################################
-
## Not currently used, more of a test case
-
###############################################################################
-
18
elsif options[:optimization] == :flat
-
# Un-nest everything embedded in else nodes
-
4
ast = Processors::ElseRemover.new.run(ast)
-
# Un-nest everything embedded in on_pass/fail nodes except for binning and
-
# flag setting
-
4
ast = Processors::OnPassFailRemover.new.run(ast)
-
4
ast = Processors::Condition.new.run(ast)
-
4
ast = Processors::Flattener.new.run(ast)
-
-
###############################################################################
-
## Default Optimization
-
###############################################################################
-
else
-
14
ast = Processors::Condition.new.run(ast)
-
end
-
-
###############################################################################
-
## Common cleanup
-
###############################################################################
-
# Removes any empty on_pass and on_fail branches
-
127
ast = Processors::EmptyBranchRemover.new.run(ast)
-
127
ast
-
end
-
-
# Indicate the that given flags should be considered volatile (can change at any time), which will
-
# prevent them from been touched by the optimization algorithms
-
2
def volatile(*flags)
-
10
options = flags.pop if flags.last.is_a?(Hash)
-
10
flags = flags.flatten
-
10
@pipeline[0] = add_volatile_flags(@pipeline[0], flags)
-
end
-
-
# Indicate the that given flags should keep state between units
-
# prevent them from being in the initialization block
-
# these flags will be the user's responsibility to initialize
-
2
def add_global_flag(*flags)
-
8
options = flags.pop if flags.last.is_a?(Hash)
-
8
flags = flags.flatten
-
8
@pipeline[0] = add_global_flag_to_node(@pipeline[0], flags)
-
end
-
-
# Record a description for a bin number
-
2
def describe_bin(number, description, options = {})
-
2
@pipeline[0] = add_bin_description(@pipeline[0], number, description, type: :hard)
-
end
-
-
# Record a description for a softbin number
-
2
def describe_soft_bin(number, description, options = {})
-
2
@pipeline[0] = add_bin_description(@pipeline[0], number, description, type: :soft)
-
end
-
2
alias_method :describe_softbin, :describe_soft_bin
-
-
# Group all tests generated within the given block
-
#
-
# @example
-
# flow.group "RAM Tests" do
-
# flow.test ...
-
# flow.test ...
-
# end
-
2
def group(name, options = {}, &block)
-
# The idiomatic way of creating a group in SMT8 is a sub-flow
-
242
if tester.try(:smt8?)
-
28
extract_meta!(options) do
-
28
apply_conditions(options) do
-
28
parent, sub_flow = *::Flow._sub_flow(name, options, &block)
-
28
path = sub_flow.output_file.relative_path_from(Origen.file_handler.output_directory)
-
28
ast = sub_flow.atp.raw
-
28
name, *children = *ast
-
28
nodes = [name]
-
28
nodes << id(options[:id]) if options[:id]
-
28
nodes << n1(:path, path.to_s)
-
28
nodes += children
-
28
ast = ast.updated :sub_flow, nodes,
-
file: options.delete(:source_file) || source_file,
-
line_number: options.delete(:source_line_number) || source_line_number,
-
description: options.delete(:description) || description
-
28
ast
-
end
-
end
-
else
-
214
extract_meta!(options) do
-
214
apply_conditions(options) do
-
214
children = [n1(:name, name)]
-
214
children << n1(:bypass, options[:bypass]) if options[:bypass]
-
214
if options[:comment] || options[:description] || options[:desc]
-
4
children << n1(:comment, options[:comment] || options[:description] || options[:desc])
-
end
-
214
children << id(options[:id]) if options[:id]
-
214
children << on_fail(options[:on_fail]) if options[:on_fail]
-
214
children << on_pass(options[:on_pass]) if options[:on_pass]
-
214
g = n(:group, children)
-
428
append_to(g) { yield }
-
end
-
end
-
end
-
end
-
-
# Add a test line to the flow
-
#
-
# @param [String, Symbol] the name of the test
-
# @param [Hash] options a hash to describe the test's attributes
-
# @option options [Symbol] :id A unique test ID
-
# @option options [String] :description A description of what the test does, usually formatted in markdown
-
# @option options [Hash] :on_fail What action to take if the test fails, e.g. assign a bin
-
# @option options [Hash] :on_pass What action to take if the test passes
-
# @option options [Hash] :conditions What conditions must be met to execute the test
-
2
def test(instance, options = {})
-
3124
extract_meta!(options) do
-
3124
apply_conditions(options) do
-
3124
if options[:on_fail].is_a?(Proc)
-
14
before_on_fail = options.delete(:on_fail)
-
end
-
3124
if options[:on_pass].is_a?(Proc)
-
8
before_on_pass = options.delete(:on_pass)
-
end
-
# Allows any continue, bin, or soft bin argument passed in at the options top-level to be assumed
-
# to be the action to take if the test fails
-
3124
if b = options.delete(:bin)
-
537
options[:on_fail] ||= {}
-
537
options[:on_fail][:bin] = b
-
end
-
3124
if b = options.delete(:bin_description)
-
3
options[:on_fail] ||= {}
-
3
options[:on_fail][:bin_description] = b
-
end
-
3124
if b = options.delete(:bin_attrs)
-
4
options[:on_fail] ||= {}
-
4
options[:on_fail][:bin_attrs] = b
-
end
-
3124
if b = options.delete(:softbin) || b = options.delete(:sbin) || b = options.delete(:soft_bin)
-
199
options[:on_fail] ||= {}
-
199
options[:on_fail][:softbin] = b
-
end
-
3124
if b = options.delete(:softbin_description) || options.delete(:sbin_description) || options.delete(:soft_bin_description)
-
2
options[:on_fail] ||= {}
-
2
options[:on_fail][:softbin_description] = b
-
end
-
3124
if options.delete(:continue)
-
92
options[:on_fail] ||= {}
-
92
options[:on_fail][:continue] = true
-
end
-
3124
if options.key?(:delayed)
-
1
options[:on_fail] ||= {}
-
1
options[:on_fail][:delayed] = options.delete(:delayed)
-
end
-
3124
if f = options.delete(:flag_pass)
-
options[:on_pass] ||= {}
-
options[:on_pass][:set_flag] = f
-
end
-
3124
if f = options.delete(:flag_fail)
-
options[:on_fail] ||= {}
-
options[:on_fail][:set_flag] = f
-
end
-
-
3124
children = [n1(:object, instance)]
-
-
3124
name = (options[:name] || options[:tname] || options[:test_name])
-
3124
unless name
-
# Starting in Ruby3 type Symbol responds to name
-
3104
unless instance.is_a?(Symbol)
-
2447
[:name, :tname, :test_name].each do |m|
-
7341
name ||= instance.respond_to?(m) ? instance.send(m) : nil
-
end
-
end
-
end
-
3124
children << n1(:name, name) if name
-
-
3124
num = (options[:number] || options[:num] || options[:tnum] || options[:test_number])
-
3124
unless num
-
492
[:number, :num, :tnum, :test_number].each do |m|
-
1968
num ||= instance.respond_to?(m) ? instance.send(m) : nil
-
end
-
end
-
3124
children << number(num) if num
-
-
3124
children << id(options[:id]) if options[:id]
-
-
3124
if levels = options[:level] || options[:levels]
-
2
levels = [levels] unless levels.is_a?(Array)
-
2
levels.each do |l|
-
3
children << level(l[:name], l[:value], l[:unit] || l[:units])
-
end
-
end
-
-
3124
lims = options[:limit] || options[:limits]
-
3124
if lims || options[:lo] || options[:low] || options[:hi] || options[:high]
-
1497
if lims == :none || lims == 'none'
-
1
children << n0(:nolimits)
-
else
-
1496
lims = Array(lims) unless lims.is_a?(Array)
-
1496
if lo = options[:lo] || options[:low]
-
11
lims << { value: lo, rule: :gte }
-
end
-
1496
if hi = options[:hi] || options[:high]
-
11
lims << { value: hi, rule: :lte }
-
end
-
1496
lims.each do |l|
-
188
if l.is_a?(Hash)
-
188
children << n(:limit, [l[:value], l[:rule], l[:unit] || l[:units], l[:selector]])
-
end
-
end
-
end
-
end
-
-
3124
if pins = options[:pin] || options[:pins]
-
7
pins = [pins] unless pins.is_a?(Array)
-
7
pins.each do |p|
-
8
if p.is_a?(Hash)
-
3
children << pin(p[:name])
-
else
-
5
children << pin(p)
-
end
-
end
-
end
-
-
3124
if pats = options[:pattern] || options[:patterns]
-
2
pats = [pats] unless pats.is_a?(Array)
-
2
pats.each do |p|
-
3
if p.is_a?(Hash)
-
1
children << pattern(p[:name], p[:path])
-
else
-
2
children << pattern(p)
-
end
-
end
-
end
-
-
3124
if options[:meta]
-
1
attrs = []
-
3
options[:meta].each { |k, v| attrs << attribute(k, v) }
-
1
children << n(:meta, attrs)
-
end
-
-
3124
if options[:test_text]
-
10
children << n(:test_text, [options[:test_text]])
-
end
-
-
3124
if subs = options[:sub_test] || options[:sub_tests]
-
6
subs = [subs] unless subs.is_a?(Array)
-
6
subs.each do |s|
-
12
children << s.updated(:sub_test, nil)
-
end
-
end
-
-
3124
if before_on_fail
-
14
on_fail_node = on_fail(before_on_fail)
-
14
if options[:on_fail]
-
1
on_fail_node = on_fail_node.updated(nil, on_fail_node.children + on_fail(options[:on_fail]).children)
-
end
-
14
children << on_fail_node
-
else
-
3110
children << on_fail(options[:on_fail]) if options[:on_fail]
-
end
-
-
3124
if before_on_pass
-
8
on_pass_node = on_pass(before_on_pass)
-
8
if options[:on_pass]
-
on_pass_node = on_pass_node.updated(nil, on_pass_node.children + on_pass(options[:on_pass]).children)
-
end
-
8
children << on_pass_node
-
else
-
3116
children << on_pass(options[:on_pass]) if options[:on_pass]
-
end
-
-
3124
children << priority(options[:priority]) if options[:priority]
-
-
3124
save_conditions
-
3124
n(:test, children)
-
end
-
end
-
end
-
-
# Equivalent to calling test, but returns a sub_test node instead of adding it to the flow.
-
#
-
# This is a helper to create sub_tests for inclusion in a top-level test node.
-
2
def sub_test(instance, options = {})
-
24
temp = append_to(n0(:temp)) { test(instance, options) }
-
12
temp.children.first.updated(:sub_test, nil)
-
end
-
-
2
def sub_flow(flow_node, options = {})
-
28
name, *children = *flow_node
-
28
if options[:path]
-
26
children = [name] + [n1(:path, options[:path])] + children
-
else
-
2
children = [name] + children
-
end
-
28
apply_conditions(options) do
-
28
flow_node.updated(:sub_flow, children)
-
end
-
end
-
-
2
def add_auxiliary_flow(name, options = {})
-
2
if tester.smt8?
-
2
if name.to_s != options[:path].split('.').last.to_s
-
fail "Auxiliary flow path does not end in '#{name}'. The path instead is '#{options[:path]}'. Please update the path to align with the provided name."
-
end
-
2
extract_meta!(options) do
-
2
apply_conditions(options) do
-
2
n2(:auxiliary_flow, n1(:name, name), n1(:path, options[:path]))
-
end
-
end
-
else
-
fail 'Auxiliary flow API is only usable in SMT8.'
-
end
-
end
-
-
2
def bin(number, options = {})
-
100
if number.is_a?(Hash)
-
fail 'The bin number must be passed as the first argument'
-
end
-
100
options[:bin_description] ||= options.delete(:description)
-
100
extract_meta!(options) do
-
100
apply_conditions(options) do
-
100
options[:type] ||= :fail
-
100
options[:bin] = number
-
100
options[:softbin] ||= options[:soft_bin] || options[:sbin]
-
100
set_result(options[:type], options)
-
end
-
end
-
end
-
-
2
def pass(number, options = {})
-
23
if number.is_a?(Hash)
-
fail 'The bin number must be passed as the first argument'
-
end
-
23
options[:type] = :pass
-
23
bin(number, options)
-
end
-
-
2
def cz(instance, cz_setup, options = {})
-
17
extract_meta!(options) do
-
17
apply_conditions(options) do
-
17
node = n1(:cz, cz_setup)
-
34
append_to(node) { test(instance, options) }
-
end
-
end
-
end
-
2
alias_method :characterize, :cz
-
-
# Append a log message line to the flow
-
2
def log(message, options = {})
-
718
extract_meta!(options) do
-
718
apply_conditions(options) do
-
718
n1(:log, message.to_s)
-
end
-
end
-
end
-
-
# Enable a flow control variable
-
2
def enable(var, options = {})
-
13
extract_meta!(options) do
-
13
apply_conditions(options) do
-
13
n1(:enable, var)
-
end
-
end
-
end
-
-
# Disable a flow control variable
-
2
def disable(var, options = {})
-
7
extract_meta!(options) do
-
7
apply_conditions(options) do
-
7
n1(:disable, var)
-
end
-
end
-
end
-
-
2
def set_flag(flag, options = {})
-
19
extract_meta!(options) do
-
19
apply_conditions(options) do
-
19
set_flag_node(flag)
-
end
-
end
-
end
-
-
2
def unset_flag(flag, options = {})
-
7
extract_meta!(options) do
-
7
apply_conditions(options) do
-
7
unset_flag_node(flag)
-
end
-
end
-
end
-
-
2
def add_flag(flag, options = {})
-
13
extract_meta!(options) do
-
13
apply_conditions(options) do
-
13
add_flag_node(flag)
-
end
-
end
-
end
-
-
2
def set(var, val, options = {})
-
16
extract_meta!(options) do
-
16
apply_conditions(options) do
-
16
n2(:set, var, val)
-
end
-
end
-
end
-
-
# Insert explicitly rendered content in to the flow
-
2
def render(str, options = {})
-
17
extract_meta!(options) do
-
17
apply_conditions(options) do
-
17
n1(:render, str)
-
end
-
end
-
end
-
-
2
def continue(options = {})
-
1
extract_meta!(options) do
-
1
apply_conditions(options) do
-
1
n0(:continue)
-
end
-
end
-
end
-
-
# Execute the given flow in the console
-
2
def run(options = {})
-
Formatters::Datalog.run_and_format(ast, options)
-
nil
-
end
-
-
# Returns true if the test context generated from the supplied options + existing condition
-
# wrappers, is different from that which was applied to the previous test.
-
2
def context_changed?(options)
-
21
options[:_dont_delete_conditions_] = true
-
21
last_conditions != clean_conditions(open_conditions + [extract_conditions(options)])
-
end
-
-
2
def whenever(*expressions, &block)
-
9
if expressions.last.is_a?(Hash)
-
9
options = expressions.pop
-
else
-
options = {}
-
end
-
9
flow_control_method(:whenever, expressions, options, &block)
-
end
-
-
2
def loop(*args, &block)
-
24
unless args[0].keys.include?(:from) && args[0].keys.include?(:to)
-
fail 'Loop must specify :from, :to'
-
end
-
# assume 1 if :step not provided
-
24
unless args[0].keys.include?(:step)
-
4
args[0][:step] = 1
-
end
-
# assume 1 if :test_num_inc not provided
-
24
unless args[0].keys.include?(:test_num_inc)
-
23
args[0][:test_num_inc] = 1
-
end
-
# Add node for set of flag to be used for loop
-
24
unless args[0][:var].nil?
-
23
unless tester.smt8?
-
9
set(args[0][:var], 0)
-
end
-
end
-
24
extract_meta!(options) do
-
24
apply_conditions(options) do
-
# always pass 5-element array to loop node to simplify downstream parser
-
# element, 'var', will be nil if not specified by loop call
-
24
params = [args[0][:from], args[0][:to], args[0][:step], args[0][:var], args[0][:test_num_inc]]
-
-
24
node = n(:loop, params)
-
48
node = append_to(node) { block.call }
-
24
node
-
end
-
end
-
end
-
-
2
RELATIONAL_OPERATORS.each do |method|
-
define_method method do |*args, &block|
-
25
options = args.pop if args.last.is_a?(Hash)
-
25
unless args.size == 2
-
fail "Format for relational operation must match: ':<operator>(var1, var2)'"
-
end
-
25
n2(method.to_sym, args[0], args[1])
-
12
end unless method_defined?(method)
-
end
-
-
# Define handlers for all of the flow control block methods, unless a custom one has already
-
# been defined above
-
2
CONDITION_KEYS.keys.each do |method|
-
define_method method do |*flags, &block|
-
609
if flags.last.is_a?(Hash)
-
609
options = flags.pop
-
else
-
options = {}
-
end
-
609
if flags.include? nil
-
1
Origen.log.error("Found Nil flag passed to the '#{method}' method, ensure the flag is passed as a String or a Symbol!")
-
1
fail
-
end
-
608
flags = flags.first if flags.size == 1
-
# Legacy option provided by OrigenTesters that permits override of a block enable method by passing
-
# an :or option with a true value
-
608
if (CONDITION_KEYS[method] == :if_enabled || CONDITION_KEYS[method] || :unless_enabled) && options[:or]
-
11
block.call
-
else
-
597
flow_control_method(CONDITION_KEYS[method], flags, options, &block)
-
end
-
104
end unless method_defined?(method)
-
end
-
-
2
def inspect
-
"<OrigenTesters::ATP::Flow:#{object_id} #{name}>"
-
end
-
-
2
def ids(options = {})
-
13
OrigenTesters::ATP::AST::Extractor.new.process(raw, [:id]).map { |node| node.to_a[0] }
-
end
-
-
2
private
-
-
2
def description
-
17943
@description.last
-
end
-
-
2
def source_file
-
17943
@source_file.last
-
end
-
-
2
def source_line_number
-
17943
@source_line_number.last
-
end
-
-
2
def flow_control_method(name, flag, options = {}, &block)
-
606
extract_meta!(options) do
-
606
if flag.is_a?(Array)
-
111
if name == :if_passed
-
fail 'if_passed only accepts one ID, use if_any_passed or if_all_passed for multiple IDs'
-
end
-
111
if name == :if_failed
-
fail 'if_failed only accepts one ID, use if_any_failed or if_all_failed for multiple IDs'
-
end
-
111
if name == :if_any_sites_failed || name == :if_all_sites_failed || name == :if_any_sites_passed || name == :if_all_sites_passed
-
fail "#{name} currently only accepts one ID, please create a ticket here if you need this functionality: https://github.com/Origen-SDK/origen_testers/issues"
-
end
-
end
-
606
apply_conditions(options) do
-
606
if block
-
590
node = n1(name, flag)
-
590
open_conditions << [name, flag]
-
1180
node = append_to(node) { block.call }
-
590
open_conditions.pop
-
else
-
16
unless options[:then] || options[:else]
-
fail "You must supply a :then or :else option when calling #{name} like this!"
-
end
-
16
node = n1(name, flag)
-
16
if options[:then]
-
32
node = append_to(node) { options[:then].call }
-
end
-
16
if options[:else]
-
16
e = n0(:else)
-
32
e = append_to(e) { options[:else].call }
-
16
node = node.updated(nil, node.children + [e])
-
end
-
end
-
606
node
-
end
-
end
-
end
-
-
2
def apply_conditions(options, node = nil)
-
# Applying the current context, means to append to the same node as the last time, this
-
# means that the next node will pick up the exact same condition context as the previous one
-
4954
if options[:context] == :current
-
20
node = yield
-
20
found = false
-
20
@pipeline = @pipeline.map do |parent|
-
46
p = Processors::AppendTo.new
-
46
n = p.run(parent, node, @last_append.id)
-
46
found ||= p.succeeded?
-
46
n
-
end
-
20
unless found
-
fail 'The request to apply the current context has failed, this is likely a bug in OrigenTesters::ATP'
-
end
-
20
node
-
else
-
4934
conditions = extract_conditions(options)
-
4934
open_conditions << conditions
-
4934
node = yield
-
4934
open_conditions.pop
-
-
4934
update_last_append = !condition_node?(node)
-
-
4934
conditions.each do |key, value|
-
767
if key == :group
-
2
node = n2(key, n1(:name, value.to_s), node)
-
else
-
765
node = n2(key, value, node)
-
end
-
767
if update_last_append
-
699
@last_append = node
-
699
update_last_append = false
-
end
-
end
-
-
4934
append(node)
-
4934
node
-
end
-
end
-
-
2
def save_conditions
-
3124
@last_conditions = clean_conditions(open_conditions.dup)
-
end
-
-
2
def last_conditions
-
21
@last_conditions || {}
-
end
-
-
2
def open_conditions
-
14193
@open_conditions ||= []
-
end
-
-
2
def clean_conditions(conditions)
-
3145
result = {}.with_indifferent_access
-
3145
conditions.each do |cond|
-
6930
if cond.is_a?(Array)
-
1108
if cond.size != 2
-
fail 'Something has gone wrong in OrigenTesters::ATP!'
-
else
-
1108
result[cond[0]] = cond[1].to_s if cond[1]
-
end
-
else
-
6517
cond.each { |k, v| result[k] = v.to_s if v }
-
end
-
end
-
3145
result
-
end
-
-
2
def extract_conditions(options)
-
4955
conditions = {}
-
4955
delete_from_options = !options.delete(:_dont_delete_conditions_)
-
4955
options.each do |key, value|
-
10147
if CONDITION_KEYS[key]
-
773
options.delete(key) if delete_from_options
-
773
key = CONDITION_KEYS[key]
-
773
if conditions[key] && value
-
fail "Multiple values assigned to flow condition #{key}" unless conditions[key] == value
-
else
-
773
conditions[key] = value if value
-
end
-
end
-
end
-
4955
conditions
-
end
-
-
2
def append(node)
-
4934
@last_append = @pipeline.last unless condition_node?(node)
-
4934
n = @pipeline.pop
-
4934
@pipeline << n.updated(nil, n.children + [node])
-
4934
@pipeline.last
-
end
-
-
# Append all nodes generated within the given block to the given node
-
# instead of the top-level flow node
-
2
def append_to(node)
-
911
@pipeline << node
-
911
yield
-
911
@pipeline.pop
-
end
-
-
2
def condition_node?(node)
-
9868
!!CONDITION_KEYS[node.type]
-
end
-
-
2
def extract_meta!(options)
-
5177
@source_file << options.delete(:source_file)
-
5177
@source_line_number << options.delete(:source_line_number)
-
5177
@description << options.delete(:description)
-
5177
yield
-
5177
@source_file.pop
-
5177
@source_line_number.pop
-
5177
@description.pop
-
end
-
-
2
def id(name)
-
683
n1(:id, name)
-
end
-
-
2
def priority(name)
-
1
n1(:priority, name)
-
end
-
-
2
def on_fail(options = {})
-
619
if options.is_a?(Proc)
-
14
node = n0(:on_fail)
-
28
append_to(node) { options.call }
-
else
-
605
children = []
-
605
if options[:bin] || options[:softbin]
-
543
fail_opts = { bin: options[:bin], softbin: options[:softbin] }
-
543
fail_opts[:bin_description] = options[:bin_description] if options[:bin_description]
-
543
fail_opts[:softbin_description] = options[:softbin_description] if options[:softbin_description]
-
543
fail_opts[:bin_attrs] = options[:bin_attrs] if options[:bin_attrs]
-
543
children << set_result(:fail, fail_opts)
-
end
-
605
if options[:set_run_flag] || options[:set_flag]
-
51
children << set_flag_node(options[:set_run_flag] || options[:set_flag])
-
end
-
605
children << n0(:continue) if options[:continue]
-
605
children << n1(:delayed, !!options[:delayed]) if options.key?(:delayed)
-
605
children << n1(:render, options[:render]) if options[:render]
-
605
n(:on_fail, children)
-
end
-
end
-
-
2
def on_pass(options = {})
-
8
if options.is_a?(Proc)
-
8
node = n0(:on_pass)
-
16
append_to(node) { options.call }
-
else
-
children = []
-
if options[:bin] || options[:softbin]
-
pass_opts = { bin: options[:bin], softbin: options[:softbin] }
-
pass_opts[:bin_description] = options[:bin_description] if options[:bin_description]
-
pass_opts[:softbin_description] = options[:softbin_description] if options[:softbin_description]
-
pass_opts[:bin_attrs] = options[:bin_attrs] if options[:bin_attrs]
-
children << set_result(:pass, pass_opts)
-
end
-
if options[:set_run_flag] || options[:set_flag]
-
children << set_flag_node(options[:set_run_flag] || options[:set_flag])
-
end
-
children << n0(:continue) if options[:continue]
-
children << n1(:render, options[:render]) if options[:render]
-
n(:on_pass, children)
-
end
-
end
-
-
2
def pattern(name, path = nil)
-
3
if path
-
1
n2(:pattern, name, path)
-
else
-
2
n1(:pattern, name)
-
end
-
end
-
-
2
def attribute(name, value)
-
2
n2(:attribute, name, value)
-
end
-
-
2
def level(name, value, units = nil)
-
3
if units
-
1
n(:level, [name, value, units])
-
else
-
2
n2(:level, name, value)
-
end
-
end
-
-
2
def pin(name)
-
8
n1(:pin, name)
-
end
-
-
2
def set_result(type, options = {})
-
643
children = []
-
643
children << type
-
643
if options[:bin] && options[:bin_description]
-
13
children << n2(:bin, options[:bin], options[:bin_description])
-
else
-
630
children << n1(:bin, options[:bin]) if options[:bin]
-
end
-
643
if options[:softbin] && options[:softbin_description]
-
2
children << n2(:softbin, options[:softbin], options[:softbin_description])
-
else
-
641
children << n1(:softbin, options[:softbin]) if options[:softbin]
-
end
-
643
if options[:bin_attrs]
-
4
options[:bin_attrs].each do |key, val|
-
4
children << n1(key, val)
-
end
-
end
-
643
n(:set_result, children)
-
end
-
-
2
def number(val)
-
2720
n1(:number, val.to_i)
-
end
-
-
2
def set_flag_node(flag)
-
70
n1(:set_flag, flag)
-
end
-
-
2
def unset_flag_node(flag)
-
7
n1(:unset_flag, flag)
-
end
-
-
2
def add_flag_node(flag)
-
13
n1(:add_flag, flag)
-
end
-
-
# Ensures the flow ast has a volatile node, then adds the
-
# given flags to it
-
2
def add_volatile_flags(node, flags)
-
10
name, *nodes = *node
-
10
if nodes[0] && nodes[0].type == :volatile
-
2
v = nodes.shift
-
else
-
8
v = n0(:volatile)
-
end
-
14
existing = v.children.map { |f| f.type == :flag ? f.value : nil }.compact
-
10
new = []
-
10
flags.each do |flag|
-
13
new << n1(:flag, flag) unless existing.include?(flag)
-
end
-
10
v = v.updated(nil, v.children + new)
-
10
node.updated(nil, [name, v] + nodes)
-
end
-
-
# Ensures the flow ast has a global node, then adds the
-
# given flags to it
-
2
def add_global_flag_to_node(node, flags)
-
8
name, *nodes = *node
-
8
if nodes[0] && nodes[0].type == :global
-
1
v = nodes.shift
-
else
-
7
v = n0(:global)
-
end
-
10
existing = v.children.map { |f| f.type == :flag ? f.value : nil }.compact
-
8
new = []
-
8
flags.each do |flag|
-
9
new << n1(:flag, flag) unless existing.include?(flag)
-
end
-
8
v = v.updated(nil, v.children + new)
-
8
node.updated(nil, [name, v] + nodes)
-
end
-
-
# Ensures the flow ast has a bin descriptions node, then adds the
-
# given description to it
-
2
def add_bin_description(node, number, description, options)
-
4
@existing_bin_descriptions ||= { soft: {}, hard: {} }
-
4
return node if @existing_bin_descriptions[options[:type]][number]
-
4
@existing_bin_descriptions[options[:type]][number] = true
-
4
name, *nodes = *node
-
4
if nodes[0] && nodes[0].type == :volatile
-
2
v = nodes.shift
-
else
-
2
v = nil
-
end
-
4
if nodes[0] && nodes[0].type == :bin_descriptions
-
2
d = nodes.shift
-
else
-
2
d = n0(:bin_descriptions)
-
end
-
4
d = d.updated(nil, d.children + [n2(options[:type], number, description)])
-
4
node.updated(nil, [name, v, d].compact + nodes)
-
end
-
-
2
def n(type, children, options = {})
-
17915
options[:file] ||= options.delete(:source_file) || source_file
-
17915
options[:line_number] ||= options.delete(:source_line_number) || source_line_number
-
17915
options[:description] ||= options.delete(:description) || description
-
# Guarantee that each node has a unique meta-ID, in case we need to ever search
-
# for it
-
17915
options[:id] = OrigenTesters::ATP.next_id
-
17915
OrigenTesters::ATP::AST::Node.new(type, children, options)
-
end
-
-
2
def n0(type, options = {})
-
165
n(type, [], options)
-
end
-
-
2
def n1(type, arg, options = {})
-
12106
n(type, [arg], options)
-
end
-
-
2
def n2(type, arg1, arg2, options = {})
-
834
n(type, [arg1, arg2], options)
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module FlowAPI
-
2
def atp=(atp)
-
110
@atp = atp
-
end
-
-
2
def atp
-
653
@atp
-
end
-
-
2
([:test, :bin, :pass, :continue, :cz, :log, :sub_test, :volatile, :add_global_flag, :set_flag, :unset_flag, :add_flag, :set, :enable, :disable, :render,
-
:context_changed?, :ids, :describe_bin, :describe_softbin, :describe_soft_bin, :add_auxiliary_flow] +
-
OrigenTesters::ATP::Flow::CONDITION_KEYS.keys + OrigenTesters::ATP::Flow::RELATIONAL_OPERATORS).each do |method|
-
160
define_method method do |*args, &block|
-
4930
options = args.pop if args.last.is_a?(Hash)
-
4930
options ||= {}
-
4930
add_meta!(options) if respond_to?(:add_meta!, true)
-
4930
add_description!(options) if respond_to?(:add_description!, true)
-
4930
args << options
-
4930
atp.send(method, *args, &block)
-
end
-
end
-
-
2
alias_method :logprint, :log
-
-
2
def loop(*args, &block)
-
25
if args.empty?
-
1
super(&block)
-
else
-
24
options = args.pop if args.last.is_a?(Hash)
-
24
options ||= {}
-
24
add_meta!(options) if respond_to?(:add_meta!, true)
-
24
add_description!(options) if respond_to?(:add_description!, true)
-
24
args << options
-
24
atp.send(:loop, *args, &block)
-
end
-
end
-
-
2
def lo_limit(value, options)
-
{
-
value: value,
-
rule: options[:rule] || :gte,
-
units: options[:units],
-
selector: options[:selector] || options[:test_mode]
-
}
-
end
-
-
2
def hi_limit(value, options)
-
{
-
value: value,
-
rule: options[:rule] || :lte,
-
units: options[:units],
-
selector: options[:selector] || options[:test_mode]
-
}
-
end
-
-
2
def limit(value, options)
-
unless options[:rule]
-
fail 'You must supply option :rule (e.g. rule: :gt) when calling the limit helper'
-
end
-
{
-
value: value,
-
rule: options[:rule] || :lt,
-
units: options[:units],
-
selector: options[:selector] || options[:test_mode]
-
}
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
class Formatter < Processor
-
2
def format(node, options = {})
-
process(node)
-
end
-
-
2
def run_and_format(node, options = {})
-
ast = Runner.new.run(node, options)
-
format(ast, options)
-
end
-
-
2
def self.format(node, options = {})
-
15
new.format(node, options)
-
end
-
-
2
def self.run_and_format(node, options = {})
-
15
ast = Runner.new.run(node, options)
-
15
format(ast, options)
-
end
-
-
2
def self.run(*args)
-
15
run_and_format(*args)
-
end
-
end
-
end
-
1
module OrigenTesters::ATP
-
1
module Formatters
-
# Returns the executed flow as a string of test names. This
-
# is mainly intended to be used for testing the runner.
-
1
class Basic < Formatter
-
1
def format(node, options = {})
-
15
@output = ''
-
15
process(node)
-
15
@output
-
end
-
-
1
def on_test(node)
-
54
if node.find(:name)
-
@output += node.find(:name).value
-
else
-
54
obj = node.find(:object).value
-
54
obj = obj['Test'] unless obj.is_a?(String)
-
54
@output += obj
-
end
-
54
@output += ' F' if node.find(:failed)
-
54
@output += "\n"
-
end
-
-
1
def on_set_result(node)
-
3
@output += node.to_a[0].upcase
-
3
@output += " #{node.find(:bin).value}" if node.find(:bin)
-
3
@output += " #{node.find(:softbin).value}" if node.find(:softbin)
-
3
@output += "\n"
-
end
-
end
-
end
-
end
-
1
require 'sexpistol'
-
1
module OrigenTesters::ATP
-
1
class Parser < Sexpistol
-
1
def initialize
-
# This accessor moves to Sexpistol::Parser in newer versions of the gem
-
1
self.ruby_keyword_literals = true
-
end
-
-
1
def string_to_ast(string)
-
2
to_sexp(parse_string(string))
-
end
-
-
1
def to_sexp(ast_array)
-
24
children = ast_array.map do |item|
-
62
if item.is_a?(Array)
-
22
to_sexp(item)
-
else
-
40
item
-
end
-
end
-
24
type = children.shift
-
24
return type if type.is_a?(OrigenTesters::ATP::AST::Node)
-
22
type = type.to_s.gsub('-', '_').to_sym
-
22
OrigenTesters::ATP::AST::Node.new(type, children)
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module Processors
-
# Assigns an ID to all test nodes that don't have one
-
2
class AddIDs < Processor
-
2
def run(node)
-
94
@i = 0
-
94
@existing_ids = []
-
94
@add_ids = false
-
# First collect all existing IDs, this is required to make sure
-
# that a generated ID does not clash with an existing one
-
94
process(node)
-
# Now run again to fill in the blanks
-
94
@add_ids = true
-
94
process(node)
-
end
-
-
2
def on_test(node)
-
6224
if @add_ids
-
3112
node = node.ensure_node_present(:id)
-
3112
node.updated(nil, process_all(node))
-
else
-
3112
if id = node.find(:id)
-
686
@existing_ids << id.value
-
end
-
3112
process_all(node)
-
end
-
end
-
2
alias_method :on_group, :on_test
-
-
2
def on_id(node)
-
3826
if @add_ids
-
3126
unless node.value
-
2426
node.updated(nil, [next_id])
-
end
-
end
-
end
-
-
2
def next_id
-
2426
@i += 1
-
2426
@i += 1 while @existing_ids.include?("t#{@i}")
-
2426
"t#{@i}"
-
end
-
end
-
end
-
end
-
1
module OrigenTesters::ATP
-
1
module Processors
-
# Makes sure every test node has an on_fail/set_result node,
-
1
class AddSetResult < Processor
-
1
def run(node)
-
15
process(node)
-
end
-
-
1
def on_test(node)
-
75
node = node.ensure_node_present(:on_fail)
-
75
node.updated(nil, process_all(node))
-
end
-
-
1
def on_on_fail(node)
-
78
unless node.find(:continue)
-
60
node = node.ensure_node_present(:set_result, 'fail')
-
end
-
78
node.updated(nil, process_all(node))
-
end
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module Processors
-
# This combines adjacent if flag nodes where the flag is in the opposite state
-
#
-
# s(:flow,
-
# s(:name, "prb1"),
-
# s(:if_flag, "SOME_FLAG",
-
# s(:test,
-
# s(:name, "test1"))),
-
# s(:unless_flag, "SOME_FLAG",
-
# s(:test,
-
# s(:name, "test2"))))
-
#
-
# s(:flow,
-
# s(:name, "prb1"),
-
# s(:if_flag, "SOME_FLAG",
-
# s(:test,
-
# s(:name, "test1"))),
-
# s(:else,
-
# s(:test,
-
# s(:name, "test2"))))
-
#
-
# See here for an example of the kind of flow level effect it has:
-
# https://github.com/Origen-SDK/origen_testers/issues/43
-
2
class AdjacentIfCombiner < OrigenTesters::ATP::Processor
-
2
class SetRunFlagFinder < OrigenTesters::ATP::Processor
-
2
def contains?(node, flag_name)
-
43
@result = false
-
43
@flag_name = flag_name
-
43
process_all(node)
-
43
@result
-
end
-
-
2
def on_set_flag(node)
-
1
if node.to_a[0] == @flag_name
-
1
@result = true
-
end
-
end
-
2
alias_method :on_enable, :on_set_flag
-
2
alias_method :on_disable, :on_set_flag
-
end
-
-
2
def on_flow(node)
-
83
extract_volatiles(node)
-
83
name, *nodes = *node
-
83
node.updated(nil, [name] + optimize(process_all(nodes)))
-
end
-
-
2
def on_named_collection(node)
-
176
name, *nodes = *node
-
176
node.updated(nil, [name] + optimize(process_all(nodes)))
-
end
-
2
alias_method :on_group, :on_named_collection
-
2
alias_method :on_sub_flow, :on_named_collection
-
-
2
def on_unnamed_collection(node)
-
682
node.updated(nil, optimize(process_all(node.children)))
-
end
-
2
alias_method :on_on_fail, :on_unnamed_collection
-
2
alias_method :on_on_pass, :on_unnamed_collection
-
-
2
def optimize(nodes)
-
941
results = []
-
941
node1 = nil
-
941
nodes.each do |node2|
-
3088
if node1
-
2229
if opposite_flag_states?(node1, node2) && safe_to_combine?(node1, node2)
-
42
results << combine(node1, node2)
-
42
node1 = nil
-
else
-
2187
results << node1
-
2187
node1 = node2
-
end
-
else
-
859
node1 = node2
-
end
-
end
-
941
results << node1 if node1
-
941
results
-
end
-
-
2
def combine(node1, node2)
-
42
node1.updated(nil, process_all(node1.children) + [node2.updated(:else, process_all(node2.to_a[1..-1]))])
-
end
-
-
2
def opposite_flag_states?(node1, node2)
-
2229
((node1.type == :if_flag && node2.type == :unless_flag) || (node1.type == :unless_flag && node2.type == :if_flag) ||
-
2191
(node1.type == :if_enabled && node2.type == :unless_enabled) || (node1.type == :unless_enabled && node2.type == :if_enabled)) &&
-
node1.to_a[0] == node2.to_a[0]
-
end
-
-
2
def safe_to_combine?(node1, node2)
-
# Nodes won't be collapsed if node1 touches the shared run flag, i.e. if there is any chance
-
# that by the time it would naturally execute node2, the flag could have been changed by node1
-
47
(!volatile?(node1.to_a[0]) || (volatile?(node1.to_a[0]) && !node1.contains?(:test))) &&
-
!SetRunFlagFinder.new.contains?(node1, node1.to_a[0])
-
end
-
end
-
end
-
end
-
1
module OrigenTesters::ATP
-
1
module Processors
-
# Appends the given node to the node with the given ID, if it exists
-
# somewhere within the given parent node
-
1
class AppendTo < Processor
-
1
def run(parent, node, id, options = {})
-
46
@to_be_appended = node
-
46
@id_of_to_be_appended_to = id
-
46
@found = false
-
46
process(parent)
-
end
-
-
1
def succeeded?
-
36
@found
-
end
-
-
1
def handler_missing(node)
-
3164
if node.id == @id_of_to_be_appended_to
-
20
@found = true
-
20
node.updated(nil, node.children + [@to_be_appended])
-
else
-
3144
node.updated(nil, process_all(node.children))
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module Processors
-
# This removes on_pass/fail operations from groups and applies them to all
-
# contained tests
-
2
class ApplyPostGroupActions < Processor
-
2
def run(node)
-
26
@on_pass = []
-
26
@on_fail = []
-
26
process(node)
-
end
-
-
2
def on_group(node)
-
77
on_pass = node.find(:on_pass)
-
77
on_fail = node.find(:on_fail)
-
77
@on_pass << on_pass
-
77
@on_fail << on_fail
-
77
node = node.remove(on_pass) if on_pass
-
77
node = node.remove(on_fail) if on_fail
-
77
node = node.updated(nil, process_all(node.children))
-
77
@on_fail.pop
-
77
@on_pass.pop
-
77
node
-
end
-
-
2
def on_test(node)
-
1656
node = node.ensure_node_present(:on_pass) if @on_pass.any? { |n| n }
-
1655
node = node.ensure_node_present(:on_fail) if @on_fail.any? { |n| n }
-
1080
node.updated(nil, process_all(node.children))
-
end
-
-
2
def on_on_pass(node)
-
84
@on_pass.each do |on_pass|
-
18
if on_pass
-
4
node = node.updated(nil, node.children + process_all(on_pass.children))
-
end
-
end
-
84
node
-
end
-
-
2
def on_on_fail(node)
-
443
@on_fail.each do |on_fail|
-
248
if on_fail
-
42
node = node.updated(nil, node.children + process_all(on_fail.children))
-
end
-
end
-
443
node
-
end
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module Processors
-
# This optimizes the condition nodes such that any adjacent flow nodes that
-
# have the same condition, will be grouped together under a single condition
-
# wrapper.
-
#
-
# For example this AST:
-
#
-
# (flow
-
# (group
-
# (name "g1")
-
# (test
-
# (name "test1"))
-
# (flow-flag "bitmap" true
-
# (test
-
# (name "test2"))))
-
# (flow-flag "bitmap" true
-
# (group
-
# (name "g1")
-
# (flow-flag "x" true
-
# (test
-
# (name "test3")))
-
# (flow-flag "y" true
-
# (flow-flag "x" true
-
# (test
-
# (name "test4")))))))
-
#
-
# Will be optimized to this:
-
#
-
# (flow
-
# (group
-
# (name "g1")
-
# (test
-
# (name "test1"))
-
# (flow-flag "bitmap" true
-
# (test
-
# (name "test2"))
-
# (flow-flag "x" true
-
# (test
-
# (name "test3"))
-
# (flow-flag "y" true
-
# (test
-
# (name "test4")))))))
-
#
-
2
class Condition < Processor
-
2
def on_flow(node)
-
127
extract_volatiles(node)
-
127
node.updated(nil, optimize(process_all(node.children)))
-
end
-
-
2
def on_sub_flow(node)
-
58
node.updated(nil, optimize(process_all(node.children)))
-
end
-
-
2
def on_group(node)
-
275
array_for_update = []
-
275
if node.find(:bypass) && node.find(:comment)
-
name, bypass, comment, *nodes = *node
-
array_for_update = [name, bypass, comment]
-
275
elsif node.find(:bypass)
-
4
name, bypass, *nodes = *node
-
4
array_for_update = [name, bypass]
-
271
elsif node.find(:comment)
-
4
name, comment, *nodes = *node
-
4
array_for_update = [name, comment]
-
else
-
267
name, *nodes = *node
-
267
array_for_update = [name]
-
end
-
-
611
if conditions_to_remove.any? { |c| node.type == c.type && c.to_a == [name] }
-
24
conditions_to_remove << node.updated(nil, array_for_update)
-
24
result = node.updated(:inline, optimize(process_all(nodes)))
-
24
conditions_to_remove.pop
-
else
-
251
conditions_to_remove << node.updated(nil, [name, bypass, comment])
-
251
result = node.updated(nil, array_for_update + optimize(process_all(nodes)))
-
251
conditions_to_remove.pop
-
end
-
275
result
-
end
-
-
2
def on_condition_node(node)
-
1875
flag, *nodes = *node
-
3594
if conditions_to_remove.any? { |c| node.type == c.type && c.to_a == [flag] }
-
264
if volatile?(flag)
-
result = node.updated(:inline, optimize(process_all(nodes)))
-
else
-
# This ensures any duplicate conditions matching the current one get removed
-
264
conditions_to_remove << node.updated(nil, [flag])
-
264
result = node.updated(:inline, optimize(process_all(nodes)))
-
264
conditions_to_remove.pop
-
end
-
else
-
1611
if volatile?(flag)
-
23
result = node.updated(nil, [flag] + optimize(process_all(nodes)))
-
else
-
1588
conditions_to_remove << node.updated(nil, [flag])
-
1588
result = node.updated(nil, [flag] + optimize(process_all(nodes)))
-
1588
conditions_to_remove.pop
-
end
-
end
-
1875
result
-
end
-
2
OrigenTesters::ATP::Flow::CONDITION_NODE_TYPES.each do |type|
-
44
alias_method "on_#{type}", :on_condition_node unless method_defined?("on_#{type}")
-
end
-
-
2
def optimize(nodes)
-
2335
results = []
-
2335
node1 = nil
-
2335
nodes.each do |node2|
-
7043
if node1
-
4714
if can_be_combined?(node1, node2)
-
132
node1 = process(combine(node1, node2))
-
else
-
4582
results << node1
-
4582
node1 = node2
-
end
-
else
-
2329
node1 = node2
-
end
-
end
-
2335
results << node1 if node1
-
2335
results
-
end
-
-
2
def can_be_combined?(node1, node2)
-
4714
if condition_node?(node1) && condition_node?(node2)
-
534
!(conditions(node1) & conditions(node2)).empty?
-
else
-
4180
false
-
end
-
end
-
-
2
def condition_node?(node)
-
# [:flow_flag, :run_flag, :test_result, :group, :job, :test_executed].include?(node.type)
-
6010
node.respond_to?(:type) && OrigenTesters::ATP::Flow::CONDITION_KEYS[node.type]
-
end
-
-
2
def combine(node1, node2)
-
132
common = conditions(node1) & conditions(node2)
-
266
common.each { |condition| conditions_to_remove << condition }
-
132
node1 = process(node1)
-
132
node1 = [node1] unless node1.is_a?(Array)
-
132
node2 = process(node2)
-
132
node2 = [node2] unless node2.is_a?(Array)
-
266
common.size.times { conditions_to_remove.pop }
-
-
132
node = nil
-
132
common.reverse_each do |condition|
-
134
if node
-
2
node = condition.updated(nil, condition.children + [node])
-
else
-
132
node = condition.updated(nil, condition.children + node1 + node2)
-
end
-
end
-
132
node
-
end
-
-
2
def conditions(node)
-
2511
result = []
-
# if [:flow_flag, :run_flag].include?(node.type)
-
2511
if [:if_enabled, :unless_enabled, :if_flag, :unless_flag].include?(node.type)
-
1060
flag, *children = *node
-
1060
unless volatile?(flag)
-
1047
result << node.updated(nil, [flag])
-
end
-
1060
result += conditions(children.first) if children.first && children.size == 1
-
# elsif [:test_result, :job, :test_executed].include?(node.type)
-
1451
elsif node.type == :group
-
179
name, *children = *node
-
# Sometimes a group can have an ID
-
179
if children.first.try(:type) == :id
-
74
result << node.updated(nil, [name, children.shift])
-
else
-
105
result << node.updated(nil, [name])
-
end
-
179
result += conditions(children.first) if children.first && children.size == 1
-
1272
elsif OrigenTesters::ATP::Flow::CONDITION_NODE_TYPES.include?(node.type)
-
241
flag, *children = *node
-
241
result << node.updated(nil, [flag])
-
241
result += conditions(children.first) if children.first && children.size == 1
-
end
-
2511
result
-
end
-
-
2
def conditions_to_remove
-
6672
@conditions_to_remove ||= []
-
end
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module Processors
-
# Implements continue on a fail branch for V93K by removing any bin nodes that are
-
# siblings of continue nodes. The continue nodes are also removed in the process since
-
# they have now served their function.
-
2
class ContinueImplementer < OrigenTesters::ATP::Processor
-
# Delete any on-fail child if it's 'empty'
-
2
def on_on_fail(node)
-
548
if cont = node.find(:continue) || @continue
-
334
node = node.updated(nil, node.children - [cont] - node.find_all(:set_result))
-
end
-
548
node.updated(nil, process_all(node.children))
-
end
-
-
2
def on_group(node)
-
110
f = node.find(:on_fail)
-
110
if f && f.find(:continue)
-
10
with_continue do
-
10
node = node.updated(nil, process_all(node.children))
-
end
-
10
node
-
else
-
100
node.updated(nil, process_all(node.children))
-
end
-
end
-
-
2
def with_continue
-
10
orig = @continue
-
10
@continue = true
-
10
yield
-
10
@continue = orig
-
end
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module Processors
-
# Removes embedded else nodes and converts them to the equivalent inverse condition
-
# node at the same level as the parent node
-
2
class ElseRemover < Processor
-
2
def run(node)
-
30
process(node)
-
end
-
-
2
def on_condition_node(node)
-
554
if e = node.find(:else)
-
7
n1 = node.remove(e)
-
7
if node.type.to_s =~ /if_/
-
7
type = node.type.to_s.sub('if_', 'unless_').to_sym
-
elsif node.type.to_s =~ /unless_/
-
type = node.type.to_s.sub('unless_', 'if_').to_sym
-
else
-
fail "Don't know how to inverse: #{node.type}"
-
end
-
7
n2 = e.updated(type, [n1.to_a[0]] + e.children)
-
7
node.updated(:inline, [n1, n2])
-
else
-
547
node.updated(nil, process_all(node.children))
-
end
-
end
-
2
OrigenTesters::ATP::Flow::CONDITION_NODE_TYPES.each do |type|
-
44
alias_method "on_#{type}", :on_condition_node unless method_defined?("on_#{type}")
-
end
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module Processors
-
# Removes any empty on_pass and on_fail branches
-
2
class EmptyBranchRemover < Processor
-
# Delete any on-fail child if it's 'empty'
-
2
def on_test(node)
-
3010
if on_pass = node.find(:on_pass)
-
170
node = node.remove(on_pass) if on_pass.children.empty?
-
end
-
3010
if on_fail = node.find(:on_fail)
-
1015
node = node.remove(on_fail) if on_fail.children.empty?
-
end
-
3010
node = node.updated(nil, process_all(node.children))
-
end
-
end
-
end
-
end
-
1
module OrigenTesters::ATP
-
1
module Processors
-
# Extracts all flags which are set within the given flow, returning
-
# them in an array
-
1
class ExtractSetFlags < OrigenTesters::ATP::Processor
-
1
def run(nodes)
-
84
@results = []
-
84
process_all(nodes)
-
84
@results.uniq
-
end
-
-
1
def on_set_flag(node)
-
227
flag = node.value
-
227
@results << flag
-
end
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module Processors
-
# This processor eliminates the use of run flags between adjacent tests:
-
#
-
# s(:flow,
-
# s(:name, "prb1"),
-
# s(:test,
-
# s(:name, "test1"),
-
# s(:id, "t1"),
-
# s(:on_fail,
-
# s(:set_flag, "t1_FAILED", "auto_generated"),
-
# s(:continue))),
-
# s(:if_flag, "t1_FAILED",
-
# s(:test,
-
# s(:name, "test2"))))
-
#
-
#
-
# s(:flow,
-
# s(:name, "prb1"),
-
# s(:test,
-
# s(:name, "test1"),
-
# s(:id, "t1"),
-
# s(:on_fail,
-
# s(:test,
-
# s(:name, "test2")))))
-
#
-
2
class FlagOptimizer < Processor
-
2
attr_reader :run_flag_table, :optimize_when_continue
-
-
2
class ExtractRunFlagTable < Processor
-
# Hash table of run_flag name with number of times used
-
2
attr_reader :run_flag_table
-
-
# Reset hash table
-
2
def initialize
-
83
@run_flag_table = {}.with_indifferent_access
-
end
-
-
# For run_flag nodes, increment # of occurrences for specified flag
-
2
def on_if_flag(node)
-
481
children = node.children.dup
-
481
names = children.shift
-
481
state = node.type == :if_flag
-
481
Array(names).each do |name|
-
500
if @run_flag_table[name.to_sym].nil?
-
415
@run_flag_table[name.to_sym] = 1
-
else
-
85
@run_flag_table[name.to_sym] += 1
-
end
-
end
-
481
process_all(node.children)
-
end
-
2
alias_method :on_unless_flag, :on_if_flag
-
end
-
-
2
def run(node, options = {})
-
options = {
-
83
optimize_when_continue: true
-
}.merge(options)
-
83
@optimize_when_continue = options[:optimize_when_continue]
-
# Pre-process the AST for # of occurrences of each run-flag used
-
83
t = ExtractRunFlagTable.new
-
83
t.process(node)
-
83
@run_flag_table = t.run_flag_table
-
83
extract_volatiles(node)
-
83
process(node)
-
end
-
-
2
def on_named_collection(node)
-
358
name, *nodes = *node
-
358
node.updated(nil, [name] + optimize(process_all(nodes)))
-
end
-
2
alias_method :on_flow, :on_named_collection
-
2
alias_method :on_group, :on_named_collection
-
2
alias_method :on_unless_flag, :on_named_collection
-
2
alias_method :on_sub_flow, :on_named_collection
-
-
2
def on_unnamed_collection(node)
-
10
node.updated(nil, optimize(process_all(node.children)))
-
end
-
2
alias_method :on_else, :on_unnamed_collection
-
-
2
def on_whenever(node)
-
12
name, *nodes = *node
-
12
node.updated(nil, [name] + optimize(process_all(nodes)))
-
end
-
2
alias_method :on_whenever_all, :on_whenever
-
2
alias_method :on_whenever_any, :on_whenever
-
-
2
def on_if_flag(node)
-
481
name, *nodes = *node
-
# Remove this node and return its children if required
-
481
if if_run_flag_to_remove.last == node.to_a[0]
-
17
node.updated(:inline, optimize(process_all(node.to_a[1..-1])))
-
else
-
464
node.updated(nil, [name] + optimize(process_all(nodes)))
-
end
-
end
-
-
2
def on_on_fail(node)
-
956
if to_inline = nodes_to_inline_on_pass_or_fail.last
-
# If this node sets the flag that gates the node to be inlined
-
183
set_flag = node.find(:set_flag)
-
183
if set_flag && gated_by_set?(set_flag.to_a[0], to_inline)
-
# Remove the sub-node that sets the flag if there are no further references to it
-
-
155
if @run_flag_table[set_flag.to_a[0]] == 1 || !@run_flag_table[set_flag.to_a[0]]
-
137
node = node.updated(nil, node.children - [set_flag])
-
end
-
-
# And append the content of the node to be in_lined at the end of this on pass/fail node
-
155
append = reorder_nested_run_flags(set_flag.to_a[0], to_inline).to_a[1..-1]
-
-
# Belt and braces approach to make sure this node to be inlined does
-
# not get picked up anywhere else
-
155
nodes_to_inline_on_pass_or_fail.pop
-
155
nodes_to_inline_on_pass_or_fail << nil
-
end
-
end
-
956
node.updated(nil, optimize(process_all(node.children + Array(append))))
-
end
-
2
alias_method :on_on_pass, :on_on_fail
-
-
2
def optimize(nodes)
-
1817
results = []
-
1817
node1 = nil
-
1817
nodes.each do |node2|
-
4291
if node1
-
2604
if can_be_combined?(node1, node2)
-
155
node1 = combine(node1, node2)
-
else
-
2449
results << node1
-
2449
node1 = node2
-
end
-
else
-
1687
node1 = node2
-
end
-
end
-
1817
results << node1 if node1
-
1817
results
-
end
-
-
2
def can_be_combined?(node1, node2)
-
2604
if (node1.type == :test || node1.type == :sub_flow) && (node2.type == :if_flag || node2.type == :unless_flag) &&
-
# Don't optimize tests which are marked as continue if told not to
-
242
!(node1.find(:on_fail) && node1.find(:on_fail).find(:continue) && !optimize_when_continue)
-
-
241
if node1.find_all(:on_fail, :on_pass).any? do |node|
-
267
if n = node.find(:set_flag)
-
# Inline instead of setting a flag if...
-
230
gated_by_set?(n.to_a[0], node2) && # The flag set by node1 is gating node2
-
n.to_a[1] == 'auto_generated' && # The flag has been generated and not specified by the user
-
n.to_a[0] !~ /_RAN$/ && # And don't compress RAN flags because they can be set by both on_fail and on_pass
-
!volatile?(n.to_a[0]) # And make sure the flag has not been marked as volatile
-
end
-
end
-
155
return true
-
end
-
end
-
2449
false
-
end
-
-
2
def combine(node1, node2)
-
155
nodes_to_inline_on_pass_or_fail << node2 # .updated(nil, process_all(node2.children))
-
155
node1 = node1.updated(nil, process_all(node1.children))
-
155
nodes_to_inline_on_pass_or_fail.pop
-
155
node1
-
end
-
-
# node will always be an if_flag or unless_flag type node, guaranteed by the caller
-
#
-
# Returns true if flag matches the one supplied
-
#
-
# s(:if_flag, flag,
-
# s(:test, ...
-
#
-
# Also returns true if flag matches the one supplied, but it is nested within other flag conditions:
-
#
-
# s(:unless_flag, other_flag,
-
# s(:if_flag, other_flag2,
-
# s(:if_flag, flag,
-
# s(:test, ...
-
2
def gated_by_set?(flag, node)
-
426
(flag == node.to_a[0] && node.type == :if_flag) ||
-
104
(node.to_a.size == 2 && (node.to_a.last.type == :if_flag || node.to_a.last.type == :unless_flag) && gated_by_set?(flag, node.to_a.last))
-
end
-
-
# Returns the node with the run_flag clauses re-ordered to have the given flag of interest at the top.
-
#
-
# The caller guarantees the run_flag clause containing the given flag is present.
-
#
-
# For example, given this node:
-
#
-
# s(:unless_flag, "flag1",
-
# s(:if_flag, "ot_BEA7F3B_FAILED",
-
# s(:test,
-
# s(:object, <TestSuite: inner_test1_BEA7F3B>),
-
# s(:name, "inner_test1_BEA7F3B"),
-
# s(:number, 0),
-
# s(:id, "it1_BEA7F3B"),
-
# s(:on_fail,
-
# s(:render, "multi_bin;")))))
-
#
-
# Then this node would be returned when the flag of interest is ot_BEA7F3B_FAILED:
-
#
-
# s(:if_flag, "ot_BEA7F3B_FAILED",
-
# s(:unless_flag, "flag1",
-
# s(:test,
-
# s(:object, <TestSuite: inner_test1_BEA7F3B>),
-
# s(:name, "inner_test1_BEA7F3B"),
-
# s(:number, 0),
-
# s(:id, "it1_BEA7F3B"),
-
# s(:on_fail,
-
# s(:render, "multi_bin;")))))
-
2
def reorder_nested_run_flags(flag, node)
-
# If the run_flag we care about is already at the top, just return node
-
155
unless node.to_a[0] == flag && node.type == :if_flag
-
17
if_run_flag_to_remove << flag
-
17
node = node.updated(:if_flag, [flag] + [process(node)])
-
17
if_run_flag_to_remove.pop
-
end
-
155
node
-
end
-
-
2
def if_run_flag_to_remove
-
515
@if_run_flag_to_remove ||= []
-
end
-
-
2
def nodes_to_inline_on_pass_or_fail
-
1576
@nodes_to_inline_on_pass_or_fail ||= []
-
end
-
end
-
end
-
end
-
1
module OrigenTesters::ATP
-
1
module Processors
-
# Gives every node their own individual wrapping of condition nodes. No attempt is made
-
# to identify or remove duplicate conditions in the wrapping, that will be done later by
-
# the RedundantConditionRemover.
-
1
class Flattener < Processor
-
1
def run(node)
-
4
@results = [[]]
-
4
@conditions = []
-
4
process(node)
-
4
node.updated(:flow, results)
-
end
-
-
1
def on_flow(node)
-
4
process_all(node.children)
-
end
-
-
# Handles the top-level flow nodes
-
1
def on_volatile(node)
-
6
results << node
-
end
-
1
alias_method :on_name, :on_volatile
-
1
alias_method :on_id, :on_volatile
-
-
1
def on_group(node)
-
1
@results << []
-
1
process_all(node.children)
-
1
nodes = @results.pop
-
1
results << node.updated(nil, nodes)
-
end
-
-
1
def on_condition_node(node)
-
8
flag, *nodes = *node
-
8
@conditions << node.updated(node.type, [flag])
-
8
process_all(nodes)
-
8
@conditions.pop
-
end
-
1
OrigenTesters::ATP::Flow::CONDITION_NODE_TYPES.each do |type|
-
22
alias_method "on_#{type}", :on_condition_node unless method_defined?("on_#{type}")
-
end
-
-
1
def handler_missing(node)
-
16
results << wrap_with_current_conditions(node)
-
end
-
-
1
def wrap_with_current_conditions(node)
-
16
@conditions.reverse_each do |condition|
-
14
node = condition.updated(nil, condition.children + [node])
-
end
-
16
node
-
end
-
-
1
def results
-
27
@results.last
-
end
-
end
-
end
-
end
-
1
module OrigenTesters::ATP
-
1
module Processors
-
# Adds the flow ID to all ids and label names
-
1
class FlowID < Processor
-
1
attr_reader :id
-
-
1
def run(node, id)
-
39
@id = id
-
39
process(node)
-
end
-
-
1
def on_id(node)
-
2177
if node.value =~ /^extern/
-
node
-
else
-
2177
node.updated(nil, ["#{node.value}_#{id}"])
-
end
-
end
-
-
1
def on_if_failed(node)
-
389
tid, *nodes = *node
-
389
if tid.is_a?(Array)
-
52
tid = tid.map do |tid|
-
104
if tid =~ /^extern/
-
tid
-
else
-
104
"#{tid}_#{id}"
-
end
-
end
-
else
-
337
if tid !~ /^extern/
-
337
tid = "#{tid}_#{id}"
-
end
-
end
-
389
node.updated(nil, [tid] + process_all(nodes))
-
end
-
1
alias_method :on_if_any_failed, :on_if_failed
-
1
alias_method :on_if_all_failed, :on_if_failed
-
1
alias_method :on_if_passed, :on_if_failed
-
1
alias_method :on_if_any_passed, :on_if_failed
-
1
alias_method :on_if_all_passed, :on_if_failed
-
1
alias_method :on_if_ran, :on_if_failed
-
1
alias_method :on_unless_ran, :on_if_failed
-
1
alias_method :on_if_any_sites_failed, :on_if_failed
-
1
alias_method :on_if_all_sites_failed, :on_if_failed
-
1
alias_method :on_if_any_sites_passed, :on_if_failed
-
1
alias_method :on_if_all_sites_passed, :on_if_failed
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module Processors
-
# Makes the AST safe for Marshaling
-
2
class Marshal < Processor
-
2
def on_object(node)
-
13294
o = node.value
-
13294
if o.is_a?(String)
-
419
meta = { 'Test' => o }
-
12875
elsif o.is_a?(Hash)
-
10150
meta = o
-
2725
elsif o.respond_to?(:to_meta) && o.to_meta && !o.to_meta.empty?
-
2431
meta = o.to_meta
-
else
-
294
meta = {}
-
end
-
# The test suite / test instance name
-
13294
meta['Test'] ||= o.try(:name)
-
13294
meta['Pattern'] ||= o.try(:pattern)
-
# The test name column on IG-XL, or the name of a specific instance of a test which shares a common
-
# 'Test' name with other tests
-
13294
meta['Test Name'] ||= o.try(:test_name) || o.try(:_test_name) || o.try('TestName') || meta['Test']
-
# The name of the primary test that is logged by the test instance / test method, if it logs more
-
# than one then this is represented by sub_test nodes
-
13294
meta['Sub Test Name'] ||= o.try(:sub_test_name) || o.try('SubTestName') || meta['Test']
-
13294
node.updated(nil, [meta])
-
end
-
-
2
def on_render(node)
-
80
node.updated(nil, [node.value.to_s])
-
end
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module Processors
-
# Removes most things from embedded on_pass/fail nodes and converts them to the equivalent
-
# on_passed/failed condition at the same level as the parent node
-
2
class OnPassFailRemover < Processor
-
2
def run(node)
-
30
process(node)
-
end
-
-
2
def on_test(node)
-
1087
on_pass = node.find(:on_pass)
-
1087
on_fail = node.find(:on_fail)
-
1087
if on_pass || on_fail
-
278
id = node.find(:id)
-
278
unless id
-
fail 'Something has gone wrong, all nodes should have IDs by this point'
-
end
-
278
id = id.value
-
278
nodes = [node]
-
278
if on_fail && contains_anything_interesting?(on_fail)
-
4
nodes << node.updated(:if_failed, [id] + on_fail.children)
-
4
nodes[0] = nodes[0].remove(on_fail)
-
end
-
278
if on_pass && contains_anything_interesting?(on_pass)
-
4
nodes << node.updated(:if_passed, [id] + on_pass.children)
-
4
nodes[0] = nodes[0].remove(on_pass)
-
end
-
278
node.updated(:inline, nodes)
-
else
-
809
node.updated(nil, process_all(node.children))
-
end
-
end
-
-
2
def contains_anything_interesting?(node)
-
597
node.children.any? { |n| n.type != :set_result && n.type != :continue && n.type != :set_flag }
-
end
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module Processors
-
# Ensures that all test nodes only ever set a flag once
-
2
class OneFlagPerTest < Processor
-
2
def run(node)
-
24
@build_table = true
-
24
@pass_table = {}
-
24
@fail_table = {}
-
24
process(node)
-
24
@counters = {}
-
105
@pass_table.each { |f, v| @counters[f] = 0 }
-
190
@fail_table.each { |f, v| @counters[f] = 0 }
-
24
@build_table = false
-
24
process(node)
-
end
-
-
2
def on_test(node)
-
2146
on_pass = node.find(:on_pass)
-
2146
on_fail = node.find(:on_fail)
-
2146
if @build_table
-
1073
if on_fail
-
439
on_fail.find_all(:set_flag).each do |n|
-
195
@fail_table[n.to_a[0]] ||= 0
-
195
@fail_table[n.to_a[0]] += 1
-
end
-
end
-
1073
if on_pass
-
82
on_pass.find_all(:set_flag).each do |n|
-
82
@pass_table[n.to_a[0]] ||= 0
-
82
@pass_table[n.to_a[0]] += 1
-
end
-
end
-
else
-
1073
to_be_set = {}
-
1073
if on_fail
-
439
node = node.remove(on_fail)
-
439
on_fail.find_all(:set_flag).each do |set_flag|
-
195
old_flag = set_flag.to_a[0]
-
195
if @fail_table[old_flag] > 1
-
50
on_fail = on_fail.remove(set_flag)
-
50
new_flag = "#{old_flag}_#{@counters[old_flag]}"
-
50
@counters[old_flag] += 1
-
50
to_be_set[old_flag] = new_flag
-
50
c = set_flag.children.dup
-
50
c[0] = new_flag
-
50
set_flag = set_flag.updated(nil, c)
-
50
on_fail = on_fail.updated(nil, on_fail.children + [set_flag])
-
end
-
end
-
439
node = node.updated(nil, node.children + [on_fail])
-
end
-
1073
if on_pass
-
82
node = node.remove(on_pass)
-
82
on_pass.find_all(:set_flag).each do |set_flag|
-
82
old_flag = set_flag.to_a[0]
-
82
if @pass_table[old_flag] > 1
-
2
on_pass = on_pass.remove(set_flag)
-
2
new_flag = "#{old_flag}_#{@counters[old_flag]}"
-
2
@counters[old_flag] += 1
-
2
to_be_set[old_flag] = new_flag
-
2
c = set_flag.children.dup
-
2
c[0] = new_flag
-
2
set_flag = set_flag.updated(nil, c)
-
2
on_pass = on_pass.updated(nil, on_pass.children + [set_flag])
-
end
-
end
-
82
node = node.updated(nil, node.children + [on_pass])
-
end
-
1073
if to_be_set.empty?
-
1023
node
-
else
-
102
nodes = to_be_set.map { |old, new| node.updated(:if_flag, [new, node.updated(:set_flag, [old, 'auto_generated'])]) }
-
50
node.updated(:inline, [node] + nodes)
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module Processors
-
# Modifies the AST by performing some basic clean up, mainly to sanitize
-
# user input. For example it will ensure that all IDs and references are underscored
-
# and lower cased.
-
2
class PreCleaner < Processor
-
2
def initialize
-
133
@group_ids = []
-
end
-
-
# Make all IDs lower cased symbols
-
# unless literal_flags is set
-
2
def on_id(node)
-
758
id = node.to_a[0]
-
758
if tester.literal_flags
-
52
node.updated(nil, [id])
-
else
-
706
node.updated(nil, [clean(id)])
-
end
-
end
-
-
# Make all ID references use the lower case symbols
-
# unless literal_flags is set
-
2
def on_if_failed(node)
-
625
id, *children = *node
-
625
if tester.literal_flags
-
34
node.updated(nil, [id] + process_all(children))
-
else
-
591
node.updated(nil, [clean(id)] + process_all(children))
-
end
-
end
-
2
alias_method :on_if_passed, :on_if_failed
-
2
alias_method :on_if_any_failed, :on_if_failed
-
2
alias_method :on_if_all_failed, :on_if_failed
-
2
alias_method :on_if_any_passed, :on_if_failed
-
2
alias_method :on_if_all_passed, :on_if_failed
-
2
alias_method :on_if_ran, :on_if_failed
-
2
alias_method :on_unless_ran, :on_if_failed
-
2
alias_method :on_if_any_sites_failed, :on_if_failed
-
2
alias_method :on_if_all_sites_failed, :on_if_failed
-
2
alias_method :on_if_any_sites_passed, :on_if_failed
-
2
alias_method :on_if_all_sites_passed, :on_if_failed
-
-
2
def on_group(node)
-
2433
if id = node.children.find { |n| n.type == :id }
-
70
@group_ids << process(id).value
-
else
-
201
@group_ids << nil
-
end
-
271
group = node.updated(nil, process_all(node.children))
-
271
@group_ids.pop
-
271
group
-
end
-
2
alias_method :on_sub_flow, :on_group
-
-
2
def on_test(node)
-
# Remove IDs nodes from test nodes if they refer to the ID of a parent group
-
3024
if @group_ids.last
-
156
children = node.children.reject do |n|
-
472
if n.type == :id
-
27
@group_ids.last == process(n).value
-
end
-
end
-
else
-
2868
children = node.children
-
end
-
3024
node.updated(nil, process_all(children))
-
end
-
-
2
def clean(id)
-
1429
if id.is_a?(Array)
-
198
id.map { |i| clean(i) }
-
else
-
1363
id.to_s.symbolize.to_s
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module Processors
-
# Removes any conditions nodes that are nested within other condition
-
# nodes that specify the same condition
-
2
class RedundantConditionRemover < Processor
-
2
def run(node)
-
26
@conditions = []
-
26
process(node)
-
end
-
-
2
def on_condition_node(node)
-
573
sig = [node.type, node.to_a[0]]
-
573
if @conditions.include?(sig)
-
flag, *nodes = *node
-
node.updated(:inline, process_all(nodes))
-
else
-
573
@conditions << sig
-
573
node = node.updated(nil, process_all(node.children))
-
573
@conditions.pop
-
573
node
-
end
-
end
-
2
OrigenTesters::ATP::Flow::CONDITION_NODE_TYPES.each do |type|
-
44
alias_method "on_#{type}", :on_condition_node unless method_defined?("on_#{type}")
-
end
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module Processors
-
# This processor will apply the relationships between tests, e.g. if testB should only
-
# execute if testA passes, then this processor will update the AST to make testA set
-
# a flag on pass, and then update testB to only run if that flag is set.
-
2
class Relationship < Processor
-
# Returns a hash containing the IDs of all tests that have dependents
-
2
attr_reader :test_results
-
-
# Extracts all test-result nodes from the given AST
-
2
class ExtractTestResults < Processor
-
2
attr_reader :results
-
-
2
def on_if_failed(node)
-
392
ids, *children = *node
-
392
unless ids.is_a?(Array)
-
346
ids = [ids]
-
end
-
392
ids.each do |id|
-
438
results[id] ||= {}
-
438
results[id][:failed] = true
-
end
-
392
process_all(children)
-
end
-
2
alias_method :on_if_any_failed, :on_if_failed
-
2
alias_method :on_if_all_failed, :on_if_failed
-
2
alias_method :on_if_any_sites_failed, :on_if_failed
-
2
alias_method :on_if_all_sites_failed, :on_if_failed
-
-
2
def on_if_passed(node)
-
134
ids, *children = *node
-
134
unless ids.is_a?(Array)
-
102
ids = [ids]
-
end
-
134
ids.each do |id|
-
166
results[id] ||= {}
-
166
results[id][:passed] = true
-
end
-
134
process_all(children)
-
end
-
2
alias_method :on_if_any_passed, :on_if_passed
-
2
alias_method :on_if_all_passed, :on_if_passed
-
2
alias_method :on_if_any_sites_passed, :on_if_passed
-
2
alias_method :on_if_all_sites_passed, :on_if_passed
-
-
2
def on_if_ran(node)
-
87
id, *children = *node
-
87
results[id] ||= {}
-
87
results[id][:ran] = true
-
87
process_all(children)
-
end
-
2
alias_method :on_unless_ran, :on_if_ran
-
-
2
def results
-
1489
@results ||= {}.with_indifferent_access
-
end
-
end
-
-
2
def run(node)
-
107
t = ExtractTestResults.new
-
107
t.process(node)
-
107
@test_results = t.results || {}
-
107
process(node)
-
end
-
-
2
def add_pass_flag(id, node)
-
166
node = node.ensure_node_present(:on_pass)
-
166
node = node.ensure_node_present(:on_fail)
-
166
node.updated(nil, node.children.map do |n|
-
969
if n.type == :on_pass
-
166
n = n.add node.updated(:set_flag, ["#{id}_PASSED", :auto_generated])
-
803
elsif n.type == :on_fail
-
166
delayed = n.find(:delayed)
-
166
if delayed && delayed.to_a[0]
-
1
n
-
else
-
165
n.ensure_node_present(:continue)
-
end
-
else
-
637
n
-
end
-
end)
-
end
-
-
2
def add_fail_flag(id, node)
-
389
node = node.ensure_node_present(:on_fail)
-
389
node.updated(nil, node.children.map do |n|
-
1922
if n.type == :on_fail
-
389
n = n.add node.updated(:set_flag, ["#{id}_FAILED", :auto_generated])
-
389
delayed = n.find(:delayed)
-
389
if delayed && delayed.to_a[0]
-
1
n
-
else
-
388
n.ensure_node_present(:continue)
-
end
-
else
-
1533
n
-
end
-
end)
-
end
-
-
2
def add_ran_flags(id, node)
-
87
set_flag = node.updated(:set_flag, ["#{id}_RAN", :auto_generated])
-
# For a group, set a flag immediately upon entry to the group to signal that
-
# it ran to later tests, this is better than doing it immediately after the group
-
# in case it was bypassed
-
87
if node.type == :group || node.type == :sub_flow
-
13
nodes = node.to_a.dup
-
13
pre_nodes = []
-
13
while [:name, :id, :path].include?(nodes.first.try(:type))
-
28
pre_nodes << nodes.shift
-
end
-
13
node.updated(nil, pre_nodes + [set_flag] + nodes)
-
-
# For a test, set a flag immediately after the referenced test has executed
-
# but don't change its pass/fail handling
-
74
elsif node.type == :test
-
74
node.updated(:inline, [node, set_flag])
-
else
-
fail "Don't know how to add ran flag to #{node.type}"
-
end
-
end
-
-
# Set flags depending on the result on tests which have dependents later
-
# in the flow
-
2
def on_test(node)
-
3187
node = node.updated(nil, process_all(node.children))
-
3187
nid = id(node)
-
# If this test has a dependent
-
3187
if test_results[nid]
-
613
node = add_pass_flag(nid, node) if test_results[nid][:passed]
-
613
node = add_fail_flag(nid, node) if test_results[nid][:failed]
-
613
node = add_ran_flags(nid, node) if test_results[nid][:ran]
-
end
-
3187
node
-
end
-
2
alias_method :on_group, :on_test
-
2
alias_method :on_sub_flow, :on_test
-
-
2
def on_if_failed(node)
-
359
id, *children = *node
-
359
node.updated(:if_flag, [id_to_flag(id, 'FAILED')] + process_all(children))
-
end
-
2
alias_method :on_if_any_failed, :on_if_failed
-
-
2
def on_if_any_sites_failed(node)
-
7
id, *children = *node
-
7
node.updated(:if_any_sites_flag, [id_to_flag(id, 'FAILED')] + process_all(children))
-
end
-
-
2
def on_if_all_sites_failed(node)
-
3
id, *children = *node
-
3
node.updated(:if_all_sites_flag, [id_to_flag(id, 'FAILED')] + process_all(children))
-
end
-
-
2
def on_if_all_failed(node)
-
23
ids, *children = *node
-
23
ids.reverse_each.with_index do |id, i|
-
46
if i == 0
-
23
node = node.updated(:if_flag, [id_to_flag(id, 'FAILED')] + process_all(children))
-
else
-
23
node = node.updated(:if_flag, [id_to_flag(id, 'FAILED'), node])
-
end
-
end
-
23
node
-
end
-
-
2
def on_if_passed(node)
-
110
id, *children = *node
-
110
node.updated(:if_flag, [id_to_flag(id, 'PASSED')] + process_all(children))
-
end
-
2
alias_method :on_if_any_passed, :on_if_passed
-
-
2
def on_if_any_sites_passed(node)
-
4
id, *children = *node
-
4
node.updated(:if_any_sites_flag, [id_to_flag(id, 'PASSED')] + process_all(children))
-
end
-
-
2
def on_if_all_sites_passed(node)
-
4
id, *children = *node
-
4
node.updated(:if_all_sites_flag, [id_to_flag(id, 'PASSED')] + process_all(children))
-
end
-
-
2
def on_if_all_passed(node)
-
16
ids, *children = *node
-
16
ids.reverse_each.with_index do |id, i|
-
32
if i == 0
-
16
node = node.updated(:if_flag, [id_to_flag(id, 'PASSED')] + process_all(children))
-
else
-
16
node = node.updated(:if_flag, [id_to_flag(id, 'PASSED'), node])
-
end
-
end
-
16
node
-
end
-
-
2
def on_if_ran(node)
-
50
id, *children = *node
-
50
node.updated(:if_flag, [id_to_flag(id, 'RAN')] + process_all(children))
-
end
-
-
2
def on_unless_ran(node)
-
37
id, *children = *node
-
37
node.updated(:unless_flag, [id_to_flag(id, 'RAN')] + process_all(children))
-
end
-
-
# Returns the ID of the give test node (if any), caller is responsible
-
# for only passing test nodes
-
2
def id(node)
-
17057
if n = node.children.find { |c| c.type == :id }
-
3064
n.children.first
-
end
-
end
-
-
2
def id_to_flag(id, type)
-
652
if id.is_a?(Array)
-
117
id.map { |i| "#{i}_#{type}" }
-
else
-
613
"#{id}_#{type}"
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module Processors
-
# Removes all :sub_flow nodes
-
2
class SubFlowRemover < Processor
-
2
def on_sub_flow(node)
-
49
node.updated(:remove, nil)
-
end
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
# Program is the top-level container for a collection of test flows
-
2
class Program
-
# Load a program from a previously saved file
-
2
def self.load(file)
-
p = nil
-
File.open(file) do |f|
-
p = Marshal.load(f)
-
end
-
p
-
end
-
-
2
def flow(name, options = {})
-
269
flows[name] ||= Flow.new(self, name, options)
-
end
-
-
2
def flows
-
295
@flows ||= {}.with_indifferent_access
-
# To rescue previously created programs which have been loaded
-
295
unless @flows.is_a?(ActiveSupport::HashWithIndifferentAccess)
-
@flows = @flows.with_indifferent_access
-
end
-
295
@flows
-
end
-
-
# Save the program to a file
-
2
def save(file)
-
13
File.open(file, 'w') do |f|
-
13
Marshal.dump(self, f)
-
end
-
end
-
-
2
def respond_to?(*args)
-
26
flows.key?(args.first) || super
-
end
-
-
2
def method_missing(method, *args, &block) # :nodoc:
-
if f = flows[method]
-
define_singleton_method method do
-
f
-
end
-
f
-
else
-
super
-
end
-
end
-
end
-
end
-
1
module OrigenTesters::ATP
-
# This class is responsible for executing the given test flow based on a given
-
# set of runtime conditions.
-
# A subset of the input AST will be returned containing only the nodes that would
-
# be hit when the flow is executed under the given conditions.
-
1
class Runner < Processor
-
1
def run(node, options = {})
-
options = {
-
15
evaluate_enables: true,
-
evaluate_flags: true,
-
evaluate_set_result: true
-
}.merge(options)
-
15
@options = options
-
15
@completed = false
-
15
@groups = []
-
15
@groups_on_fail = []
-
15
@groups_on_pass = []
-
15
node = Processors::AddIDs.new.run(node)
-
15
node = Processors::AddSetResult.new.run(node)
-
15
process(node)
-
end
-
-
1
def on_flow(node)
-
15
c = open_container do
-
15
process_all(node.children)
-
end
-
15
node.updated(nil, c)
-
end
-
-
1
def on_name(node)
-
20
container << node
-
end
-
-
1
def on_if_flag(node)
-
19
if @options[:evaluate_flags]
-
19
flag, *nodes = *node
-
19
flag = [flag].flatten
-
19
enabled = node.type == :if_flag
-
38
active = flag.any? { |f| set_flags.include?(f) }
-
19
if (enabled && active) || (!enabled && !active)
-
12
process_all(nodes)
-
end
-
else
-
c = open_container do
-
process_all(node.children)
-
end
-
container << node.updated(nil, node.children.take(1) + c)
-
end
-
end
-
1
alias_method :on_unless_flag, :on_if_flag
-
-
1
def on_if_enabled(node)
-
9
if @options[:evaluate_enables]
-
9
flag, *nodes = *node
-
9
flag = [flag].flatten
-
9
enabled = node.type == :if_enabled
-
18
active = flag.any? { |f| set_enables.include?(f) }
-
9
if (enabled && active) || (!enabled && !active)
-
7
process_all(nodes)
-
end
-
else
-
c = open_container do
-
process_all(node.children)
-
end
-
container << node.updated(nil, node.children.take(1) + c)
-
end
-
end
-
1
alias_method :on_unless_enabled, :on_if_enabled
-
-
1
def on_if_failed(node)
-
id, *nodes = *node
-
if failed_test_ids.include?(id)
-
process_all(nodes)
-
end
-
end
-
-
1
def on_if_passed(node)
-
id, *nodes = *node
-
unless failed_test_ids.include?(id)
-
process_all(nodes)
-
end
-
end
-
-
1
def on_test(node)
-
55
if id = node.find(:id)
-
55
id = id.to_a[0]
-
55
if failed_test_ids.include?(id)
-
9
node = node.add(node.updated(:failed, []))
-
9
failed = true
-
9
if n_on_fail = node.find(:on_fail)
-
9
node = node.remove(n_on_fail)
-
end
-
end
-
end
-
55
unless failed
-
46
if n_on_pass = node.find(:on_pass)
-
4
node = node.remove(n_on_pass)
-
end
-
end
-
-
55
unless completed?
-
54
container << node
-
54
process_all(n_on_fail) if n_on_fail
-
54
process_all(n_on_pass) if n_on_pass
-
end
-
-
55
if failed
-
# Give indication to the parent group that at least one test within it failed
-
9
if @groups.last
-
3
@groups.pop
-
3
@groups << false
-
end
-
9
if n = node.find(:on_fail)
-
# If it has been set by a parent group, don't clear it
-
orig = @continue
-
@continue ||= !!n.find(:continue)
-
process_all(n)
-
@continue = orig
-
end
-
else
-
46
if n = node.find(:on_pass)
-
process_all(n)
-
end
-
end
-
end
-
-
1
def on_group(node)
-
5
on_fail = node.find(:on_fail)
-
5
on_pass = node.find(:on_pass)
-
5
c = open_container do
-
5
@groups << true # This will be set to false by any tests that fail within the group
-
5
@groups_on_fail << on_fail
-
5
@groups_on_pass << on_pass
-
5
if on_fail
-
3
orig = @continue
-
3
@continue = !!on_fail.find(:continue)
-
3
process_all(node.children - [on_fail, on_pass])
-
3
@continue = orig
-
else
-
2
process_all(node.children - [on_fail, on_pass])
-
end
-
5
if !@groups.pop # If failed
-
3
if on_fail
-
2
@continue = !!on_fail.find(:continue)
-
2
process_all(on_fail)
-
2
@continue = false
-
end
-
else
-
2
if on_pass
-
process_all(on_pass)
-
end
-
end
-
5
@groups_on_fail.pop
-
5
@groups_on_pass.pop
-
end
-
5
container << node.updated(nil, c)
-
end
-
-
1
def on_set_result(node)
-
8
unless @continue
-
6
container << node unless completed?
-
6
@completed = true if @options[:evaluate_set_result]
-
end
-
end
-
-
1
def on_set_flag(node)
-
12
set_flags << node.to_a[0]
-
end
-
-
1
def on_enable(node)
-
set_enables << node.value unless set_enables.include?(node.value)
-
end
-
-
1
def on_disable(node)
-
set_enables.delete(node.value)
-
end
-
-
1
def on_log(node)
-
3
container << node unless completed?
-
end
-
1
alias_method :on_render, :on_log
-
-
1
def on_if_job(node)
-
15
jobs, *nodes = *node
-
15
jobs = clean_job(jobs)
-
15
state = node.type == :if_job
-
15
unless job
-
fail 'Flow contains JOB-based conditions and no current JOB has been given!'
-
end
-
15
if state
-
9
process_all(node) if jobs.include?(job)
-
else
-
6
process_all(node) unless jobs.include?(job)
-
end
-
end
-
1
alias_method :on_unless_job, :on_if_job
-
-
1
def clean_job(job)
-
36
[job].flatten.map { |j| j.to_s.upcase }
-
end
-
-
1
def job
-
30
@options[:job].to_s.upcase if @options[:job]
-
end
-
-
1
def failed_test_ids
-
55
@failed_test_ids ||= [@options[:failed_test_id] || @options[:failed_test_ids]].flatten.compact
-
end
-
-
1
def set_flags
-
31
@set_flags ||= []
-
end
-
-
# Returns an array of enabled flow flags
-
1
def set_enables
-
9
@set_enables ||= [@options[:enable] || @options[:enables]].flatten.compact
-
end
-
-
1
def completed?
-
64
@completed
-
end
-
-
1
def open_container(c = [])
-
20
@containers ||= []
-
20
@containers << c
-
20
yield
-
20
@containers.pop
-
end
-
-
1
def container
-
85
@containers.last
-
end
-
end
-
end
-
2
require 'ast'
-
2
module OrigenTesters::ATP
-
2
class Validator < Processor
-
2
attr_reader :flow
-
-
2
def self.testing=(value)
-
17
@testing = value
-
end
-
-
2
def self.testing
-
21
@testing
-
end
-
-
2
def initialize(flow)
-
524
@flow = flow
-
end
-
-
2
def process(node)
-
123873
if @top_level_called
-
123349
super
-
else
-
524
@top_level_called = true
-
524
setup
-
524
super(node)
-
524
unless @testing
-
524
exit 1 if on_completion
-
end
-
end
-
end
-
-
# For test purposes, returns true if validation failed rather
-
# than exiting the process
-
2
def test_process(node)
-
@testing = true
-
process(node)
-
on_completion
-
end
-
-
2
def setup
-
end
-
-
2
def error(message)
-
# This is a hack to make the specs pass, for some reason RSpec
-
# seems to be swallowing the Origen log output after the first
-
# test that generates an error
-
21
if Validator.testing
-
21
puts message
-
else
-
Origen.log.error(message)
-
end
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module Validators
-
2
class DuplicateIDs < Validator
-
2
def on_completion
-
133
if @duplicate_ids
-
1
@duplicate_ids.each do |id, nodes|
-
1
error "Test ID #{id} is defined more than once in flow #{flow.name}:"
-
1
nodes.each do |node|
-
2
error " #{node.source}"
-
end
-
end
-
1
true
-
end
-
end
-
-
2
def on_id(node)
-
661
@existing_ids ||= {}
-
661
id = node.value
-
661
if @existing_ids[id]
-
1
@duplicate_ids ||= {}
-
1
if @duplicate_ids[id]
-
@duplicate_ids[id] << node
-
else
-
1
@duplicate_ids[id] = [@existing_ids[id], node]
-
end
-
else
-
660
@existing_ids[id] = node
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module Validators
-
2
class Flags < Validator
-
2
def setup
-
128
@open_if_nodes = []
-
128
@open_unless_nodes = []
-
128
@conflicting = []
-
end
-
-
2
def on_completion
-
128
failed = false
-
128
unless @conflicting.empty?
-
1
error 'if_flag and unless_flag conditions cannot be nested and refer to the same flag unless it is declared as volatile'
-
1
error "The following conflicts were found in flow #{flow.name}:"
-
1
@conflicting.each do |a, b|
-
1
a_condition = a.to_a[1] ? 'if_job: ' : 'unless_job:'
-
1
b_condition = b.to_a[1] ? 'if_job: ' : 'unless_job:'
-
1
error " #{a.type}(#{a.to_a[0]}) #{a.source}"
-
1
error " #{b.type}(#{b.to_a[0]}) #{b.source}"
-
1
error ''
-
end
-
1
failed = true
-
end
-
128
failed
-
end
-
-
2
def on_flow(node)
-
128
extract_volatiles(node)
-
128
process_all(node.children)
-
end
-
-
2
def on_if_flag(node)
-
133
if volatile?(node.to_a[0])
-
16
process_all(node.children)
-
else
-
118
if n = @open_unless_nodes.find { |n| n.to_a[0] == node.to_a[0] }
-
1
@conflicting << [n, node]
-
end
-
117
@open_if_nodes << node
-
117
process_all(node.children)
-
117
@open_if_nodes.pop
-
end
-
end
-
-
2
def on_unless_flag(node)
-
60
if volatile?(node.to_a[0])
-
7
process_all(node.children)
-
else
-
53
if n = @open_if_nodes.find { |n| n.to_a[0] == node.to_a[0] }
-
@conflicting << [n, node]
-
end
-
53
@open_unless_nodes << node
-
53
process_all(node.children)
-
53
@open_unless_nodes.pop
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module Validators
-
2
class Jobs < Validator
-
2
def setup
-
131
@conflicting = []
-
131
@negative = []
-
end
-
-
2
def on_completion
-
131
failed = false
-
131
unless @conflicting.empty?
-
1
error 'if_job and unless_job conditions cannot both be applied to the same tests'
-
1
error "The following conflicts were found in flow #{flow.name}:"
-
1
@conflicting.each do |a, b|
-
1
a_condition = a.to_a[1] ? 'if_job: ' : 'unless_job:'
-
1
b_condition = b.to_a[1] ? 'if_job: ' : 'unless_job:'
-
1
error " #{a_condition} #{a.source}"
-
1
error " #{b_condition} #{b.source}"
-
1
error ''
-
end
-
1
failed = true
-
end
-
-
131
unless @negative.empty?
-
2
error 'Job names should not be negated, use unless_job if you want to specify !JOB'
-
2
error "The following negative job names were found in flow #{flow.name}:"
-
2
@negative.each do |node|
-
2
error " #{node.to_a[0]} #{node.source}"
-
end
-
2
failed = true
-
end
-
-
131
failed
-
end
-
-
2
def on_if_job(node)
-
175
jobs, *nodes = *node
-
175
jobs = [jobs].flatten
-
175
state = node.type == :if_job
-
412
if jobs.any? { |j| j.to_s =~ /^(!|~)/ }
-
2
@negative << node
-
end
-
175
@stack ||= []
-
175
if !@stack.empty? && @stack.last[1] != state
-
1
@conflicting << [@stack.last[0], node]
-
else
-
174
@stack << [node, state]
-
174
process_all(node)
-
174
@stack.pop
-
end
-
end
-
2
alias_method :on_unless_job, :on_if_job
-
end
-
end
-
end
-
2
module OrigenTesters::ATP
-
2
module Validators
-
2
class MissingIDs < Validator
-
2
def setup
-
132
@referenced_ids = {}
-
132
@present_ids ||= {}.with_indifferent_access
-
132
@referenced_early = {}.with_indifferent_access
-
end
-
-
2
def on_completion
-
132
failed = false
-
132
@referenced_ids.each do |id, nodes|
-
608
unless @present_ids[id]
-
1
error "Test ID #{id} is referenced in flow #{flow.name} in the following lines, but it is never defined:"
-
1
nodes.each do |node|
-
1
error " #{node.source}"
-
end
-
1
failed = true
-
1
@referenced_early.delete(id)
-
end
-
end
-
132
@referenced_early.each do |id, nodes|
-
error "Test ID #{id} is referenced in flow #{flow.name} in the following line(s):"
-
nodes.each do |node|
-
error " #{node.source}"
-
end
-
error 'but it was not defined until later:'
-
error " #{@present_ids[id].first.source}"
-
failed = true
-
end
-
132
failed
-
end
-
-
2
def on_id(node)
-
659
id = node.value
-
659
@present_ids[id] ||= []
-
659
@present_ids[id] << node
-
end
-
-
2
def on_if_failed(node)
-
607
ids = node.to_a[0]
-
607
[ids].flatten.each do |id|
-
689
unless id =~ /^extern/
-
689
@referenced_ids[id] ||= []
-
689
@referenced_ids[id] << node
-
689
unless @present_ids[id]
-
1
@referenced_early[id] ||= []
-
1
@referenced_early[id] << node
-
end
-
end
-
end
-
607
process_all(node)
-
end
-
2
alias_method :on_if_any_failed, :on_if_failed
-
2
alias_method :on_if_all_failed, :on_if_failed
-
2
alias_method :on_if_passed, :on_if_failed
-
2
alias_method :on_if_any_passed, :on_if_failed
-
2
alias_method :on_if_all_passed, :on_if_failed
-
2
alias_method :on_if_ran, :on_if_failed
-
2
alias_method :on_unless_ran, :on_if_failed
-
end
-
end
-
end
-
2
module OrigenTesters
-
# Including this module in a class will create a basic test program interface that
-
# can generate programs for all ATE platforms supported by the Testers plugin.
-
#
-
# It provides a number of methods that can be called from a test program flow file
-
# to do basic things like a functional test.
-
#
-
# @example How to setup and use
-
# # lib/myapp/program_interface.rb
-
# module MyApp
-
# class Interface
-
# include OrigenTesters::BasicTestSetups
-
# end
-
# end
-
#
-
# # program/prb1.rb
-
# Flow.create interface: 'MyApp::Interface' do
-
#
-
# functional :my_pattern_1, bin: 10
-
# functional :my_pattern_2, bin: 11
-
#
-
# end
-
2
module BasicTestSetups
-
2
include OrigenTesters::ProgramGenerators
-
-
# Execute a functional test
-
#
-
# @param [Symbol, String] name the name of the test.
-
# @param [Hash] options the options to customize the test.
-
# @option options [Integer] :bin The bin number
-
# @option options [Integer] :sbin The soft bin number
-
# @option options [String] :pattern The pattern name, if not specified the test
-
# name will be used
-
# @option options [String] :pin_levels ('Lvl') The name of the pin levels
-
# @option options [String] :time_set ('Tim') The name of the time set
-
#
-
# @see http://origen.freescale.net/origen/latest/guides/program/flowapi/ The options associated with the flow control API are fully supported
-
#
-
# @example Customizing a test from the flow
-
# functional :erase, pattern: 'erase_all_nosrc', sbin: 150
-
#
-
# @example Applying global customization from the interface
-
# include OrigenTesters::BasicTestSetups
-
#
-
# def functional(name, options = {})
-
# # Apply custom defaults before calling
-
# options = {
-
# bin: 3,
-
# levels: 'nvm',
-
# }.merge(options)
-
# # Now call the generator
-
# super
-
# end
-
#
-
# @return [Hash] all generated components of the test will be returned. The key
-
# naming will depend on what platform the test has been generated for, but for
-
# example this will contain :flow_line, :test_instance and :patset objects in
-
# the case of an IG-XL-based platform.
-
#
-
# @example Adding a custom interpose function for J750
-
# include OrigenTesters::BasicTestSetups
-
#
-
# # Override the default J750 test instance to add an interpose function
-
# def functional(name, options = {})
-
# components = super
-
# if tester.j750?
-
# components[:test_instance].post_test_func = 'delayedBinning'
-
# end
-
# end
-
2
def functional(name, options = {})
-
options = {
-
7
pin_levels: 'Lvl',
-
time_set: 'Tim'
-
}.merge(options)
-
7
pattern = extract_pattern(name, options)
-
7
if tester.j750? || tester.j750_hpt? || tester.ultraflex?
-
4
ins = test_instances.functional(name, options)
-
4
pname = "#{pattern}_pset"
-
4
pset = patsets.add(pname, [{ pattern: "#{pattern}.PAT" }])
-
4
ins.pattern = pname
-
4
line = flow.test(ins, options)
-
4
{ test_instance: ins, flow_line: line, patset: pset }
-
3
elsif tester.v93k?
-
3
tm = test_methods.ac_tml.ac_test.functional_test
-
3
ts = test_suites.run(name, options)
-
3
ts.test_method = tm
-
3
ts.pattern = pattern
-
3
node = flow.test(ts, options)
-
3
{ test_method: tm, test_suite: ts, node: node }
-
else
-
fail "Unsupported tester: #{tester.class}"
-
end
-
end
-
-
# Extract the pattern name from the given options, falling back to the given
-
# test name if a :pattern option is not present.
-
#
-
# It will also strip any extension if one is present.
-
2
def extract_pattern(name, options = {})
-
7
p = options[:pattern] || name
-
7
p = p.to_s.sub(/\..*$/, '')
-
7
p
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
class CallbackHandlers
-
2
include Origen::PersistentCallbacks
-
-
# Snoop the pattern path that was just created and then compile it
-
# if the compiler was passed on the command line
-
2
def pattern_generated(path_to_generated_pattern, job_options = {})
-
142
if job_options[:testers_compile_pat]
-
opts = {}
-
opts[:compiler_instance] = job_options[:testers_compiler_instance_name]
-
opts[:pattern_generated] = true
-
OrigenTesters::PatternCompilers::Runner.run_compiler(path_to_generated_pattern, opts)
-
end
-
end
-
-
# Listen for a pattern with .atp or .atp.gz extension. If found then compile the fileand kill the 'origen g' command
-
2
def before_pattern_lookup(requested_pattern)
-
96
path = Pathname.new(requested_pattern)
-
96
patname = path.basename
-
96
dir = path.dirname
-
96
if patname.to_s.match(/.atp/)
-
if patname.extname == '.atp' || patname.extname == '.gz'
-
# Found a .atp or .atp.gz file so we should compile it
-
matches = Dir.glob("#{Origen.root}/**/#{patname}")
-
fail "Found multiple locations for #{patname}, exiting...\n\t#{matches}" if matches.size > 1
-
pattern = matches.first.to_s
-
current_compiler = select_compiler
-
run_compiler(current_compiler, pattern)
-
$compile = true
-
end
-
# Return false so the Origen generate command stops
-
return false
-
end
-
96
true
-
end
-
end
-
-
# Instantiate an instance of this class immediately when this file is required, this object will
-
# then listen for the remainder of the Origen thread
-
2
CallbackHandlers.new
-
end
-
2
Dir.glob("#{File.dirname(__FILE__)}/charz/**/*.rb").sort.each do |file|
-
10
require file
-
end
-
2
module OrigenTesters
-
2
module Charz
-
2
CharzTuple = Struct.new(:obj, :options, :defined_routines, keyword_init: true)
-
# @!attribute charz_stack
-
# @return [Array] FILO queue of charz session defining data
-
# @!attribute charz_routines
-
# @return [Hash] user defined charz routines
-
# @!attribute charz_profiles
-
# @return [Hash] user defined charz profiles
-
# @!attribute charz_session
-
# @return [Session] current charz session, based on data in the top of the charz_stack
-
# @!attribute charz_instance
-
# @return [Session] current charz instance of the session. If there is not a current instance, will return the first instance of the session instance stack
-
# @!attribute eof_charz_tests
-
# @return [Array] charz tests to be added at the end of the flow
-
# @!attribute skip_group_eof_charz_tests
-
# @return [Boolean] whether or not to wrap eof charz tests in a group
-
# @!attribute eof_charz_tests_group_name
-
# @return [String, Symbol] group name to be used to for eof charz tests
-
2
attr_accessor :charz_stack, :charz_routines, :charz_profiles, :charz_session, :charz_instance, :eof_charz_tests, :skip_group_eof_charz_tests, :eof_charz_tests_group_name
-
-
2
def charz_stack
-
173
@charz_stack ||= []
-
end
-
-
2
def charz_profiles
-
1750
@charz_profiles ||= {}
-
end
-
-
2
def charz_routines
-
2363
@charz_routines ||= {}
-
end
-
-
2
def charz_session
-
992
@charz_session ||= Session.new
-
end
-
-
# If there is a current instance present, that should always be used. However when running EOF charz,
-
# the instance to be used is no longer set, so instead of referencing the session, use the one that we've
-
# stored already
-
2
def charz_instance
-
187
unless charz_session.current_instance(stored_instance_valid: true).nil?
-
185
set_charz_instance(charz_session.current_instance(stored_instance_valid: true))
-
end
-
187
@charz_instance
-
end
-
-
2
def set_charz_instance(instance)
-
204
@charz_instance = instance
-
204
charz_session.stored_instance = instance
-
end
-
-
2
def eof_charz_tests
-
142
@eof_charz_tests ||= []
-
end
-
-
# Add a new charz routine to @charz_routines
-
# A charz routine is a object that contains all the necessary info specific to a characterization test
-
# Its intended to be used in combination with an existing point test (regular non charz test) to create
-
# a characterization version of the point test
-
#
-
# To use your own Routine classes, override the create_charz_routine method in your interface
-
#
-
# @example create a 1d search routine that searches vdd, from 900mv to 300mv, resolution of 5mv
-
# add_charz_routine :my_routine, type: search do |rt|
-
# rt.start = 900.mv
-
# rt.stop = 300.mv
-
# rt.res = 5.mv
-
# rt.spec = 'vdd'
-
# end
-
#
-
# @param [Symbol] id charz_routine id, will be the key value in the @charz_routines hash. Must not have been previously used
-
# @param [Hash] options charz_routine options
-
# @option options [Symbol] :type :search or :'1d' will create a SearchRoutine, :shmoo or :'2d' will create a ShmooRoutine, nil will create a Routine
-
2
def add_charz_routine(id, options = {}, &block)
-
711
if charz_routines.ids.include?(id)
-
1
Origen.log.error("Cannot create charz routine '#{id}', it already exists!")
-
1
fail
-
end
-
710
charz_routines[id] = create_charz_routine(id, options, &block)
-
end
-
-
# Called by add_charz_routine, split out from that method to make it easier to override this handler from a user's interface
-
# This is the method to override if you want to use custom Routines specifc to your company's implementation
-
#
-
# @param [Symbol] id charz_routine id, will be the key value in the @charz_routines hash. Must not have been previously used
-
# @param [Hash] options charz_routine options
-
# @option options [Symbol] :type :search or :'1d' will create a SearchRoutine, :shmoo or :'2d' will create a ShmooRoutine, nil will create a Routine
-
# @return [Routine] a charz routine object
-
2
def create_charz_routine(id, options = {}, &block)
-
710
case options[:type]
-
when :search, :'1d'
-
5
SearchRoutine.new(id, options, &block)
-
when :shmoo, :'2d'
-
3
ShmooRoutine.new(id, options, &block)
-
else
-
702
Routine.new(id, options, &block)
-
end
-
end
-
-
# Add a new charz profile to @charz_profiles
-
# A charz profile is a collection of one or more charz routines, as well as flow control and placement data for
-
# the charz tests generated by those routines
-
#
-
# @example create a profile containing 2 routines, end of flow placement, whose tests are only ran if the parent fails
-
# add_charz_profile :my_profile do |prof|
-
# prof.routines = [:my_routine1, :my_routine2]
-
# prof.placement = :eof
-
# prof.on_result = :on_fail
-
# end
-
#
-
# @param [Symbol] id charz_profile id, will be the key value in the @charz_profiles hash. Must not have been previously used
-
# @param [Hash] options charz_profile options
-
2
def add_charz_profile(id, options = {}, &block)
-
856
if charz_profiles.ids.include?(id)
-
1
Origen.log.error("Cannot create charz profile '#{id}', it already exists!")
-
1
fail
-
end
-
855
charz_profiles[id] = Profile.new(id, options.merge(defined_routines: charz_routines.ids), &block)
-
end
-
-
# Queries the current charz session to see if its active, indicating point tests should be generating charz tests
-
2
def charz_active?
-
135
charz_session.active?
-
end
-
-
# Queries the current charz session to see if point tests should skip generation, only adding the resulting charz test
-
2
def charz_only?
-
55
charz_active? && charz_session.charz_only?
-
end
-
-
# Pauses the current charz session, preventing point tests from generating charz tests even if the session is valid
-
2
def charz_pause
-
4
charz_session.pause
-
end
-
-
# Resumes the current charz session. If the session isn't valid (ie charz_resume before setting up the session) then nothing will happen
-
2
def charz_resume
-
4
charz_session.resume
-
end
-
-
# Removes the current session generating data off the charz stack
-
# If charz data is still on the stack afterward, the session will update to reflect the new data
-
# if not, the session will become inactive
-
2
def charz_off
-
20
charz_stack.pop
-
20
unless charz_session.update(charz_stack.last) || charz_stack.empty?
-
Origen.log.error 'charz_on failed to create a valid charz session'
-
fail
-
end
-
20
if charz_stack.empty?
-
18
set_charz_instance(nil)
-
end
-
end
-
-
# Pushes a charz object (either a profile or a routine) onto the stack, along with any optional updates to modify the current session
-
# Once pushed, the charz_session will attempt to update itself with the new data, failing if the resulting session is invalid
-
#
-
# If a block is passed, yield the block of tests to enable charz for those tests, then disable charz with a charz_off call
-
#
-
# @param [Symbol] charz_id either a routine or profile id. Method fails if the id can't be found in @charz_routines or @charz_profiles
-
# @param [Hash] options charz_on options
-
# @option options [Symbol] :type (:profile) whether the charz_id refers to a charz profile or routine
-
2
def charz_on(charz_id, options = {})
-
38
charz_stack.push([get_charz_tuple(charz_id, options)])
-
36
unless charz_session.update(charz_stack.last)
-
Origen.log.error 'charz_on failed to create a valid charz session'
-
fail
-
end
-
35
if block_given?
-
2
yield
-
2
charz_off
-
end
-
end
-
-
# Pushes a charz object (either a profile or a routine) onto the current sessions instance stack, along with any optional updates to modify that instance.
-
# This will result in subsequent charzable point tests in being processed against each of the current instances. In other words, this new push will not
-
# take priority over the current stack head, but instead append to it.
-
# Once pushed, the charz_session will attempt to update itself with the new data, failing if the resulting session is invalid
-
#
-
# If a block is passed, yield the block of tests to enable charz for those tests, then disable charz with a charz_off_truncate call
-
#
-
# @param [Symbol] charz_id either a routine or profile id. Method fails if the id can't be found in @charz_routines or @charz_profiles
-
# @param [Hash] options charz_on options
-
# @option options [Symbol] :type (:profile) whether the charz_id refers to a charz profile or routine
-
2
def charz_on_append(charz_id, options = {})
-
4
charz_tuple = get_charz_tuple(charz_id, options)
-
-
# take the current session and append to its instance stack
-
4
session = charz_stack.pop || []
-
4
session.push(charz_tuple)
-
4
charz_stack.push(session)
-
-
4
unless charz_session.update(charz_stack.last)
-
Origen.log.error 'charz_on failed to create a valid charz session'
-
fail
-
end
-
4
if block_given?
-
yield
-
charz_off_truncate
-
end
-
end
-
-
# Removes the current sessions last instance. If the session only had one instance, this is functionally the same as charz_off
-
# If charz data is still on the stack afterward, the session will update to reflect the new data
-
# if not, the session will become inactive
-
2
def charz_off_truncate
-
2
session = charz_stack.pop || []
-
2
session.pop
-
2
unless session.empty?
-
2
charz_stack.push(session)
-
end
-
-
2
unless charz_session.update(charz_stack.last) || charz_stack.empty?
-
Origen.log.error 'charz_on failed to create a valid charz session'
-
fail
-
end
-
2
if charz_stack.empty?
-
set_charz_instance(nil)
-
end
-
end
-
-
# An optional helper method to automatically assign an id to tests that will be generating charz tests that depend on the result of the parent test
-
# @param [Hash] options the options for a test before its created and added to the flow
-
# @param [TestInstance, #name] instance <Optional> the test instance whose name is stored in .name, alternatively pass the name in the options hash under :parent_test_name
-
2
def set_conditional_charz_id(*args)
-
55
case args.size
-
when 1
-
47
options = args[0]
-
47
parent_test_name = options[:parent_test_name]
-
when 2
-
7
instance = args[0]
-
7
options = args[1]
-
7
parent_test_name = instance.name
-
else
-
1
Origen.log.error 'Too many arguments passed to set_conditional_charz_id. Pass either (test_instance, options), or just (options)'
-
1
fail
-
end
-
54
unless options[:id]
-
50
if charz_active?
-
46
if charz_session.on_result?
-
9
md5_id = Digest::MD5.new
-
9
md5_id << parent_test_name.to_s
-
9
md5_id << options.to_s
-
9
md5_id << charz_session.id.to_s
-
9
options[:id] = "auto_charz_id_#{md5_id}".to_sym
-
end
-
end
-
end
-
end
-
-
# Called after the relevant point test has been inserted into the flow
-
# Takes the options used to build the previous point test as well as insert_charz_test specific options to then
-
# drill down to the point of the flow where the charz test would go, at which point control is handed back to the user's
-
# interface to handle creating and inserting the test. This will occur for each instance in the current session's instance stack
-
#
-
# By default, this method will handle:
-
# - the placement of the test (inline aka right after the point test, end of flow, or other)
-
# - wrapping the created charz tests in a group (skippable, group name defaults to <point test name> charz <session name>)
-
# - conditionally executing the charz tests based on if the point test passed or failed (see set_conditional_charz_id)
-
# - conditionally executing some/all charz tests based on a mix of enables and flags
-
#
-
# After the above is determined, the user regains control on a per-routine (if multiple routines) basis to then process generating the charz test
-
2
def insert_charz_tests(options, &block)
-
16
if charz_active?
-
15
if options[:id]
-
# two purposes:
-
# 1) prevent all charz tests inadverntently using the same ID as their parent
-
# 2) used in on_result behavior
-
2
current_id = options.delete(:id)
-
2
options[:last_test_id] ||= current_id
-
end
-
15
charz_session.loop_instances do
-
16
case charz_instance.placement
-
when :inline
-
15
create_charz_group(options, &block)
-
when :eof
-
# collect the current instance and options into a proc, stored in eof_charz_tests to be called later
-
1
current_instance = charz_instance.clone
-
1
eof_charz_tests << proc do
-
1
set_charz_instance(current_instance)
-
1
create_charz_group(options, &block)
-
end
-
else
-
# inline is the default behavior, and eof (end of flow) has built in support.
-
if respond_to?(:"create_#{charz_instance.placement}_charz_tests")
-
send(:"create_#{charz_instance.placement}_charz_tests", options, &block)
-
elsif respond_to?(:"insert_#{charz_instance.placement}_charz_tests")
-
send(:"insert_#{charz_instance.placement}_charz_tests", options, &block)
-
else
-
Origen.log.error "No handling specified for #{charz_instance.placement} placement charz tests"
-
fail
-
end
-
end
-
end
-
end
-
end
-
-
# called automatically right after a top_level shutdown, generates end of flow charz tests
-
# user should not have to reference this call explicitly
-
2
def generate_eof_charz_tests
-
139
unless eof_charz_tests.empty?
-
1
if skip_group_eof_charz_tests
-
eof_charz_tests.map(&:call)
-
else
-
1
group_name = eof_charz_tests_group_name || 'End of Flow Charz Tests'
-
1
group group_name do
-
1
eof_charz_tests.map(&:call)
-
end
-
end
-
end
-
end
-
-
2
private
-
-
# helper method for charz_on and charz_on_append
-
2
def get_charz_tuple(charz_id, options)
-
42
options[:type] ||= :profile
-
42
case options[:type]
-
when :profile
-
34
charz_obj = charz_profiles[charz_id]
-
when :routine
-
7
if charz_id.is_a?(Array)
-
1
charz_obj = charz_routines[charz_id.first]
-
1
options[:routines] = charz_id
-
else
-
6
charz_obj = charz_routines[charz_id]
-
6
options[:routines] = [charz_id]
-
end
-
else
-
1
Origen.log.error "Unknown charz object type #{options[:type]}, valid types: :profile, :routine"
-
1
fail
-
end
-
41
if charz_obj.nil?
-
1
Origen.log.error "No #{options[:type]} found for charz_id: #{charz_id}"
-
1
fail
-
end
-
40
CharzTuple.new(obj: charz_obj, options: options, defined_routines: charz_routines.ids)
-
end
-
-
# called by insert_charz_tests
-
#
-
# if insert_charz_tests was called with the skip group option, then skip to processing the sessions on_result functionality
-
# otherwise, on_result processing occurs within the created group
-
#
-
# group name defaults to <point test name> charz <session name>, but can be set by the user by passing :group_name in the options
-
2
def create_charz_group(options, &block)
-
16
if options[:skip_group]
-
1
process_on_result(options, &block)
-
else
-
15
group_name = options[:group_name] || "#{options[:parent_test_name]} charz #{charz_instance.name}"
-
15
group group_name.to_sym do
-
15
process_on_result(options, &block)
-
end
-
end
-
end
-
-
# called by create_charz_group
-
#
-
# Handles the case where the session indicates these charz tests' execution depend on the point test's result
-
# Requires that the id of the point test has been passed to use this functionality. Otherwise, make sure that
-
# charz_session.on_result == nil
-
#
-
# on_fail and on_pass results are built-in, but if the user has a different check to make, it can be handled
-
# by defining the method process_<custom result>_charz_tests
-
#
-
# @see set_conditional_charz_id
-
2
def process_on_result(options, &block)
-
16
if charz_instance.on_result
-
2
case charz_instance.on_result
-
when :on_fail, :fail, :failed
-
1
last_test_id = options[:last_test_id] || @last_test_id
-
1
if_failed last_test_id do
-
1
process_gates(options, &block)
-
end
-
when :on_pass, :pass, :passed
-
1
last_test_id = options[:last_test_id] || @last_test_id
-
1
if_passed last_test_id do
-
1
process_gates(options, &block)
-
end
-
else
-
if respond_to?(:"process_#{charz_instance.placement}_charz_tests")
-
send(:"process_#{charz_instance.on_result}_charz_tests", options, &block)
-
else
-
Origen.log.error "No handling specified for result #{charz_instance.on_result} charz tests"
-
fail
-
end
-
end
-
else
-
14
process_gates(options, &block)
-
end
-
end
-
-
# called by process_on_result
-
#
-
# Handles the case where charz_session.enables or charz_session.flags have been set
-
# referring to enables and flags both as gates, gates can wrap all routines in a session if they're in the form of an
-
# array, symbol, or a string (think of the normal use case of if_enable or if_flag)
-
#
-
# If the gate is a Hash, then that means different routines are getting different gate wrappers.
-
# Also if a routine is not indicated in the values of the gate, then that means that routine should not be gated at all
-
#
-
# This is the final method of handling the insert_charz_test usecases, where the block thats been passed around is finally called
-
# the user's provided block is passed the current routine (one at a time) to then take its info to generate a charz test
-
-
# Pass an "and_if_true" variable for enables and flags? And use that to to decide what to do? Then we don't need 4.
-
# But the hash has to be structured a different way for the enable_and (routine is key, enables is value.)
-
2
def process_gates(options, &block)
-
16
if options[:skip_gates] || !(charz_instance.enables || charz_instance.flags)
-
5
charz_instance.routines.each do |routine|
-
5
block.call(options.merge(current_routine: routine))
-
end
-
else
-
11
if charz_instance.and_enables
-
2
if charz_instance.flags
-
# Wrap all tests in flag, wrap some tests in anded enables.
-
1
ungated_routines = charz_instance.routines - charz_instance.enables.keys
-
1
ungated_routines.each do |routine|
-
if_flag charz_instance.flags do
-
block.call(options.merge(current_routine: routine))
-
end
-
end
-
1
gated_routines = charz_instance.routines - ungated_routines
-
# Build the proc which contains the nested if statements for each routine so they are anded.
-
1
gated_routines.each do |routine|
-
1
my_proc = -> do
-
1
if_flag charz_instance.flags do
-
1
block.call(options.merge(current_routine: routine))
-
end
-
end
-
1
charz_instance.enables[routine].inject(my_proc) do |my_block, enable|
-
2
lambda do
-
2
if_enable :"#{enable}" do
-
2
my_block.call
-
end
-
end
-
end.call
-
end
-
else
-
1
ungated_routines = charz_instance.routines - charz_instance.enables.keys
-
1
ungated_routines.each do |routine|
-
block.call(options.merge(current_routine: routine))
-
end
-
# Build the proc which contains the nested if statements for each routine so they are anded.
-
1
gated_routines = charz_instance.routines - ungated_routines
-
1
gated_routines.each do |routine|
-
2
my_proc = -> { block.call(options.merge(current_routine: routine)) }
-
1
charz_instance.enables[routine].inject(my_proc) do |my_block, enable|
-
2
lambda do
-
2
if_enable :"#{enable}" do
-
2
my_block.call
-
end
-
end
-
end.call
-
end
-
end
-
9
elsif charz_instance.and_flags
-
3
if charz_instance.enables
-
# Wrap all tests in enable, some tests in anded flags.
-
2
ungated_routines = charz_instance.routines - charz_instance.flags.keys
-
2
ungated_routines.each do |routine|
-
if_enable charz_instance.enables do
-
block.call(options.merge(current_routine: routine))
-
end
-
end
-
# Build the proc which contains the nested if statemements for each routine so they are anded.
-
2
gated_routines = charz_instance.routines - ungated_routines
-
2
gated_routines.each do |routine|
-
2
my_proc = -> do
-
2
if_enable charz_instance.enables do
-
2
block.call(options.merge(current_routine: routine))
-
end
-
end
-
2
charz_instance.flags[routine].inject(my_proc) do |my_block, flag|
-
4
lambda do
-
4
if_flag :"#{flag}" do
-
4
my_block.call
-
end
-
end
-
end.call
-
end
-
else
-
1
ungated_routines = charz_instance.routines - charz_instance.flags.keys
-
1
ungated_routines.each do |routine|
-
block.call(options.merge(current_routine: routine))
-
end
-
# Build the proc which contains the nested if statemements for each routine so they are anded.
-
1
gated_routines = charz_instance.routines - ungated_routines
-
1
gated_routines.each do |routine|
-
2
my_proc = -> { block.call(options.merge(current_routine: routine)) }
-
1
charz_instance.flags[routine].inject(my_proc) do |my_block, flag|
-
2
lambda do
-
2
if_flag :"#{flag}" do
-
2
my_block.call
-
end
-
end
-
end.call
-
end
-
end
-
6
elsif charz_instance.enables && charz_instance.flags
-
4
if charz_instance.enables.is_a?(Hash) && !charz_instance.flags.is_a?(Hash)
-
# wrap all tests in flags, wrap specific tests in enables
-
1
if_flag charz_instance.flags do
-
1
insert_hash_gates(options, charz_instance.enables, :if_enable, &block)
-
end
-
3
elsif !charz_instance.enables.is_a?(Hash) && charz_instance.flags.is_a?(Hash)
-
# wrap all tests in enables, wrap specific tests in flags
-
1
if_enable charz_instance.enables do
-
1
insert_hash_gates(options, charz_instance.flags, :if_flag, &block)
-
end
-
2
elsif charz_instance.enables.is_a?(Hash) && charz_instance.flags.is_a?(Hash)
-
# first insert the tests that are not tied to an enable or flag gate
-
1
ungated_routines = charz_instance.routines - (charz_instance.enables.values.flatten | charz_instance.flags.values.flatten)
-
1
ungated_routines.each do |routine|
-
1
block.call(options.merge(current_routine: routine))
-
end
-
# wrap tests in an enable gate, flag gate, or both
-
1
gated_routines = charz_instance.routines - ungated_routines
-
1
gated_routines.each do |routine|
-
16
enable = charz_instance.enables.find { |gates, routines| routines.include?(routine) }&.first
-
15
flag = charz_instance.flags.find { |gates, routines| routines.include?(routine) }&.first
-
5
if enable && flag
-
3
if_enable enable do
-
3
if_flag flag do
-
# wrap test in both enable and flag gate
-
3
block.call(options.merge(current_routine: routine))
-
end
-
end
-
2
elsif enable
-
1
if_enable enable do
-
# enable only
-
1
block.call(options.merge(current_routine: routine))
-
end
-
1
elsif flag
-
1
if_flag flag do
-
# flag only
-
1
block.call(options.merge(current_routine: routine))
-
end
-
end
-
end
-
else
-
# both enable and flag is set, and both apply to all routines in session
-
1
if_enable charz_instance.enables do
-
1
if_flag charz_instance.flags do
-
1
charz_instance.routines.each do |routine|
-
1
block.call(options.merge(current_routine: routine))
-
end
-
end
-
end
-
end
-
else
-
# only enables or flags is set, not both
-
2
if charz_instance.enables
-
1
gates = charz_instance.enables
-
1
gate_method = :if_enable
-
1
elsif charz_instance.flags
-
1
gates = charz_instance.flags
-
1
gate_method = :if_flag
-
end
-
2
if gates.is_a?(Hash)
-
# wrap some tests in specific gates
-
insert_hash_gates(options, gates, gate_method, &block)
-
else
-
# wrap all tests in the indicated gates
-
2
send(gate_method, gates) do
-
2
charz_instance.routines.each do |routine|
-
2
block.call(options.merge(current_routine: routine))
-
end
-
end
-
end
-
end
-
end
-
end
-
-
# helper method for the process gates method above
-
# handles wrapping routines in specific gates, and passing ungated routines back to the user
-
2
def insert_hash_gates(options, gate_hash, gate_method, &block)
-
2
ungated_routines = charz_instance.routines - gate_hash.values.flatten
-
2
ungated_routines.each do |routine|
-
4
block.call(options.merge(current_routine: routine))
-
end
-
2
gate_hash.each do |gate, gated_routines|
-
6
send(gate_method, gate) do
-
6
gated_routines.each do |routine|
-
8
block.call(options.merge(current_routine: routine))
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Charz
-
# A Charz Profile
-
# Used to store characterization routines as well as flow control, conditional execution, and test placement meta data
-
2
class Profile
-
# @!attribute id
-
# @return [Symbol] the id of the current profile, used as a key in OrigenTesters::Charz#charz_profiles hash
-
# @!attribute name
-
# @return [Symbol] the value used (if the user decides) to generate the name of the created charz test. defaults to the value of @id
-
# @!attribute placement
-
# @return [Symbol] placement of the to be created charz tests, defaults to inline, accepts :eof as well. Other placements can be used as well if @valid_placements is altered
-
# @!attribute on_result
-
# @return [Symbol] indicates if the resulting charz tests are depending on the point tests result, valid values include :on_fail, and :on_pass
-
# @!attribute enables
-
# @return [Symbol, String, Array, Hash] enable gates to be wrapped around the resulting charz tests
-
# @!attribute flags
-
# @return [Symbol, String, Array, Hash] flag gates to be wrapped around the resulting charz tests
-
# @!attribute routines
-
# @return [Array] list of charz routines to be called under this profile
-
# @!attribute charz_only
-
# @return [Boolean] indicates if the point tests should or shouldn't be added to the flow
-
2
attr_accessor :id, :name, :placement, :on_result, :enables, :flags, :routines, :charz_only, :force_keep_parent, :and_enables, :and_flags
-
-
2
def initialize(id, options, &block)
-
906
@id = id
-
906
@id = @id.symbolize unless id.is_a? Symbol
-
2501
options.each { |k, v| instance_variable_set("@#{k}", v) }
-
906
(block.arity < 1 ? (instance_eval(&block)) : block.call(self)) if block_given?
-
906
@name ||= id
-
906
@placement ||= :inline
-
906
@defined_routines = options.delete(:defined_routines)
-
906
attrs_ok?
-
892
massage_gates
-
end
-
-
2
def attrs_ok?
-
906
return if @quality_check == false
-
-
906
unless @routines.is_a?(Array)
-
1
Origen.log.error "Profile #{id}: routines is expected to be of type <Array>, but is instead of type <#{@routines.class}>!"
-
1
fail
-
end
-
-
# allowing a config for empty routines for usecase of
-
# determining routines on the fly dynamically
-
905
if @routines.empty? && !@allow_empty_routines
-
1
Origen.log.error "Profile #{id}: routines array is empty!"
-
1
Origen.log.warn "If you'd like to enable profile creation without routines, set the profile's @allow_empty_routines attribute to true"
-
1
fail
-
end
-
-
904
unknown_routines = @routines - @defined_routines
-
904
unless unknown_routines.empty?
-
1
Origen.log.error "Profile #{id}: unknown routines: #{unknown_routines}"
-
1
fail
-
end
-
-
903
@valid_placements ||= [:inline, :eof]
-
903
unless @valid_placements.include? @placement
-
1
Origen.log.error "Profile #{id}: invalid placement value, must be one of: #{@valid_placements}"
-
1
fail
-
end
-
-
902
if @on_result
-
49
@valid_on_results ||= [:on_fail, :fail, :failed, :on_pass, :pass, :passed]
-
49
unless @valid_on_results.include?(@on_result)
-
1
Origen.log.error "Profile #{id}: invalid on_result value, must be one of: #{@valid_on_results}"
-
1
fail
-
end
-
end
-
-
901
if @charz_only && @on_result
-
1
Origen.log.error "Profile #{id}: @charz_only is set, but @on_result (#{@on_result}) requires the parent test to exist in the flow"
-
1
fail
-
end
-
-
900
unless @gate_checks == false
-
900
if @and_enables && @and_flags
-
1
Origen.log.error "@and_enables and @and_flags are both set to true. Please only 'and' one gate type"
-
1
fail
-
end
-
899
if @and_enables
-
207
gate_check(@flags, :flags) if @flags
-
207
gate_check_and(@enables, :enables, @flags) if @enables
-
692
elsif @and_flags
-
204
gate_check(@enables, :enables) if @enables
-
204
gate_check_and(@flags, :flags, @enables) if @flags
-
else
-
488
gate_check(@enables, :enable) if @enables
-
484
gate_check(@flags, :flags) if @flags
-
end
-
end
-
end
-
-
# convert hash gates to set convert their routines to type array if not already
-
2
def massage_gates
-
892
if @enables.is_a?(Hash)
-
106
@enables = {}.tap do |new_h|
-
417
@enables.each { |gates, routines| new_h[gates] = [routines].flatten }
-
end
-
end
-
892
if @flags.is_a?(Hash)
-
107
@flags = {}.tap do |new_h|
-
418
@flags.each { |gates, routines| new_h[gates] = [routines].flatten }
-
end
-
end
-
end
-
-
2
def gate_check(gates, gate_type)
-
1239
case gates
-
when Symbol, String
-
return
-
when Array
-
826
unknown_gates = gates.reject { |gate| [String, Symbol].include? gate.class }
-
413
if unknown_gates.empty?
-
return
-
else
-
1
Origen.log.error "Profile #{id}: Unknown #{gate_type} type(s) in #{gate_type} array."
-
1
Origen.log.error "Arrays must contain Strings and/or Symbols, but #{unknown_gates.map(&:class).uniq } were found in #{gates}"
-
1
fail
-
end
-
when Hash
-
208
gates.each do |gate, gated_routines|
-
616
if gate.is_a? Hash
-
1
Origen.log.error "Profile #{id}: #{gate_type} Hash keys cannot be of type Hash, but only Symbol, String, or Array"
-
1
fail
-
end
-
615
gate_check(gate, gate_type)
-
615
gated_routines = [gated_routines] unless gated_routines.is_a? Array
-
615
unknown_routines = gated_routines - @defined_routines
-
615
unless unknown_routines.empty?
-
1
Origen.log.error "Profile #{id}: unknown routines found in @#{gate_type}[#{gate.is_a?(Symbol) ? ':' : ''}#{gate}]: #{unknown_routines}"
-
1
fail
-
end
-
end
-
else
-
1
Origen.log.error "Profile #{id}: Unknown #{gate_type} type: #{gates.class}. #{gate_type} must be of type Symbol, String, Array, or Hash"
-
1
fail
-
end
-
end
-
-
2
def gate_check_and(gates, gate_type, other_gate)
-
11
if other_gate.is_a? Hash
-
Origen.log.error "Profile #{id}: #{other_gate} When using &&-ing feature, the non-anded gate can not be of type hash."
-
fail
-
end
-
11
case gates
-
when Symbol, String
-
return
-
when Array
-
6
unknown_gates = gates.reject { |gate| [String, Symbol].include? gate.class }
-
2
if unknown_gates.empty?
-
return
-
else
-
1
Origen.log.error "Profile #{id}: Unknown #{gate_type} type(s) in #{gate_type} array."
-
1
Origen.log.error "Arrays must contain Strings and/or Symbols, but #{unknown_gates.map(&:class).uniq } were found in #{gates}"
-
1
fail
-
end
-
when Hash
-
9
gates.each do |gated_routine, gates|
-
10
if gated_routine.is_a? Hash
-
1
Origen.log.error "Profile #{id}: #{gate_type} Hash keys cannot be of type Hash, but only Symbol, String, or Array"
-
1
fail
-
end
-
9
unless @defined_routines.include?(gated_routine)
-
1
Origen.log.error "Profile #{id}: #{gated_routine} Hash keys for &&-ed gates must be defined routines."
-
1
fail
-
end
-
8
gates = [gates] unless gates.is_a? Array
-
23
unknown_gates = gates.reject { |gate| [String, Symbol].include? gate.class }
-
8
unless unknown_gates.empty?
-
Origen.log.error "Gate array must contain Strings and/or Symbols, but #{unknown_gates.map(&:class).uniq } were found in #{gates}"
-
fail
-
end
-
end
-
else
-
Origen.log.error "Profile #{id}: Unknown #{gate_type} type: #{gates.class}. #{gate_type} must be of type Symbol, String, Array, or Hash"
-
fail
-
end
-
end
-
-
2
def method_missing(m, *args, &block)
-
138
ivar = "@#{m.to_s.gsub('=', '')}"
-
138
ivar_sym = ":#{ivar}"
-
138
if m.to_s =~ /=$/
-
4
define_singleton_method(m) do |val|
-
4
instance_variable_set(ivar, val)
-
end
-
134
elsif instance_variables.include? ivar_sym
-
instance_variable_get(ivar)
-
else
-
134
define_singleton_method(m) do
-
295
instance_variable_get(ivar)
-
end
-
end
-
138
send(m, *args, &block)
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Charz
-
# A Generic charz routine
-
# Used to store characterization test specific meta data, values of which are used by the user to determine test parameter values
-
2
class Routine
-
# @!attribute id
-
# @return [Symbol] charz routine symbol, used as a key in OrigenTesters::Charz#charz_routines
-
# @!attribute name
-
# @return [Symbol] the value used (if the user decides) to generate the name of the created charz test. defaults to the value of @id
-
2
attr_accessor :id, :name
-
-
2
def initialize(id, options = {}, &block)
-
710
@id = id
-
710
@id = @id.symbolize unless id.is_a? Symbol
-
718
options.each { |k, v| instance_variable_set("@#{k}", v) }
-
710
(block.arity < 1 ? (instance_eval(&block)) : block.call(self)) if block_given?
-
710
@name ||= @id
-
end
-
-
2
def method_missing(m, *args, &block)
-
486
ivar = "@#{m.to_s.gsub('=', '')}"
-
486
ivar_sym = ":#{ivar}"
-
486
if m.to_s =~ /=$/
-
408
define_singleton_method(m) do |val|
-
408
instance_variable_set(ivar, val)
-
end
-
78
elsif instance_variables.include? ivar_sym
-
instance_variable_get(ivar)
-
else
-
78
define_singleton_method(m) do
-
114
instance_variable_get(ivar)
-
end
-
end
-
486
send(m, *args, &block)
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Charz
-
# a 1D search routine
-
2
class SearchRoutine < Routine
-
# @!attribute start
-
# @return [Numeric] search start value
-
# @!attribute stop
-
# @return [Numeric] search stop value
-
# @!attribute res
-
# @return [Numeric] search resolution
-
# @!attribute spec
-
# @return [Numeric] spec parameter to be searched
-
2
attr_accessor :start, :stop, :res, :spec
-
-
# Runs the same initialization as Routine
-
# performs some rudimentary quality checks, which can be disabled by setting @quality_check = false
-
2
def initialize(id, options = {}, &block)
-
5
super
-
5
attrs_ok?
-
end
-
-
2
def attrs_ok?
-
5
return if @quality_check == false
-
-
5
@required_attrs ||= [:start, :stop, :res, :spec]
-
25
attrs = @required_attrs.map { |attr| instance_variable_get("@#{attr}") }
-
5
if attrs.compact.size != @required_attrs.size
-
1
Origen.log.error "SearchRoutine #{@id}: unspecified attributes, each of #{@required_attrs} must have a value"
-
1
fail
-
end
-
-
4
return if @attr_value_check == false
-
16
if [@start, @stop, @res].all? { |attr| attr.is_a? Numeric }
-
4
unless @res <= (@start - @stop).abs
-
1
Origen.log.error "SearchRoutine #{@id}: Search resolution (#{@res}) is larger than the search range: #{(@start - @stop).abs}"
-
1
fail
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Charz
-
# A 2D search or "Shmoo" routine
-
2
class ShmooRoutine < Routine
-
# @!attribute x_start
-
# @return [Numeric] the starting search value for the x dimension's spec search
-
# @!attribute x_stop
-
# @return [Numeric] the stopping search value for the x dimension's spec search
-
# @!attribute x_res
-
# @return the search resolution value for the x dimension's spec search
-
# @!attribute x_spec
-
# @return [Symbol, String] the spec parameter of interest for the x dimension
-
2
attr_accessor :x_start, :x_stop, :x_res, :x_spec
-
# @!attribute y_start
-
# @return [Numeric] the starting search value for the x dimension's spec search
-
# @!attribute y_stop
-
# @return [Numeric] the stopping search value for the x dimension's spec search
-
# @!attribute y_res
-
# @return the search resolution value for the x dimension's spec search
-
# @!attribute y_spec
-
# @return [Symbol, String] the spec parameter of interest for the x dimension
-
2
attr_accessor :y_start, :y_stop, :y_res, :y_spec
-
-
2
def initialize(id, options = {}, &block)
-
3
super
-
3
attrs_ok?
-
end
-
-
2
def attrs_ok?
-
3
return if @quality_check == false
-
-
3
@required_attrs ||= [:x_start, :x_stop, :x_res, :x_spec, :y_start, :y_stop, :y_res, :y_spec]
-
27
attrs = @required_attrs.map { |attr| instance_variable_get("@#{attr}") }
-
3
if attrs.compact.size != @required_attrs.size
-
1
Origen.log.error "ShmooRoutine #{@id}: unspecified attributes, each of #{@required_attrs} must have a value"
-
1
fail
-
end
-
-
2
return if @attr_value_check == false
-
-
# not sure if I want this check, if so need to scope out if step count is common
-
-
# if [@x_start, @x_stop, @x_res].all? { |attr| attr.is_a? Numeric }
-
# unless @x_res <= (@x_start - @x_stop).abs
-
# Origen.log.error "ShmooRoutine #{@id}: Search x_resolution (#{@x_res} is larger than the search x_range (#{@x_start - @x_stop).abs})"
-
# fail
-
# end
-
# end
-
# if [@y_start, @y_stop, @y_res].all? { |attr| attr.is_a? Numeric }
-
# unless @y_res <= (@y_start - @y_stop).abs
-
# Origen.log.error "ShmooRoutine #{@id}: Search y_resolution (#{@y_res} is larger than the search y_range (#{@y_start - @y_stop).abs})"
-
# fail
-
# end
-
# end
-
2
unless @x_spec != @y_spec
-
1
Origen.log.error "ShmooRoutine #{@id}: Search x_spec is identical to y_spec"
-
1
fail
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Charz
-
# A charz session
-
# contains a collection of the final combinations of charz object (routines/profiles) and user options to determine how and what charz tests should be created
-
# the session should be checked in your interface to determine the current status and can be queried to make charz generation decisions
-
2
class Session
-
# @!attribute id
-
# @return [Symbol] current session ID. Will be a concatenation of the instances' ids
-
# @!attribute instances
-
# @return [Array] list of active instances (which are essentially Profiles)
-
# @!attribute current_instance
-
# @return [Profile] Set when looping over instances via #loop_instances. The interface can query the charz_instance for more detailed info
-
# @!attribute valid
-
# @return [Boolean] whether or not the current session setup is valid, if not then charz wont be created
-
# @!attribute defaults
-
# @return [Hash] list of values to instantiate the inherited attributes from Profile with if not altered by the session update
-
# @!attribute stored_instance
-
# @return [Profile] This is to store the instance that the interface is storing. Its to support a legacy usecase of querying the session for instance level info during EOF
-
2
attr_accessor :id, :instances, :current_instance, :valid, :defaults, :stored_instance
-
-
2
def initialize(options = {})
-
29
@id = :empty_session
-
29
@instances = []
-
29
@current_instance = nil
-
29
@stored_instance = nil
-
29
@active = false
-
29
@valid = false
-
@defaults = {
-
29
placement: :inline,
-
routines: [],
-
on_result: nil,
-
enables: nil,
-
flags: nil,
-
enables_and: false,
-
and_enables: false,
-
flags_and: false,
-
and_flags: false,
-
name: 'charz',
-
charz_only: false,
-
force_keep_parent: false
-
29
}.merge((options[:defaults] || {}))
-
end
-
-
2
def on_result?
-
109
instances.any? { |charz_instance| !charz_instance.on_result.nil? }
-
end
-
-
2
def charz_only?
-
57
any_only = instances.any?(&:charz_only)
-
57
any_force = instances.any?(&:force_keep_parent)
-
57
!any_force && any_only && !on_result?
-
end
-
-
2
def charz_only
-
5
Origen.log.deprecate '#charz_only has been deprecated in favor of #charz_only? It is no longer an attribute, instead a runtime calculation.'
-
5
charz_only?
-
end
-
-
# Pauses the current session's activity while maintaining everthing else about the sessions state
-
2
def pause
-
4
@active = false
-
end
-
-
2
def active?
-
147
!!@active
-
end
-
2
alias_method :active, :active?
-
-
# Resume activity, if the session is valid
-
2
def resume
-
4
if @valid
-
3
@active = true
-
end
-
end
-
-
2
def current_instance(options = {})
-
474
instance = @current_instance || instances.first
-
474
if instance.nil? && @stored_instance
-
10
unless options[:stored_instance_valid]
-
Origen.log.deprecate '@current_instance had to source @stored_instance. This likely means charz_session.<some_attr> is being queried when the newer charz_instance.<some_attr> should be instead'
-
end
-
10
instance = @stored_instance
-
end
-
474
instance
-
end
-
-
2
def loop_instances
-
16
instances.each do |charz_instance|
-
17
@current_instance = charz_instance
-
17
yield
-
17
@current_instance = nil
-
end
-
end
-
-
# Takes a CharzTuple and queries it to setup an instance's attributes
-
# the attributes values can be set from 3 different sources, in order of priority (first is most important):
-
# - options
-
# - charz object (Profile or Routine)
-
# - defaults
-
#
-
# If the resulting session is invalid, @valid will turn false. Otherwise, the session becomes active
-
2
def update(charz_tuples)
-
62
@instances = []
-
62
@valid = false
-
62
if charz_tuples.nil? || charz_tuples.empty?
-
18
@active = false
-
18
@valid = false
-
18
@current_instance = nil
-
18
return @valid
-
end
-
44
@defined_routines = charz_tuples.map(&:defined_routines).flatten.uniq.compact
-
-
44
charz_tuples.each do |charz_tuple|
-
51
profile_options = assign_by_priority(charz_tuple)
-
51
@instances << Profile.new(charz_tuple.obj.id, profile_options.merge(defined_routines: @defined_routines))
-
end
-
43
@id = instances.map(&:id).join('_').to_sym
-
43
@active = true
-
43
@valid = true
-
end
-
-
2
private
-
-
2
def assign_by_priority(charz_tuple)
-
51
options = charz_tuple.options
-
51
charz_obj = charz_tuple.obj
-
51
instance_options = {}
-
51
get_instance_setting_keys(charz_obj).each do |ivar|
-
915
if options.keys.include?(ivar)
-
44
instance_options[ivar] = options[ivar]
-
871
elsif charz_obj.send(ivar)
-
460
instance_options[ivar] = charz_obj.send(ivar)
-
411
elsif @defaults.keys.include?(ivar)
-
411
instance_options[ivar] = @defaults[ivar]
-
else
-
Origen.log.error "Charz Session: No value could be determined for #{ivar}"
-
fail
-
end
-
end
-
51
instance_options
-
end
-
-
2
def get_instance_setting_keys(charz_obj)
-
51
keys = charz_obj.instance_variables | @defaults.keys
-
1017
keys.map! { |k| k.to_s.sub('@', '').to_sym }
-
51
keys -= [:id]
-
51
keys
-
end
-
-
2
def method_missing(method, *args, &block)
-
51
deprecated_methods = [
-
:name,
-
:placement,
-
:on_result,
-
:enables,
-
:flags,
-
:routines,
-
:and_enables,
-
:enables_and,
-
:and_flags,
-
:flags_and,
-
:charz_only,
-
:force_keep_parent
-
]
-
51
if deprecated_methods.include?(method.to_sym) || deprecated_methods.include?(method.to_s[0..-2].to_sym)
-
51
Origen.log.deprecate "charz_session.#{method} has been deprecated. Please query charz_instance.#{method} instead."
-
51
if current_instance.nil? && !valid
-
Origen.log.error "blocked call of 'charz_session.#{method}'!"
-
Origen.log.warn 'The charz instance attributes are no longer accessible when the session is invalid!'
-
else
-
51
current_instance.send(method, *args, &block)
-
end
-
else
-
super
-
end
-
end
-
end
-
end
-
end
-
2
require_relative 'decompiler/decompiler_api'
-
2
require_relative 'decompiler/nodes'
-
2
require_relative 'decompiler/pattern'
-
-
2
module OrigenTesters
-
2
module Decompiler
-
2
extend API
-
end
-
end
-
2
module OrigenTesters
-
2
module Decompiler
-
2
module API
-
2
@registered_decompilers = []
-
-
# Decompiles the given pattern, returning
-
2
def decompile(pattern, options = {})
-
14
decompiled_pattern(pattern, options).decompile
-
end
-
-
# @note This method is the same as #decompile except that the module's
-
# #decompile method won't be automatically called.
-
2
def decompiled_pattern(pattern, options = {})
-
# decompiler!(pattern).decompiled_pattern(pattern)
-
16
_decompiler = options.delete(:decompiler)
-
16
_decompiler.nil? ? decompiler!(pattern).new(pattern, options) : _decompiler.new(pattern, options)
-
end
-
-
# Creates a decompiled pattern from the raw input directly.
-
# In this case, no attempts to figure out the decompiler are made. The
-
# suitable decompiler should either be given with the :decompiler parameter,
-
# or the current environment will be used.
-
2
def decompile_text(text, decompiler: nil)
-
2
if decompiler.nil?
-
1
select_decompiler!.new(text, direct_source: true).decompile
-
else
-
1
decompiler.new(text, direct_source: true).decompile
-
end
-
end
-
2
alias_method :decompile_str, :decompile_text
-
2
alias_method :decompile_string, :decompile_text
-
2
alias_method :decompile_raw_input, :decompile_text
-
-
# Returns the decompiler module that will be uesd to decompile the
-
# given pattern source.
-
2
def select_decompiler(pattern = nil, options = {})
-
28
if pattern.is_a?(Hash)
-
options = pattern
-
pattern = nil
-
28
elsif pattern.nil?
-
5
options = {}
-
5
pattern = nil
-
end
-
-
# if respond_to?(:suitable_decompiler_for)
-
# puts "HI".red
-
# puts self
-
# registered_decompilers = [self]
-
# end
-
-
28
_registered_decompilers = respond_to?(:suitable_decompiler_for) ? [self] : registered_decompilers
-
-
# We have the list of modules that support decompilation, but those modules
-
# could have sub-modules that support other decompilation flavors.
-
# We'll select the decompiler by just iterating through each support
-
# decompiler and until we find one that supports either the file extension,
-
# or the current tester name.
-
28
_registered_decompilers.each do |m|
-
36
if pattern
-
28
mod = m.suitable_decompiler_for(pattern: pattern, **options)
-
8
elsif tester.nil?
-
return nil
-
else
-
8
mod = m.suitable_decompiler_for(tester: Origen.tester.name.to_s, **options)
-
end
-
-
36
if mod
-
20
return mod
-
end
-
end
-
-
nil
-
end
-
2
alias_method :decompiler, :select_decompiler
-
2
alias_method :decompiler_for, :select_decompiler
-
-
2
def select_decompiler!(pattern = nil, options = {})
-
15
mod = select_decompiler(pattern, options)
-
-
15
if mod.nil? && pattern
-
# Origen.log.error "Unknown decompiler for file extension '#{File.extname(pattern)}'"
-
1
Origen.app!.fail(
-
message: "Cannot find a suitable decompiler for pattern source '#{pattern}' ('#{File.extname(pattern)}')",
-
exception_class: OrigenTesters::Decompiler::NoSuitableDecompiler
-
)
-
14
elsif mod.nil?
-
# Origen.log.error "Unknown decompiler for tester #{Origen.tester.name}"
-
# fail "Current environment '#{Orige.current_environment}' does not contain a suitable decompiler! Cannot select this as the decompiler."
-
1
Origen.app!.fail(
-
message: "Current environment '#{Origen.environment.file.basename}' does not contain a suitable decompiler! Cannot select this as the decompiler.",
-
exception_class: OrigenTesters::Decompiler::NoSuitableDecompiler
-
)
-
end
-
13
mod
-
end
-
2
alias_method :decompiler!, :select_decompiler!
-
2
alias_method :decompiler_for!, :select_decompiler!
-
-
# Returns all the registered decompiler modules.
-
# @note Registered decompilers are stored on the OrigenTesters::Decompiler module.
-
2
def registered_decompilers
-
41
OrigenTesters::Decompiler::API.instance_variable_get(:@registered_decompilers)
-
end
-
-
# Registers a new decompiler module.
-
# @return [TrueClass, FalseClass] Like Ruby's #require method, returns
-
# true if decompiler is now registered and returns false if the mod
-
# was previously registered.
-
# If there are problems registering the mod, an exception is raised.
-
# @raise [NoModule]
-
2
def register_decompiler(mod)
-
7
if mod.is_a?(String)
-
mod = eval(mod)
-
end
-
-
7
if registered_decompiler?(mod)
-
1
false
-
else
-
6
verify_decompiler_mod!(mod)
-
5
registered_decompilers << mod
-
5
true
-
end
-
end
-
-
# Verifies that the registered decompiler has the required methods
-
# available. Namely: #select_decompiler and #decompiled_pattern
-
2
def verify_decompiler_mod!(mod)
-
6
unless mod.respond_to?(:suitable_decompiler_for)
-
1
Origen.app!.fail(
-
exception_class: OrigenTesters::Decompiler::NoMethodError,
-
message: "No method #suitable_decompiler_for found on #{mod}. Cannot register as a decompiler."
-
)
-
end
-
5
true
-
end
-
-
# Queries if a decompiler is available for the given pattern.
-
2
def decompiler_for?(pattern = nil, options = {})
-
2
!select_decompiler(pattern, options).nil?
-
end
-
-
# Queries if the decompiler in mod has been registered.
-
2
def registered_decompiler?(mod)
-
7
if mod.is_a?(String)
-
mod = eval(mod)
-
end
-
-
7
registered_decompilers.include?(mod)
-
end
-
-
2
def execute(pattern, options = {})
-
4
decompile(pattern, options).execute(options)
-
end
-
-
2
def add_pins(pattern, options = {})
-
2
decompile(pattern, options).add_pins
-
end
-
-
2
def self.convert(pattern)
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Decompiler
-
2
module Nodes
-
2
class Node
-
2
attr_reader :context
-
2
attr_reader :type
-
-
2
def self.inherited(subclass)
-
24
if subclass.const_defined?(:PLATFORM_NODES)
-
subclass.const_get(:PLATFORM_NODES).each do |n|
-
subclass.define_instance_method(n) do
-
instance_variable_get(":@#{n}")
-
end
-
end
-
end
-
end
-
-
2
def initialize(context:, type:, **nodes)
-
48307
@context = context
-
48307
if type
-
48307
@type = type
-
elsif @type.nil?
-
type = self.class.underscore
-
end
-
-
48307
unless platform_nodes.empty?
-
26556
platform_nodes.each do |n|
-
50389
define_singleton_method(n) do
-
634
instance_variable_get("@#{n}".to_sym)
-
end
-
end
-
end
-
end
-
-
2
def execute?
-
206
@execute
-
end
-
-
2
def platform_nodes
-
76206
self.class.const_defined?(:PLATFORM_NODES) ? self.class.const_get(:PLATFORM_NODES) : []
-
end
-
end
-
-
2
class CommentBlock < OrigenTesters::Decompiler::Nodes::Node
-
2
attr_reader :comments
-
-
2
def initialize(comments:, context:)
-
9595
@comments = comments
-
9595
super(context: context, type: :comment_block)
-
end
-
-
2
def execute?
-
63
true
-
end
-
-
2
def execute!(context)
-
223
@comments.each { |c| cc(c) }
-
end
-
end
-
-
2
class Vector < OrigenTesters::Decompiler::Nodes::Node
-
2
attr_reader :repeat
-
2
attr_reader :timeset
-
2
attr_reader :pin_states
-
2
attr_reader :comment
-
-
# rubocop:disable Metrics/ParameterLists
-
2
def initialize(repeat:, timeset:, pin_states:, comment:, context:, **nodes)
-
34396
@execute = true
-
-
34396
@repeat = repeat
-
34396
@timeset = timeset
-
34396
@pin_states = pin_states
-
34396
@comment = comment
-
-
34396
super(context: context, type: :vector)
-
end
-
# rubocop:enable Metrics/ParameterLists
-
-
2
def execute!(context)
-
# Apply a timeset switch, if needed.
-
182
unless Origen.tester.timeset.name == timeset
-
2
Origen.tester.set_timeset(timeset)
-
end
-
-
# Apply the comment
-
182
unless comment.empty?
-
cc(comment)
-
end
-
-
# Apply the pin states
-
182
context.pinlist.each_with_index do |pin, i|
-
2150
dut.pins(pin).vector_formatted_value = pin_states[i]
-
end
-
-
# Cycle the tester
-
182
repeat.cycles
-
end
-
end
-
-
2
class Pinlist < OrigenTesters::Decompiler::Nodes::Node
-
2
attr_reader :pins
-
2
alias_method :pinlist, :pins
-
-
2
def initialize(pins:, context:)
-
# remove trailing formatting characters
-
175
pins = pins.map { |p| p.split(':').first }
-
26
@pins = pins.map(&:strip).map(&:to_sym)
-
26
super(context: context, type: :pinlist)
-
end
-
end
-
-
2
class Frontmatter < OrigenTesters::Decompiler::Nodes::Node
-
2
attr_reader :comments
-
2
attr_reader :pattern_header
-
-
2
alias_method :header, :pattern_header
-
2
alias_method :comment_header, :pattern_header
-
-
2
def initialize(pattern_header: nil, comments: nil, context:)
-
28
@pattern_header = pattern_header
-
28
@comments = comments || []
-
-
28
super(context: context, type: :frontmatter)
-
end
-
-
2
def execute!(context)
-
3
pattern_header.each do |c|
-
58
cc(c)
-
end
-
-
3
comments.each do |c|
-
cc(c)
-
end
-
end
-
-
2
def execute?
-
3
true
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Decompiler
-
2
require_relative './pattern/elements/base'
-
2
require_relative './pattern/elements/comment_block'
-
2
require_relative './pattern/elements/frontmatter'
-
2
require_relative './pattern/elements/pinlist'
-
2
require_relative './pattern/elements/vector_body_element'
-
2
require_relative './pattern/elements/vector'
-
2
require_relative './pattern/vector_delimiter_base'
-
2
require_relative './pattern/enumerable_ext'
-
2
require_relative './pattern/parsers'
-
2
require_relative './pattern/splitter'
-
2
require_relative './pattern/spec_helpers'
-
-
2
class ParseError < Origen::OrigenError
-
end
-
-
2
class SubclassError < Origen::OrigenError
-
end
-
-
2
class NoFirstVectorAvailable < Origen::OrigenError
-
end
-
-
2
class NoSuchSource < Origen::OrigenError
-
end
-
-
2
class NoSuitableDecompiler < Origen::OrigenError
-
end
-
-
2
class NoMethodError < Origen::OrigenError
-
end
-
-
2
class NoAvailableProcessor < Origen::OrigenError
-
end
-
-
2
class Pattern
-
2
class << self
-
2
attr_reader :splitter_config
-
2
attr_reader :parser_config
-
2
attr_reader :platform_tokens
-
2
attr_reader :platform
-
2
attr_reader :no_verify
-
end
-
-
2
attr_reader :source
-
2
attr_reader :decompiled
-
2
attr_reader :direct_source
-
-
2
include Splitter
-
2
include Parsers
-
2
include EnumerableExt
-
2
include SpecHelpers
-
-
2
def initialize(source, options = {})
-
57
options = { direct_source: false, no_verify: false }.merge(options)
-
57
direct_source = options[:direct_source]
-
57
no_verify = options[:no_verify]
-
-
57
if source.is_a?(File)
-
1
source = source.path
-
end
-
-
57
if direct_source
-
13
@source = source
-
13
@direct_source = true
-
else
-
44
@source = Pathname(source)
-
44
unless @source.exist?
-
1
message = "Cannot find pattern source '#{@source}'"
-
1
Origen.log.error(message)
-
1
Origen.app!.fail(exception_class: OrigenTesters::Decompiler::NoSuchSource, message: message)
-
end
-
43
@direct_source = false
-
end
-
56
@decompiled = false
-
-
56
unless no_verify || self.class.no_verify
-
54
verify_subclass_configuration
-
end
-
end
-
-
2
def platform
-
7
self.class.platform
-
end
-
2
alias_method :tester, :platform
-
-
2
def platform?(p = nil)
-
3
if p
-
3
platform == p
-
else
-
platform == tester.name.to_s
-
end
-
end
-
2
alias_method :tester?, :platform?
-
-
2
def decompiler
-
self.class
-
end
-
-
2
def decompiler?(d)
-
decompiler == d
-
end
-
-
2
def parser_config
-
2
self.class.parser_config || {}
-
end
-
-
2
def platform_tokens
-
1
self.class.platform_tokens
-
end
-
2
alias_method :decompiler_tokens, :platform_tokens
-
-
2
def comment_start
-
75731
self.class.platform_tokens[:comment_start]
-
end
-
2
alias_method :comment_token, :comment_start
-
-
2
def splitter_config
-
200
self.class.splitter_config
-
end
-
-
2
def method_parse_frontmatter
-
84
if self.class.respond_to?(:parse_frontmatter)
-
83
self.class.method(:parse_frontmatter)
-
end
-
end
-
-
2
def method_parse_pinlist
-
81
if self.class.respond_to?(:parse_pinlist)
-
80
self.class.method(:parse_pinlist)
-
end
-
end
-
-
2
def method_parse_vector
-
48307
if self.class.respond_to?(:parse_vector)
-
48306
self.class.method(:parse_vector)
-
end
-
end
-
-
2
def verify_subclass_configuration
-
54
if method_parse_frontmatter.nil?
-
1
subclass_error('Missing class method #parse_frontmatter')
-
53
elsif method_parse_pinlist.nil?
-
1
subclass_error('Missing class method #parse_pinlist')
-
52
elsif method_parse_vector.nil?
-
1
subclass_error('Missing class method #parse_vector')
-
51
elsif splitter_config.nil?
-
1
subclass_error('Missing class variable :splitter_config')
-
50
elsif !(Splitter::REQUIRED_KEYS - splitter_config.keys).empty?
-
3
subclass_error("Splitter config is missing required keys: #{(Splitter::REQUIRED_KEYS - splitter_config.keys).map { |k| ':' + k.to_s }.join(', ')}")
-
49
elsif !(splitter_config.keys - Splitter::REQUIRED_KEYS - Splitter::OPTIONAL_KEYS).empty?
-
subclass_error("Splitter config contains extra keys: #{(splitter_config.keys - Splitter::REQUIRED_KEYS - Splitter::OPTIONAL_KEYS).map { |k| ':' + k.to_s }.join(', ')}")
-
end
-
end
-
-
2
def subclass_error(message)
-
5
Origen.log.error("#{self.class.name} failed to subclasss OrigenTesters::DecompilerPattern: #{message}")
-
5
fail(SubclassError, "#{self.class.name} failed to subclasss OrigenTesters::DecompilerPattern: #{message}")
-
end
-
-
2
def decompiled?
-
545
@decompiled
-
end
-
-
2
def direct_source?
-
631
@direct_source
-
end
-
-
2
def first_vector
-
61
@first_vector || begin
-
16
each_vector do |v|
-
38
if v.vector?
-
12
@first_vector = v.element
-
12
break
-
end
-
end
-
15
if @first_vector.nil?
-
3
fail OrigenTesters::Decompiler::ParseError, "Could not locate the first vector in pattern #{@source}"
-
end
-
12
@first_vector
-
end
-
end
-
-
2
def first_timeset
-
6
first_vector.timeset
-
end
-
2
alias_method :initial_timeset, :first_timeset
-
-
2
def first_pin_states_mapped
-
5
pins.each.with_index.with_object({}) do |(pin, i), hash|
-
38
hash[pin] = initial_pin_states[i]
-
end
-
end
-
2
alias_method :initial_pin_states_mapped, :first_pin_states_mapped
-
-
2
def first_pin_states
-
43
first_vector.pin_states
-
end
-
2
alias_method :initial_pin_states, :first_pin_states
-
-
2
def pinlist_size
-
pinlist.pins.size
-
end
-
2
alias_method :num_pins, :pinlist_size
-
2
alias_method :number_of_pins, :pinlist_size
-
-
2
def pins
-
5
pinlist.pins
-
end
-
-
2
def decompile(options = {})
-
# Read the pattern and split it into sections then parse and store the
-
# frontmatter and pinlist models
-
40
split!
-
30
@frontmatter = _parse_frontmatter_
-
28
@pinlist = _parse_pinlist_
-
-
26
@decompiled = true
-
26
self
-
end
-
-
2
def frontmatter
-
33
@frontmatter
-
end
-
-
2
def pinlist
-
12324
@pinlist
-
end
-
-
2
def vectors
-
@vector_handler ||= vector_start
-
end
-
-
2
def current_vector_index
-
@current_vector_index
-
end
-
-
# Resolves the size of each pin in the pinlist using the initial pin states.
-
# @return [Hash] Hash wherein the keys are the pin names and each value is
-
# the corresponding size.
-
2
def pin_sizes
-
# initial_pin_states.map { |pin, state| state.size }
-
43
initial_pin_states_mapped.map { |pin, state| [pin, state.size] }.to_h
-
# pins.each.with_index.with_object({}) do |(pin, i), hash|
-
# hash[pin] = initial_pin_states[i].size
-
# end
-
end
-
-
2
def first_vector?
-
7
first_vector
-
rescue OrigenTesters::Decompiler::ParseError
-
1
return false
-
end
-
-
# Adds any pins in the decompiled pattern to the DUT which are not already present.
-
# @return [Array] Any pin names that were added to the DUT.
-
2
def add_pins
-
# pin_sizes = pat_model.pattern_model.pin_sizes
-
# pat_model.pinlist.each_with_index do |(name, pin), i|
-
# dut.add_pin(name, size: pin_sizes[i]) unless dut.has_pin?(name)
-
# end
-
6
retn = []
-
6
if first_vector?
-
5
pin_sizes.each do |pin, size|
-
38
unless dut.has_pin?(pin)
-
29
dut.add_pin(pin, size: size)
-
29
retn << pin
-
end
-
end
-
else
-
1
fail(NoFirstVectorAvailable, "No first vector available for pattern '#{source}'. Cannot add pins to the DUT '#{dut.class.name}'")
-
end
-
5
retn
-
end
-
-
# @note <code>line</code> is this context is delimited by the given separator.
-
# This may or may not be a true newline-delimited, line.
-
# def number_of_lines
-
# fail
-
# end
-
-
# Executing a pattern consist of:
-
# 1. Doing some initial setup (timesets, initial pin states, etc.)
-
# 2. Executing anything that can be executed in the frontmatter
-
# 3. Executing the vectors 1-by-1.
-
2
def execute(options = {})
-
3
if Origen.tester.timeset.nil?
-
1
if first_vector?
-
1
Origen.tester.set_timeset(first_timeset, 40)
-
else
-
Origen.log.error 'No first vector available and the timeset has not already been set!'
-
Origen.log.error 'Please set the timeset yourself prior to calling #execute! in a pattern that does not contain a first vector.'
-
fail(NoFirstVectorAvailable, "No first vector available for pattern '#{source}'. Cannot set a timeset to execute the pattern.")
-
end
-
end
-
3
frontmatter.execute!
-
3
each_vector_with_index do |vec, i|
-
269
if Origen.debug?
-
Origen.log.info("OrigenTesters: Executing Vector #{i}")
-
end
-
269
vec.execute!
-
end
-
-
3
self
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Decompiler
-
2
class Pattern
-
2
class Base
-
2
attr_reader :context
-
2
alias_method :decompiled_pattern, :context
-
-
2
attr_reader :node
-
2
alias_method :processor, :node
-
-
2
def initialize(node:, context:, **options)
-
92298
@context = context
-
92298
@node = node
-
end
-
-
2
def [](node)
-
node.find(node)
-
end
-
-
2
def platform_nodes
-
1343
node.platform_nodes
-
end
-
-
2
def method_missing(m, *args, &block)
-
1340
if platform_nodes.include?(m) || node.respond_to?(m)
-
1340
node.send(m)
-
else
-
super
-
end
-
end
-
-
2
def execute!
-
272
if node.execute?
-
248
node.execute!(self)
-
end
-
end
-
-
2
def pinlist
-
182
decompiled_pattern.pinlist.pinlist
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Decompiler
-
2
class Pattern
-
2
require_relative './base'
-
-
2
class CommentBlock < Base
-
2
def initialize(parent)
-
9595
super(node: parent, context: parent.context)
-
end
-
-
2
def comments
-
90
processor.comments
-
end
-
-
2
def to_yaml_hash(options = {})
-
{
-
class: self.class.to_s,
-
index: (node.respond_to?(:index) ? node.index : nil),
-
type: node.type,
-
processor: node.class.to_s,
-
comments: comments,
-
platform_nodes: _platform_nodes_
-
}
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Decompiler
-
2
class Pattern
-
2
require_relative './base'
-
-
2
class Frontmatter < Base
-
2
def initialize(node:, context:)
-
28
@source = :frontmatter
-
28
super
-
end
-
-
# Returns the topmost comment block.
-
# @return [Array] Array representing the topmost common, split by the <code> separator</code>.
-
# If there is no comment header, an empty array is returned.
-
2
def pattern_header
-
14
processor.pattern_header
-
end
-
-
# Returns all the comments, in the order they appear.
-
# @return [Array] Returns an array of comment blocks, where
-
# a comment block is an array of strings found in that block.
-
# The comment block can be recontructed into raw text by joining the
-
# array with the <code>separator</code>.
-
# If no comments were found, an empty array is returned.
-
# @note This will <u>NOT</u> include the <code>comment_header</code>.
-
2
def comments
-
6
processor.comments
-
end
-
-
2
def to_yaml_hash
-
{
-
class: self.class.to_s,
-
processor: processor.class.to_s,
-
pattern_header: pattern_header,
-
comments: comments,
-
platform_nodes: _platform_nodes_
-
}
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Decompiler
-
2
class Pattern
-
2
require_relative './base'
-
-
2
class Pinlist < Base
-
2
def initialize(node:, context:)
-
26
@source = :pinlist
-
26
super
-
end
-
-
# Returns the pinlist as an ordered list.
-
# @return [Array] Array of strings where each array element is the
-
# corresponding pin in that position.
-
# @example Return the pinlist.
-
# # (Teradyne ATP format) vector ($tset, tclk, tdi, tdo, tms)
-
# pinlist #=> ['tclk', 'tdi', 'tdo', 'tms']
-
2
def pinlist
-
182
processor.pins
-
end
-
-
2
def pins
-
15
processor.pins
-
end
-
-
# Returns the size of the pinlist.
-
# @return [Integer] Size of the pinlist.
-
2
def pinlist_size
-
12121
processor.pinlist.size
-
end
-
2
alias_method :size, :pinlist_size
-
-
2
def to_yaml_hash
-
{
-
class: self.class.to_s,
-
processor: processor.class.to_s,
-
pinlist: pinlist,
-
platform_nodes: _platform_nodes_
-
}
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Decompiler
-
2
class Pattern
-
2
require_relative './base'
-
-
# Represents a single Vector's AST.
-
2
class Vector < Base
-
2
alias_method :parent, :node
-
-
2
def initialize(parent, options = {})
-
34396
super(node: parent, context: parent.context)
-
end
-
-
2
def timeset
-
306
processor.timeset
-
end
-
-
2
def repeat
-
301
processor.repeat
-
end
-
-
2
def pin_states
-
343
processor.pin_states
-
end
-
-
2
def comment
-
300
processor.comment
-
end
-
-
2
def vector_index
-
parent.vector_index
-
end
-
-
2
def to_yaml_hash(options = {})
-
if parent.type == :vector
-
{
-
class: self.class.to_s,
-
vector_index: (parent.respond_to?(:vector_index) ? parent.vector_index : nil),
-
type: parent.type,
-
processor: processor.class.to_s,
-
timeset: timeset,
-
repeat: repeat,
-
pin_states: pin_states,
-
comment: comment,
-
platform_nodes: _platform_nodes_
-
}
-
else
-
{
-
class: self.class.to_s,
-
vector_index: (parent.respond_to?(:vector_index) ? parent.vector_index : nil),
-
type: parent.type,
-
processor: processor.class.to_s
-
}
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Decompiler
-
2
class Pattern
-
2
require_relative './base'
-
-
2
class VectorBodyElement < Base
-
# The known vector element types, supported regardless of the tester/platform.
-
2
BASE_ELEMENTS = [:vector, :comment_block]
-
-
2
attr_reader :type
-
2
attr_reader :element
-
2
attr_reader :vector_index
-
-
2
def initialize(node:, context:, **options)
-
48253
@source = :vector_body_element
-
48253
super(node: node, context: context)
-
48253
@type = node.type
-
48253
@vector_index = options[:vector_index]
-
-
# If the processor is a :vector or a comment_block, we can deal with
-
# this automatically. We also know that neither of these elemnts are
-
# platform specific.
-
48253
@element = (BASE_ELEMENTS.include?(type)) ? to_element : false
-
end
-
-
# Returns an element class (e.g., Vector) that casts itself to a known vector-element type.
-
# For example, if this element's processor is a 'vector', then it can cast itself to a Vector class,
-
# to expose functionality (e.g., #timeset) on the class itself. Otherwise, the functionality will remain
-
# on the processor and its up to the user to know what the processor has.
-
# @note Calling this not required, as this is just an interface to a known processor type.
-
2
def to_element
-
43991
if type == :comment_block
-
9595
CommentBlock.new(self)
-
34396
elsif type == :vector
-
34396
Vector.new(self)
-
else
-
fail "Could not cast platform-specific vector body element type :#{type} to a standalone class!"
-
end
-
end
-
-
2
def to_yaml_hash(options = {})
-
{
-
class: self.class.to_s,
-
vector_index: vector_index
-
}.merge(
-
begin
-
if element
-
element.to_yaml_hash(options)
-
else
-
# If this element couldn't be matched, provide a simple yaml hash
-
# including some basic elements.
-
{
-
type: type,
-
processor: processor.class.to_s,
-
platform_nodes: _platform_nodes_
-
}
-
end
-
end
-
)
-
end
-
-
2
def is_a_vector?
-
131
type == :vector
-
end
-
2
alias_method :is_vector?, :is_a_vector?
-
2
alias_method :vector?, :is_a_vector?
-
-
2
def platform
-
3
decompiled_pattern.platform
-
end
-
2
alias_method :tester, :platform
-
-
2
def platform?(p = nil)
-
3
decompiled_pattern.platform?(p)
-
end
-
2
alias_method :tester?, :platform?
-
-
2
def decompiler
-
decompiled_pattern.platform
-
end
-
-
2
def decompiler?(d = nil)
-
decompiled_pattern.decompiler?(d)
-
end
-
-
2
def is_a_comment?
-
4
type == :comment || type == :comment_block
-
end
-
2
alias_method :is_comment?, :is_a_comment?
-
-
2
def is_tester_specific?
-
3
platform_nodes.include?(type)
-
end
-
2
alias_method :is_tester_specific_element?, :is_tester_specific?
-
2
alias_method :is_platform_specific?, :is_tester_specific?
-
2
alias_method :is_platform_specific_element?, :is_tester_specific?
-
2
alias_method :is_decompiler_specific?, :is_tester_specific?
-
2
alias_method :is_decompiler_specific_element?, :is_tester_specific?
-
2
alias_method :is_a_tester_specific_element?, :is_tester_specific?
-
2
alias_method :is_a_platform_specific_element?, :is_tester_specific?
-
2
alias_method :is_a_decompiler_specific_element?, :is_tester_specific?
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Decompiler
-
2
class Pattern
-
# We can't use Ruby's enumerable mix-in directly, as our each method
-
# isn't a true implementation, as the mix-in expects.
-
# Instead, we'll provide our own enumerable methods as needed that use
-
# our own each method.
-
2
module EnumerableExt
-
# Iterate through the vectors one by one.
-
# We'll begin reading the file from the vector start until the regex/block
-
# vector_delimiter is met.
-
# This delimiter can include multiple lines.
-
# Once the delimiter finishes, those lines will be sent to the treetop
-
# parser for conversion to an AST.
-
# Lastly, the next vector will start where the previous one left off.
-
2
def each(**options, &block)
-
536
unless decompiled?
-
1
Origen.app!.fail(message: 'Pattern has not yet been decompiled! Cannot iterate through vectors or query pattern aspects!')
-
end
-
535
vectors_started = false
-
535
delimiter_klass = VectorDelimiterBase
-
535
v = delimiter_klass.new(self)
-
535
vector_index = 0
-
-
535
if direct_source?
-
1
kickoff = 'source.split("\n")'
-
else
-
534
kickoff = 'File.foreach(source)'
-
end
-
-
535
eval(kickoff).each_with_index do |line, index|
-
# Get to the point in the file where the vectors begin
-
81039
if index > section_indices[:vectors_end] && section_indices[:vectors_end] != -1
-
13
break
-
81026
elsif index < section_indices[:vectors_start]
-
14800
next
-
end
-
-
66226
v.shift(line)
-
66226
if v.delimited?
-
# index starts at 0, but most file editors start the line numbers at 1.
-
38751
yield(_parse_vector_(v.current_vector!, vector_index: vector_index, line: index + 1))
-
38367
vector_index += 1
-
-
38367
if v.include_last_line?
-
# The last line is included in the current vector.
-
28863
v = delimiter_klass.new(self)
-
else
-
# The last line shouldn't be included in this vector.
-
# Shift it into a new one.
-
9504
v = delimiter_klass.new(self)
-
9504
v.shift(line)
-
-
# Check if this new vector is delimited before grabbing
-
# the next line.
-
9504
if v.delimited?
-
9504
yield(_parse_vector_(v.current_vector!, vector_index: vector_index))
-
9371
v = delimiter_klass.new(self)
-
9371
vector_index += 1
-
end
-
end
-
end
-
end
-
end
-
2
alias_method :each_vector, :each
-
-
2
def each_vector_with_index(&block)
-
502
i = 0
-
502
each_vector do |v|
-
47663
yield(v, i)
-
47164
i += 1
-
end
-
end
-
-
2
def vector_at(index, &block)
-
498
each_vector_with_index do |v, i|
-
47389
if i == index
-
498
return v
-
end
-
end
-
nil
-
end
-
-
2
def collect(&block)
-
2
vectors = []
-
2
each_vector do |v|
-
19
if block_given?
-
vectors << yield(v)
-
else
-
19
vectors << v
-
end
-
end
-
vectors
-
end
-
2
alias_method :collect_vectors, :collect
-
2
alias_method :map, :collect
-
2
alias_method :map_vectors, :collect
-
-
2
def collect_with_index(&block)
-
vectors = []
-
each_vector_with_index do |v, i|
-
if block_given?
-
vectors << yield(v, i)
-
else
-
vectors << v
-
end
-
end
-
vectors
-
end
-
2
alias_method :collect_vectors_with_index, :collect_with_index
-
-
2
def find_all(&block)
-
2
vectors = []
-
2
if block_given?
-
30
each_vector { |v| vectors << v if yield(v) }
-
end
-
2
vectors
-
end
-
2
alias_method :select, :find_all
-
2
alias_method :filter, :find_all
-
-
2
def find(&block)
-
4
if block_given?
-
38
each_vector { |v| return v if yield(v) }
-
end
-
end
-
2
alias_method :detect, :find
-
-
2
def find_index(&block)
-
2
find(&block).vector_index
-
end
-
-
2
def count(&block)
-
8
cnt = 0
-
8
if block_given?
-
15
each_vector { |v| cnt += 1 if yield(v) }
-
else
-
449
each_vector { |v| cnt += 1 }
-
end
-
8
cnt
-
end
-
2
alias_method :size, :count
-
-
2
def reject(&block)
-
1
vectors = []
-
1
if block_given?
-
15
each_vector { |v| vectors << v unless yield(v) }
-
end
-
1
vectors
-
end
-
-
2
def first(n = nil)
-
4
if n
-
3
if n <= 0
-
2
return nil
-
end
-
-
1
vectors = []
-
1
each_vector_with_index do |v, i|
-
5
vectors << v
-
5
if n == (i - 1)
-
1
return vectors
-
end
-
end
-
vectors
-
else
-
2
each_vector { |v| return v }
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Decompiler
-
2
class Pattern
-
2
module Parsers
-
# @abstract This requires the child to supply:
-
# A method #parse_frontmatter(raw_frontmatter) which returns
-
# a node with the frontmatter parsed.
-
2
def _parse_frontmatter_
-
begin
-
30
n = method_parse_frontmatter.call(raw_frontmatter: raw_frontmatter, context: self)
-
rescue ParseError => e
-
# If parsing threw a ParseError, the platform found the error.
-
# Raise this as normal.
-
raise(e)
-
rescue Exception => e
-
# Anything else, raise a parse error and provide the error raised
-
# by parsing.
-
2
m = "Error encountered while parsing the frontmatter: #{e.class}"
-
2
Origen.log.error(m)
-
2
Origen.log.error(e.message)
-
2
Origen.log.error(e.backtrace.join("\n\t"))
-
2
Origen.app!.fail(exception_class: ParseError, message: m)
-
end
-
-
# Seperate this out so that errors creating the frontmatter class
-
# aren't confused with parsing errors.
-
28
@frontmatter = Frontmatter.new(node: n, context: self)
-
end
-
-
# @abstract This requires the child to supply:
-
# A method #parse_pinlist(raw_pinlist) which returns a node with
-
# the pinlist parsed.
-
#
-
# The node should have a #pins method, which returns an array of
-
# the pin names (as Strings).
-
# Example:
-
# parse_pinlist('vector ($tset, tclk, tdi, tdo, tms)')
-
# #=> ['tclk', 'tdi', 'tdo', 'tms']
-
2
def _parse_pinlist_
-
begin
-
28
n = method_parse_pinlist.call(raw_pinlist: raw_pinlist, context: self)
-
rescue ParseError => e
-
# If parsing threw a ParseError, the platform found the error.
-
# Raise this as normal.
-
raise(e)
-
rescue Exception => e
-
# Anything else, raise a parse error and provide the error raised by parsing.
-
2
m = "Error encountered while parsing the pinlist: #{e.class}"
-
2
Origen.log.error(m)
-
2
Origen.log.error(e.message)
-
2
Origen.log.error(e.backtrace.join("\n\t"))
-
2
Origen.app!.fail(exception_class: ParseError, message: m)
-
end
-
-
# Seperate this out so that errors creating the pinlist class
-
# aren't confused with parsing errors.
-
26
@pinlist = Pinlist.new(node: n, context: self)
-
end
-
-
# This will parse vectors line-by-line, so multi-line vectors will
-
# need to take this into account.
-
# @abstract This requires the child to supply:
-
# A method #parse_vector(raw_vector) which returns a node with
-
# the vector parsed.
-
#
-
# This node should have the following:
-
# - type
-
# - platform_nodes
-
#
-
# In the even the type is vector, it should also have:
-
# - timeset
-
# - This should return the timeset of the vector as a String.
-
# - pin states
-
# - This should return an array of strings, where each string
-
# corresponds to the pin state of a pin indicated by its offset
-
# into the pin header array.
-
# - comment
-
# The comment in this line. This can be either String,
-
# an Array of Strings (for multiline comments, if supported), or
-
# nil, if there is no comment.
-
# - comment
-
# A true/false value that indicates if this entire line is a comment.
-
# If true, operations, timeset, pin states, can be nil.
-
# If the type is something else (platform specifc, such as a 'starb label',for the J750),
-
# all contents can be in the 'platform_nodes'.
-
2
def _parse_vector_(raw_vector, options = {})
-
begin
-
48255
v = method_parse_vector.call(raw_vector: raw_vector, context: self, meta: (@vector_meta ||= {}))
-
rescue ParseError => e
-
# If parsing threw a ParseError, the platform found the error.
-
# Raise this as normal.
-
raise(e)
-
rescue Exception => e
-
# Anything else, raise a parse error and provide the error raised by parsing.
-
2
m = "Error encountered while parsing the vector at index #{options[:vector_index]}: #{e.class}"
-
2
Origen.log.error(m)
-
2
Origen.log.error('While parsing:')
-
2
Origen.log.error(" #{raw_vector}")
-
2
Origen.log.error(e.message)
-
2
Origen.log.error(e.backtrace.join("\n\t"))
-
2
Origen.app!.fail(exception_class: ParseError, message: m)
-
end
-
-
# Seperate this out so that errors creating the vector body element class
-
# aren't confused with parsing errors.
-
48253
@current_vector = VectorBodyElement.new(node: v, context: self, **options)
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Decompiler
-
2
class Pattern
-
2
module SpecHelpers
-
2
def to_yaml_hash(options = {})
-
{
-
pattern: @path,
-
timestamp: Time.now.to_s,
-
class: self.class.to_s,
-
# ... Add in the variables here
-
-
frontmatter: frontmatter.to_yaml_hash,
-
pinlist: pinlist.to_yaml_hash,
-
vectors: collect_vectors { |v, i| v.to_yaml_hash }
-
}
-
end
-
-
2
def to_spec_yaml(options = {})
-
to_yaml_hash.to_yaml
-
end
-
-
2
def spec_yaml_output
-
"#{Origen.app!.root}/output/#{platform}/decompiler/models/#{source.basename}.yaml"
-
end
-
-
2
def spec_yaml_approved
-
"#{Origen.app!.root}/approved/#{platform}/decompiler/models/#{source.basename}.yaml"
-
end
-
-
2
def write_spec_yaml(options = {})
-
path = options[:approved] ? spec_yaml_approved : spec_yaml_output
-
unless Dir.exist?(File.dirname(path))
-
FileUtils.mkdir_p(File.dirname(path))
-
end
-
File.open(path, 'w').puts(to_spec_yaml(options))
-
path
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Decompiler
-
2
class Pattern
-
2
module Splitter
-
2
REQUIRED_KEYS = [:pinlist_start, :vectors_start, :vectors_end]
-
2
OPTIONAL_KEYS = [:separator, :vectors_include_start_line, :vectors_include_end_line]
-
-
2
def section_indices
-
188260
@section_indices
-
end
-
-
2
def raw_lines(start, stop, &block)
-
58
retn_lines = []
-
58
_run_line_ = lambda do |line, index, retn_lines, &block|
-
5131
if index > stop
-
3914
break
-
1217
elsif index >= start
-
646
if block_given?
-
yield
-
else
-
646
retn_lines << line
-
end
-
end
-
end
-
-
58
if direct_source?
-
24
source.split("\n").map { |l| "#{l}\n" }.each_with_index do |line, index|
-
22
_run_line_.call(line, index, retn_lines, &block)
-
end
-
else
-
56
File.foreach(source).each_with_index do |line, index|
-
5109
_run_line_.call(line, index, retn_lines, &block)
-
end
-
end
-
58
retn_lines
-
end
-
-
2
def raw_frontmatter
-
30
raw_lines(section_indices[:frontmatter_start], section_indices[:frontmatter_end])
-
end
-
-
2
def raw_pinlist
-
28
raw_lines(section_indices[:pinlist_start], section_indices[:pinlist_end])
-
end
-
-
2
def raw_vectors(&block)
-
raw_lines(section_indices[:vectors_start], section_indices[:vectors_end])
-
end
-
-
2
def raw_endmatter
-
raw_lines(section_indices[:endmatter_start], section_indices[:endmatter_end])
-
end
-
-
2
def split!
-
40
section_indices = split(**splitter_config)
-
-
# Check that we found each section in the pattern.
-
38
if section_indices[:pinlist_start].nil?
-
6
Origen.log.error('Parsing Error!')
-
6
Origen.log.error("Could not locate the pinlist start in pattern #{source}")
-
6
Origen.log.error("Expected a pattern line to match '#{splitter_config[:pinlist_start]}'")
-
-
6
fail OrigenTesters::Decompiler::ParseError, "Parsing Error! Could not locate the pinlist start in pattern #{source}"
-
32
elsif section_indices[:vectors_start].nil?
-
2
Origen.log.error('Parsing Error!')
-
2
Origen.log.error("Could not locate the vector start in pattern #{source}")
-
2
Origen.log.error("Expected a pattern line to match '#{splitter_config[:vector_start]}'")
-
-
2
fail OrigenTesters::Decompiler::ParseError, "Parsing Error! Could not locate the vector body in pattern #{source}"
-
30
elsif section_indices[:vectors_end].nil?
-
Origen.log.error('Parsing Error!')
-
Origen.log.error("Could not locate the vector body end in pattern #{source}")
-
Origen.log.error("Expected a pattern line to match '#{splitter_config[:vector_end]}'")
-
-
fail OrigenTesters::Decompiler::ParseError, "Parsing Error! Could not locate the vector body end in pattern #{source}"
-
end
-
-
30
@section_indices = section_indices
-
30
@section_indices
-
end
-
-
# Splits the pattern into gour secionts using regexes:
-
# 1. Frontmatter
-
# 2. Pin List
-
# 3. Vectors
-
# 4. Endmatter
-
# The idea is that each section can be delimited by a line that matches some
-
# regex (and is not considered a comment line).
-
# The pattern will be read line-by-line, looking for the regexes.
-
# We're defining the pattern section as such:
-
# - Frontmatter starts at the beginning of the pattern and ends at the start of the pattern header.
-
# - Vectors start from the end of the pattern header and go until the end of the vectors.
-
# - Endmatter starts at the end of the vectors and ends at the end of the file.
-
# - Its possible (and fine) for endmatter to be non-existant, or even not allowed.
-
# - In the latter case, the endvector symbol should the EoF symbol.
-
# @return (Hash)
-
# rubocop:disable Metrics/ParameterLists
-
2
def split(pinlist_start:, vectors_start:, vectors_end:, vectors_include_start_line: false, vectors_include_end_line: false, &block)
-
40
def check_match(matcher, line, index, indices)
-
2553
if matcher.respond_to?(:call)
-
10
matcher.call(line: line, index: index, current_indices: indices)
-
2543
elsif matcher.is_a?(Regexp)
-
2543
line =~ matcher
-
elsif matcher.is_a?(String)
-
line.start_with?(matcher)
-
else
-
fail "Splitter does not know how to match given matcher of class #{matcher.class}"
-
end
-
end
-
-
40
if File.zero?(source)
-
2
Origen.log.error('Parsing Error!')
-
2
Origen.log.error("Pattern #{source} has size zero!")
-
2
Origen.log.error('Decompiling empty files is not supported.')
-
-
2
fail(OrigenTesters::Decompiler::ParseError, "Empty or non-readable pattern file #{source}")
-
end
-
-
indices = {
-
38
frontmatter_start: 0,
-
endmatter_end: -1
-
}
-
38
if block_given?
-
fail 'Blocks are not yet supported!'
-
else
-
38
if vectors_end == -1
-
16
indices[:vectors_end] = -1
-
16
indices[:endmatter_start] = -1
-
end
-
38
_split_ = lambda do |line, index, indices|
-
2892
if !indices[:pinlist_start]
-
929
if check_match(pinlist_start, line, index, indices)
-
32
indices[:frontmatter_end] = index - 1
-
32
indices[:pinlist_start] = index
-
end
-
1963
elsif !indices[:vectors_start]
-
31
if check_match(vectors_start, line, index, indices)
-
30
indices[:pinlist_end] = index - 1
-
30
vectors_include_start_line ? indices[:vectors_start] = index : indices[:vectors_start] = index + 1
-
end
-
1932
elsif !indices[:vectors_end]
-
1593
if check_match(vectors_end, line, index, indices)
-
20
vectors_include_end_line ? indices[:vectors_end] = index : indices[:vectors_end] = index - 1
-
20
indices[:endmatter_start] = index
-
end
-
end
-
end
-
-
38
if direct_source?
-
2
source.split("\n").each_with_index do |line, index|
-
22
_split_.call(line, index, indices)
-
end
-
else
-
36
File.foreach(source).each_with_index do |line, index|
-
2870
_split_.call(line, index, indices)
-
end
-
end
-
-
38
indices
-
end
-
# rubocop:enable Metrics/ParameterLists
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Decompiler
-
2
class Pattern
-
2
class VectorDelimiterBase
-
2
attr_reader :current_vector
-
2
attr_reader :parent
-
-
2
def initialize(parent)
-
48273
@current_vector = []
-
48273
@delimited = false
-
48273
@in_comment_block = false
-
-
48273
@parent = parent
-
end
-
-
2
def comment_start
-
75730
parent.comment_start
-
end
-
-
2
def in_comment_block?
-
@in_comment_block
-
end
-
-
2
def shift(line)
-
75730
if @in_comment_block
-
27474
if !line.strip.start_with?(comment_start)
-
# End of the comment block.
-
# Signal that this vector is over, but don't include the
-
# newly shifted line.
-
9595
@delimited = true
-
9595
@include_last_line = false
-
else
-
17879
@current_vector << line
-
end
-
else
-
48256
if current_vector.empty? && line.strip.start_with?(comment_start)
-
# Currently in an empty vector and encountered a comment.
-
# Start a new comment block.
-
9596
@in_comment_block = true
-
9596
@current_vector << line
-
38660
elsif !current_vector.empty? && line.strip.start_with?(comment_start)
-
# Not in an empty vector, but not in a comment block.
-
# Signal the end of this vector and start a new one with
-
# this vector.
-
@delimited = true
-
@include_last_line = false
-
else
-
# Standard single vector
-
38660
@delimited = true
-
38660
@include_last_line = true
-
38660
@current_vector << line
-
end
-
end
-
end
-
-
2
def current_vector!
-
48255
current_vector.join('')
-
end
-
-
2
def delimited?
-
75730
@delimited
-
end
-
-
2
def include_last_line?
-
38367
@include_last_line
-
end
-
end
-
end
-
end
-
end
-
2
require 'digest/md5'
-
2
module OrigenTesters
-
# Provides a common API to add tests to a flow that is supported by all testers.
-
#
-
# This builds up a flow model using the Abstract Test Program (ATP) gem, which
-
# now deals with implementing the flow control API.
-
#
-
# Individual tester drivers in this plugin are then responsible at the end to
-
# render the abstract flow to their specific format and conventions.
-
2
module Flow
-
2
include OrigenTesters::Generator
-
-
# The ATP::FlowAPI provides a render method, but let's grab a handle to the original
-
# render method from OrigenTesters, we will use this to extend the ATP render method with
-
# the ability to pass in a path to a file containing the content to be rendered into the
-
# flow
-
2
alias_method :orig_render, :render
-
-
2
include ATP::FlowAPI
-
-
2
PROGRAM_MODELS_DIR = "#{Origen.root}/tmp/program_models"
-
-
2
def self.callstack
-
5474
@callstack ||= []
-
end
-
-
2
def self.comment_stack
-
558
@comment_stack ||= []
-
end
-
-
2
def self.name_stack
-
412
@name_stack ||= []
-
end
-
-
2
def self.flow_comments
-
487
@flow_comments
-
end
-
-
2
def self.flow_comments=(val)
-
314
@flow_comments = val
-
end
-
-
2
def self.unique_ids
-
@unique_ids
-
end
-
-
2
def self.unique_ids=(val)
-
157
@unique_ids = val
-
end
-
-
# Returns true if this is a top-level Origen test program flow
-
2
def top_level?
-
392
top_level == self
-
end
-
-
# Returns the flow's parent top-level flow object, or self if this is a top-level flow
-
2
def top_level
-
392
@top_level
-
end
-
-
# Returns the flow's immediate parent flow object, or nil if this is a top-level flow
-
2
def parent
-
1055
@parent
-
end
-
-
# Returns a hash containing all child flows stored by their ID
-
2
def children
-
292
@children ||= {}.with_indifferent_access
-
end
-
-
# Returns the flow's ID prefixed with the IDs of its parent flows, joined by '.'
-
2
def path
-
372
@path ||= begin
-
159
ids = []
-
159
p = parent
-
159
while p
-
86
ids.unshift(p.id)
-
86
p = p.parent
-
end
-
159
ids << id
-
159
ids.map(&:to_s).join('.')
-
end
-
end
-
-
2
def lines
-
1965
@lines
-
end
-
-
2
def test(obj, options = {})
-
2773
@_last_parameters_ = options.dup # Save for the interface's if_parameter_changed method
-
2773
obj.extract_atp_attributes(options) if obj.respond_to?(:extract_atp_attributes)
-
2773
super(obj, options)
-
end
-
-
# @api private
-
2
def self.ht_comments
-
5473
unless @ht_comments.is_a? Hash
-
@ht_comments = {}
-
end
-
5473
@ht_comments
-
end
-
-
# @api private
-
2
def self.ht_comments=(val)
-
279
unless @ht_comments.is_a? Hash
-
2
@ht_comments = {}
-
end
-
279
@ht_comments = val
-
end
-
-
# @api private
-
2
def self.cc_comments
-
4495
unless @cc_comments.is_a? Hash
-
2
@cc_comments = {}
-
end
-
4495
@cc_comments
-
end
-
-
# @api private
-
2
def self.cc_comments=(val)
-
unless @cc_comments.is_a? Hash
-
@cc_comments = {}
-
end
-
@cc_comments = val
-
end
-
-
# Returns the abstract test program model, this is shared by all
-
# flow created together in a generation run
-
2
def program
-
172
@@program ||= ATP::Program.new
-
end
-
-
2
def save_program
-
13
FileUtils.mkdir_p(PROGRAM_MODELS_DIR) unless File.exist?(PROGRAM_MODELS_DIR)
-
13
program.save("#{PROGRAM_MODELS_DIR}/#{Origen.target.name}")
-
end
-
-
2
def model
-
4727
if Origen.interface.resources_mode?
-
59
@throwaway ||= ATP::Flow.new(self)
-
else
-
4668
@model ||= begin
-
159
f = program.flow(try(:path) || id, description: OrigenTesters::Flow.flow_comments)
-
159
@sig = flow_sig(try(:path) || id)
-
# f.id = @sig if OrigenTesters::Flow.unique_ids
-
159
f
-
end
-
end
-
end
-
2
alias_method :atp, :model
-
-
2
def render(file, options = {})
-
16
add_meta!(options)
-
begin
-
16
text = orig_render(file, options)
-
rescue
-
14
text = file
-
end
-
16
atp.render(text, options)
-
end
-
-
2
def nop(options = {})
-
end
-
-
# @api private
-
# This fires between target loads (unless overridden by the ATE specific flow class)
-
2
def at_run_start
-
39
@@program = nil
-
end
-
-
# @api private
-
# This fires between flows (unless overridden by the ATE specific flow class)
-
2
def at_flow_start
-
97
@labels = {}
-
end
-
-
# @api private
-
2
def is_the_flow?
-
16
true
-
end
-
-
# Returns true if the test context generated from the supplied options + existing condition
-
# wrappers is different from that which was applied to the previous test.
-
2
def context_changed?(options)
-
10
model.context_changed?(options)
-
end
-
-
2
def generate_unique_label(name = nil)
-
61
name = 'label' if !name || name == ''
-
61
name.gsub!(' ', '_')
-
61
name.upcase!
-
61
@labels ||= {}
-
61
@labels[name] ||= 0
-
61
@labels[name] += 1
-
61
"#{name}_#{@labels[name]}_#{sig}"
-
end
-
-
# Returns a unique signature that has been generated for the current flow, this can be appended
-
# to named references to avoid naming collisions with any other flow
-
2
def sig
-
1808
@sig
-
end
-
2
alias_method :signature, :sig
-
-
2
def active_description
-
6
flow_file = OrigenTesters::Flow.callstack.last
-
30
called_from = caller.find { |l| l =~ /^#{flow_file}:.*/ }
-
# Windows fix - prevent the drive letter in the file name from changing the index of the line_no below
-
6
called_from.gsub!(flow_file, '')
-
6
desc = nil
-
6
if called_from
-
6
called_from = called_from.split(':')
-
6
line_no = called_from[1].to_i
-
6
ht_coms = OrigenTesters::Flow.ht_comments
-
6
cc_coms = OrigenTesters::Flow.cc_comments
-
6
if line_no
-
6
if ht_coms[line_no]
-
3
desc = ht_coms[line_no].join(' ')
-
end
-
6
if cc_coms[line_no] && cc_coms[line_no].first
-
3
desc = [cc_coms[line_no].shift].join(' ')
-
end
-
end
-
end
-
6
desc
-
end
-
-
2
private
-
-
# Make a unique signature for the flow based on the flow name and the name of
-
# the plugin/app that owns it
-
2
def flow_sig(id)
-
159
s = Digest::MD5.new
-
# These guarantee uniqueness within a plugin/app
-
159
s << id.to_s
-
159
s << filename
-
# This will add the required plugin uniqueness in the case of a top-level app
-
# that has multiple plugins that can generate test program snippets
-
159
if file = OrigenTesters::Flow.callstack.first
-
155
s << get_app(file).name.to_s
-
end
-
159
s.to_s[0..6].upcase
-
end
-
-
2
def get_app(file)
-
155
path = Pathname.new(file).dirname
-
155
until File.exist?(File.join(path, 'config/application.rb')) || path.root?
-
155
path = path.parent
-
end
-
155
if path.root?
-
fail 'Something went wrong resoving the app root in OrigenTesters'
-
end
-
155
Origen.find_app_by_root(path)
-
end
-
-
# This gets called by ATP for all flow generation methods to add the source file information
-
# to the generated node
-
2
def add_meta!(options)
-
4472
flow_file = OrigenTesters::Flow.callstack.last
-
32045
called_from = caller.find { |l| l =~ /^#{flow_file}:.*/ }
-
4472
if called_from
-
# Splitting on ':' when file names are included will yield a different index for everything in Windows
-
4416
called_from.gsub!(flow_file, '')
-
4416
called_from = called_from.split(':')
-
4416
options[:source_file] = flow_file # called_from[0]
-
4416
options[:source_line_number] = called_from[1].to_i
-
end
-
end
-
-
# This gets called by ATP for all flow generation methods to add the description information
-
# to the generated node
-
2
def add_description!(options)
-
# Can be useful if an app generates additional tests on the fly for a single test in the flow,
-
# e.g. a POR, in that case they will not want the description to be attached to the POR, but to
-
# the test that follows it
-
4456
unless options[:inhibit_description_consumption]
-
4456
ht_coms = OrigenTesters::Flow.ht_comments
-
4456
cc_coms = OrigenTesters::Flow.cc_comments
-
4456
line_no = options[:source_line_number]
-
# options[:then] only present on the second iteration of the same test same loop (not sure what this is really)
-
# This method is called twice per test method in a loop but the second call should not consume a comment
-
4456
if line_no && !options[:then]
-
4388
if ht_coms[line_no]
-
59
options[:description] ||= ht_coms[line_no]
-
end
-
4388
if cc_coms[line_no] && cc_coms[line_no].first
-
30
options[:description] ||= [cc_coms[line_no].shift]
-
end
-
end
-
end
-
end
-
end
-
end
-
2
require 'active_support/concern'
-
2
require 'erb'
-
2
require 'yaml'
-
-
2
module OrigenTesters
-
# This module should be included in all test program component generators and provides the required
-
# integration with the Flow.create and Resources.create methods
-
2
module Generator
-
2
autoload :Placeholder, 'origen_testers/generator/placeholder'
-
2
autoload :IdentityMap, 'origen_testers/generator/identity_map'
-
-
2
extend ActiveSupport::Concern
-
-
2
included do
-
44
include Origen::Generator::Comparator
-
-
44
attr_accessor :output_directory
-
end
-
-
2
def self.execute_source(file)
-
193
load file
-
end
-
-
# @api private
-
2
def self.original_reference_file=(val)
-
@original_reference_file = val
-
end
-
-
# @api private
-
2
def self.original_reference_file
-
192
!!@original_reference_file
-
end
-
-
# When called on a generator no output files will be created from it
-
2
def inhibit_output
-
3
@inhibit_output = true
-
end
-
-
# Returns true if the output files from this generator will be inhibited
-
2
def output_inhibited?
-
387
@inhibit_output
-
end
-
-
# Expands and inserts all render statements that have been encountered
-
2
def close(options = {})
-
2776
Origen.profile "closing #{filename}" do
-
2776
base_collection = collection
-
2776
base_collection.each_with_index do |item, i|
-
20362
if item.is_a? Placeholder
-
2
if item.type == :render
-
2
txt = ''
-
2
Origen.file_handler.preserve_current_file do
-
2
Origen.file_handler.default_extension = file_extension
-
2
placeholder = compiler.render(item.file, item.options)
-
2
txt = compiler.insert(placeholder).chomp
-
end
-
2
base_collection[i] = txt
-
else
-
fail 'Unknown placeholder encountered!'
-
end
-
end
-
end
-
2776
@collection = base_collection.flatten.compact
-
2776
on_close(options)
-
end
-
end
-
-
2
def file_pipeline
-
476
@@file_pipeline ||= []
-
end
-
-
# Returns the directory of the current source file being generated
-
2
def current_dir
-
133
if file_pipeline.empty?
-
56
Origen.file_handler.base_directory
-
else
-
77
Pathname.new(file_pipeline.last).dirname
-
end
-
end
-
-
# Redefine this in the parent which includes this module if you want anything to
-
# occur after closing the generator (expanding all render/import statements) but
-
# before writing to a file.
-
2
def on_close(options = {})
-
end
-
-
# Redefine this in the parent which includes this module if you want anything to
-
# occur after all tests have been generated but before file writing starts.
-
2
def finalize(options = {})
-
end
-
-
2
def compiler
-
200
Origen.generator.compiler
-
end
-
-
2
def filename=(name)
-
265
@filename = name
-
end
-
-
2
def name
-
347
@filename.to_sym
-
end
-
2
alias_method :id, :name
-
-
2
def filename(options = {})
-
options = {
-
4756
include_extension: true
-
}.merge(options)
-
# Allow generators to override this and fully define the filename if they want
-
4756
return fully_formatted_filename if try(:fully_formatted_filename)
-
4564
name = (@filename || Origen.file_handler.current_file.basename('.rb')).to_s
-
4564
name[0] = '' if name[0] == '_'
-
4564
if Origen.config.program_prefix
-
unless name =~ /^#{Origen.config.program_prefix}/i
-
name = "#{Origen.config.program_prefix}_#{name}"
-
end
-
end
-
4564
f = Pathname.new(name).basename
-
4564
ext = f.extname.empty? ? file_extension : f.extname
-
4564
body = f.basename(".#{ext}").to_s
-
4564
body.gsub!('_resources', '')
-
4564
if defined? self.class::OUTPUT_PREFIX
-
# Unless the prefix is already in the name
-
67
unless body =~ /#{self.class::OUTPUT_PREFIX}$/i
-
39
body = "#{self.class::OUTPUT_PREFIX}_#{body}"
-
end
-
end
-
4564
if defined? self.class::OUTPUT_POSTFIX
-
# Unless the postfix is already in the name
-
1140
unless body =~ /#{self.class::OUTPUT_POSTFIX}$/i
-
1126
body = "#{body}_#{self.class::OUTPUT_POSTFIX}"
-
end
-
end
-
4564
ext = ".#{ext}" unless ext =~ /^\./
-
4564
if options[:include_extension]
-
4564
"#{body}#{ext}"
-
else
-
"#{body}"
-
end
-
end
-
-
2
def dont_diff=(val)
-
@dont_diff = val
-
end
-
-
# All generators must implement a collection method that returns an
-
# array containing the generated items
-
2
def collection
-
4946
@collection ||= []
-
end
-
-
2
def collection=(array)
-
28
@collection = array
-
end
-
-
2
def file_extension
-
4582
if defined? self.class::OUTPUT_EXTENSION
-
self.class::OUTPUT_EXTENSION
-
4582
elsif defined? self.class::TEMPLATE
-
4582
p = Pathname.new(self.class::TEMPLATE)
-
4582
ext = p.basename('.erb').extname
-
4582
ext.empty? ? 'txt' : ext
-
else
-
'txt'
-
end
-
end
-
-
2
def write_to_file(options = {})
-
195
unless output_inhibited?
-
192
if defined? self.class::TEMPLATE || Origen.tester.is_a?(OrigenTesters::Doc)
-
192
write_from_template(options)
-
else
-
fail "Don't know how to write without a template!"
-
end
-
192
stats.completed_files += 1
-
end
-
end
-
-
2
def write_from_template(options = {})
-
192
return unless Origen.interface.write?
-
options = {
-
192
quiet: false,
-
skip_diff: false
-
}.merge(options)
-
192
unless output_inhibited?
-
# If this is not the first time we have written to the current output file
-
# then append to it, otherwise clear it and start from scratch.
-
# The use of a class variable to store the opened files means that it will be
-
# shared by all generators in this run.
-
192
@@opened_files ||= []
-
192
if @@opened_files.include?(output_file) && !Origen.tester.is_a?(OrigenTesters::Doc)
-
@append = true
-
Origen.file_handler.preserve_state do
-
File.open(output_file, 'a') do |out|
-
content = compiler.insert(ERB.new(File.read(self.class::TEMPLATE), 0, Origen.config.erb_trim_mode).result(binding))
-
out.puts content unless content.empty?
-
end
-
end
-
Origen.log.info "Appending... #{output_file.basename}" unless options[:quiet]
-
else
-
192
@append = false
-
192
Origen.file_handler.preserve_state do
-
192
File.open(output_file, 'w') do |out|
-
192
out.puts compiler.insert(ERB.new(File.read(self.class::TEMPLATE), 0, Origen.config.erb_trim_mode).result(binding))
-
end
-
end
-
192
@@opened_files << output_file
-
192
Origen.log.info "Writing... #{output_file.basename}" unless options[:quiet]
-
end
-
192
if !@dont_diff && !options[:skip_diff] && !options[:quiet]
-
192
check_for_changes(output_file, reference_file,
-
compile_job: true,
-
comment_char: Origen.app.tester.program_comment_char)
-
end
-
end
-
end
-
-
2
def output_file
-
# If an explicit output directory has been set, use it
-
1348
if output_directory
-
p = Pathname.new("#{output_directory}/#{filename}")
-
# Otherwise resolve one
-
else
-
1348
if respond_to? :subdirectory
-
796
p = Pathname.new("#{Origen.file_handler.output_directory}/#{subdirectory}/#{filename}")
-
else
-
552
p = Pathname.new("#{Origen.file_handler.output_directory}/#{filename}")
-
end
-
end
-
1348
FileUtils.mkdir_p p.dirname.to_s unless p.dirname.exist?
-
1348
p
-
end
-
-
2
def reference_file
-
192
if OrigenTesters::Generator.original_reference_file
-
Pathname.new("#{Origen.file_handler.reference_directory}/#{filename}")
-
else
-
# If an explicit output directory has been set, use it
-
192
if output_directory
-
sub = Pathname.new(output_directory).relative_path_from(Origen.file_handler.output_directory)
-
dir = File.join(Origen.file_handler.reference_directory, sub)
-
FileUtils.mkdir_p(dir)
-
Pathname.new(File.join(dir, filename))
-
else
-
192
if respond_to? :subdirectory
-
120
dir = File.join(Origen.file_handler.reference_directory, subdirectory)
-
120
FileUtils.mkdir_p(dir)
-
120
Pathname.new(File.join(dir, filename))
-
else
-
72
Pathname.new("#{Origen.file_handler.reference_directory}/#{filename}")
-
end
-
end
-
end
-
end
-
-
# Import sub-program
-
2
def import(file, options = {})
-
options = {
-
133
name: nil
-
}.merge(options)
-
133
file = Pathname.new(file).absolute? ? file : "#{current_dir}/#{file}"
-
133
file = Origen.file_handler.add_rb_to(file) # add .rb to filename if missing
-
133
orig_file = "#{file}" # capture original filename possibly without pre-pended underscore
-
133
file_w_underscore = Origen.file_handler.add_underscore_to(file) # determine filename definitely with pre-pended underscore
-
-
# first check filename definitely with underscore
-
133
file = Origen.file_handler.clean_path_to(file_w_underscore, allow_missing: true) # allow for file missing
-
133
if file.nil? # check if file missing
-
# if so, check original filename that possibly is without underscore
-
10
file = Origen.file_handler.clean_path_to(orig_file, allow_missing: true) # allow for file missing
-
10
if file.nil?
-
# give error if could not find either file
-
fail "Could not find file to import: #{orig_file}" if file.nil? # give error if neither option above is found
-
end
-
end
-
-
133
OrigenTesters::Flow.name_stack << options[:name]
-
-
133
base_collection = collection
-
133
@collection = []
-
133
Origen.generator.option_pipeline << options
-
133
file_pipeline << file
-
133
::OrigenTesters::Generator.execute_source(file)
-
133
file_pipeline.pop
-
133
base_collection << @collection
-
133
@collection = base_collection.flatten
-
end
-
-
2
def render(file, options = {})
-
# Since the flow is now handled via ATP, render the string immediately
-
# for insertion into the AST
-
18
if try(:is_the_flow?)
-
16
val = nil
-
16
Origen.file_handler.preserve_current_file do
-
16
Origen.file_handler.default_extension = file_extension
-
16
full_path = Origen.file_handler.clean_path_to(file, allow_missing: true)
-
14
full_path ||= Origen.file_handler.clean_path_to_sub_template(file)
-
2
placeholder = compiler.render(full_path, options)
-
2
val = compiler.insert(placeholder).chomp
-
end
-
2
val
-
else
-
2
if options.delete(:_inline)
-
super Origen.file_handler.clean_path_to_sub_template(file), options
-
else
-
2
collection << Placeholder.new(:render, file, options)
-
end
-
end
-
end
-
-
2
def stats
-
Origen.app.stats
-
end
-
-
2
def to_be_written?
-
150
true
-
end
-
-
2
def set_flow_description(desc)
-
155
Origen.interface.descriptions.add_for_flow(output_file, desc)
-
end
-
-
2
def identity_map # :nodoc:
-
Origen.interface.identity_map
-
end
-
-
2
def platform
-
3983
Origen.interface.platform
-
end
-
-
2
module ClassMethods
-
2
def new(*args, &block) # :nodoc:
-
153
options = (args.last && args.last.is_a?(Hash)) ? args.last : {}
-
153
x = allocate
-
153
x.filename = options[:filename] if options[:filename]
-
153
x.send(:initialize, *args, &block)
-
153
Origen.interface.sheet_generators << x unless options[:manually_register]
-
153
x
-
end
-
end
-
end
-
end
-
1
module OrigenTesters
-
1
module Generator
-
1
class IdentityMap
-
1
def initialize
-
1
@store = {}
-
1
@versions = {}
-
end
-
-
1
def current_version_of(obj)
-
1921
map = map_for(obj)
-
1921
if map
-
map[:replaced_by] || map[:instance]
-
else
-
1921
obj
-
end
-
end
-
-
1
def map_for(obj)
-
1921
@store[obj.object_id]
-
end
-
end
-
end
-
end
-
1
module OrigenTesters
-
1
module Generator
-
1
class Placeholder
-
1
attr_accessor :type, :file, :options, :id
-
-
1
def initialize(type, file, options = {})
-
2
@type, @file, @options = type, file, options
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
autoload :Base, 'origen_testers/igxl_based_tester/base.rb'
-
2
autoload :J750, 'origen_testers/igxl_based_tester/j750.rb'
-
2
autoload :J750_HPT, 'origen_testers/igxl_based_tester/j750_hpt.rb'
-
2
autoload :UltraFLEX, 'origen_testers/igxl_based_tester/ultraflex.rb'
-
-
2
require 'origen_testers/igxl_based_tester/base.rb'
-
2
require 'origen_testers/igxl_based_tester/decompiler'
-
end
-
# Convenience/Legacy names without the IGXLBasedTester namespace
-
2
autoload :J750, 'origen_testers/igxl_based_tester/j750.rb'
-
2
autoload :J750_HPT, 'origen_testers/igxl_based_tester/j750_hpt.rb'
-
2
autoload :UltraFLEX, 'origen_testers/igxl_based_tester/ultraflex.rb'
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class << self
-
2
attr_reader :pat_extension
-
2
attr_reader :comment_char
-
end
-
2
@pat_extension = 'atp'
-
2
@comment_char = '//'
-
-
# This is the base class of all IGXL-based testers
-
2
class Base
-
2
include VectorBasedTester
-
-
2
attr_accessor :software_version
-
2
attr_accessor :pattern_compiler_pinmap
-
2
attr_accessor :memory_test_en
-
2
attr_accessor :testerconfig
-
2
attr_accessor :channelmap
-
2
attr_accessor :default_channelmap
-
2
attr_accessor :default_testerconfig
-
2
attr_accessor :max_site
-
# permit modification of minimum repeat count
-
2
attr_accessor :min_repeat_loop
-
2
alias_method :min_repeat_count, :min_repeat_loop
-
2
alias_method :min_repeat_count=, :min_repeat_loop=
-
-
# Control literal flag definitions
-
2
attr_accessor :literal_flags # whether flags should be exactly as indicated
-
2
attr_accessor :literal_enables # whether enables should be exactly as indicated
-
-
# NOTE: DO NOT USE THIS CLASS DIRECTLY ONLY USED AS PARENT FOR
-
# DESIRED TESTER CLASS
-
-
# Returns a new IGXLBasedTester instance, normally there would only ever be one of these
-
# assigned to the global variable such as $tester by your target.
-
2
def initialize(options = {})
-
393
@unique_counter = 0
-
393
@counter_lsb_bits = 0
-
393
@counter_msb_bits = 0
-
393
@max_repeat_loop = 65_535 # 16 bits
-
393
@min_repeat_loop = 2
-
393
@pat_extension = OrigenTesters::IGXLBasedTester.pat_extension
-
393
@active_loads = true
-
393
@pipeline_depth = 34
-
393
@software_version = ''
-
393
@compress = true
-
393
@support_repeat_previous = true
-
393
@match_entries = 10
-
393
@name = ''
-
393
@program_comment_char = ['logprint', "'"]
-
393
@opcode_mode = :extended
-
393
@flags = %w(cpuA cpuB cpuC cpuD)
-
393
@microcode = {}
-
393
@microcode[:enable] = 'enable'
-
393
@microcode[:set_flag] = 'set_cpu'
-
393
@microcode[:mask_vector] = 'ign ifc icc'
-
-
393
@mask_vector = false # sticky option to mask all subsequent vectors
-
-
393
@min_pattern_vectors = 0 # no minimum
-
-
393
@memory_test_en = false # memory test enabled (for all patterns?)
-
-
393
@testerconfig ||= {}
-
393
@channelmap ||= {}
-
393
@pushed_instrument_configs = {}
-
393
@overlay_style = :subroutine # default to use subroutine for overlay
-
393
@capture_style = :hram # default to use hram for capture
-
393
@overlay_history = {} # used to track labels, subroutines, digsrc pins used etc
-
393
@overlay_subr = nil
-
393
@capture_history = {}
-
-
393
if options[:literal_flags]
-
4
@literal_flags = true
-
end
-
393
if options[:literal_enables]
-
4
@literal_enables = true
-
end
-
end
-
-
2
def igxl_based?
-
12
true
-
end
-
-
2
def import_tester_config(testconfigname, fullconfigpath)
-
# This function reads in CurrentConfig.txt file generated by IG-XL.
-
# testconfigname example ==> "FT", "WT", "Production"
-
# fullconfigpath example ==> "/product_folder/CurrentConfig.txt"
-
-
1
puts "importing Testerconfig #{testconfigname}..."
-
1
slotnum = Struct.new(:slot, :instrument, :idprom)
-
1
@testerconfig[testconfigname] ||= {}
-
1
current_config_file = Pathname.new(fullconfigpath)
-
1
File.open(current_config_file, 'r').each_line do |line|
-
196
if line =~ /^\d*.0/
-
24
(slot, blank1, instrument, blank2, idprom) = line.split(/\t/)
-
24
if (!slot.nil?) && (!instrument.nil?) && (!idprom.nil?)
-
22
@testerconfig[testconfigname][slot.split('.').first.to_i] = slotnum.new(slot.split('.').first.to_i, instrument, idprom.chomp)
-
end
-
end
-
end
-
-
1
@default_testerconfig ||= testconfigname # Default TesterConfig gets set if it's not nil
-
end
-
-
2
def get_tester_instrument(testconfigname, slot)
-
8
@testerconfig[testconfigname].each_with_index do |element, index|
-
62
if slot.to_s == element[0].to_s
-
8
return element[1][:instrument]
-
end
-
end
-
nil # if no corresponding slot
-
end
-
-
2
def get_instrument_slots(testconfigname, instrument) # testconfigname example "WT", "FT", "Production"
-
1
@slots = []
-
1
@testerconfig[testconfigname].each_with_index do |element, index|
-
22
if instrument.to_s == element[1][:instrument].to_s
-
5
@slots << element[0].to_i
-
end
-
end
-
1
@slots # if no corresponding slot
-
end
-
-
2
def import_chanmap(chanmapname, fullchanmappath)
-
# This function reads IG-XL ChannelMap file
-
# chanmapname example ==> "FT", "WT", "FTX2"
-
# fullchanmappath example ==> "/product_folder/Chans_FT.txt"
-
-
1
puts "importing ChannelMap #{fullchanmappath}..."
-
-
1
chanassignment = Struct.new(:pinname, :site, :channel, :type, :packagepin)
-
1
chanmap_file = Pathname.new(fullchanmappath)
-
1
@channelmap[chanmapname] ||= {}
-
1
File.open(chanmap_file, 'r').each_line.with_index do |line, index|
-
35
if index == 0
-
1
unless line =~ /DTChanMap/
-
puts "#{fullchanmappath} is not a valid IG-XL ChannelMap!"
-
break
-
end
-
end
-
35
if index == 5
-
1
siteloc = line.strip.split(/\t/).size - 1 # strip all white spaces and grab second to last
-
1
@max_site_s = line.split(/\t/)[siteloc].strip.split(/\s/)[1]
-
1
@max_site = @max_site_s.to_i
-
1
(0..@max_site).each do |sitenum|
-
4
@channelmap[chanmapname][sitenum] ||= {}
-
end
-
end
-
35
if index > 5
-
29
(blank1, pinname, packagepin, type) = line.split(/\t/)
-
29
(0..@max_site).each do |sitenum|
-
116
channel = line.split(/\t/)[4 + sitenum].to_s
-
116
@channelmap[chanmapname][sitenum][pinname.downcase.intern] = chanassignment.new(pinname.downcase.intern, sitenum, channel.chomp, type.chomp, packagepin)
-
end
-
end
-
end
-
1
@default_channelmap ||= chanmapname # Default Channelmap gets set if it's not nil
-
end
-
-
2
def get_tester_channel(chanmapname, pinname, sitenum)
-
15
if sitenum <= @max_site
-
15
@testerchannel = @channelmap[chanmapname][sitenum][pinname].channel
-
15
return @testerchannel
-
else
-
return nil
-
end
-
end
-
-
# Check if a specific pin for a given channelmap for a given site number is using merged channel.
-
# If yes, return x2 for Merged2, x4 for Merged4, etc. If no, return nil.
-
2
def merged_channels(chanmapname, pinname, sitenum)
-
3
if sitenum <= @max_site
-
3
if @channelmap[chanmapname][sitenum][pinname].type.include?('Merged')
-
3
@merged_channels = @channelmap[chanmapname][sitenum][pinname].type.split('Merged')[1]
-
3
return 'x' + @merged_channels
-
end
-
else
-
return nil
-
end
-
end
-
-
# Check if a specific HexVS supply is HexVS+ variety, which has +/-2mV accuracy as opposed to
-
# +/-7mV accuracy.
-
# If the specific HexVS is HexVS+ variety, returns a "+" string, otherwise nil.
-
2
def is_hexvs_plus(testconfigname, slot)
-
3
if @testerconfig[testconfigname][slot][:instrument].to_s == 'HexVS'
-
1
@productnum = @testerconfig[testconfigname][slot][:idprom].split(' ')[0]
-
1
if (@productnum.include?('974-294-')) && (@productnum.split('-')[2].to_i >= 20)
-
1
return '+'
-
end
-
end
-
nil # if nothing matched
-
end
-
-
# Check if a specific VHDVS (UVS256) supply is High-Accuracy (HA) variety, which has +/-5mV+0.1%*SUPPLY accuracy as opposed to
-
# +/-10mV+0.1%*SUPPLY accuracy.
-
# If the specific VHDVS is of High-Accuracy variety, returns a "+" string, otherwise nil.
-
2
def is_vhdvs_plus(testconfigname, slot)
-
3
if @testerconfig[testconfigname][slot][:instrument].to_s == 'VHDVS'
-
3
@productnum = @testerconfig[testconfigname][slot][:idprom].split(' ')[0]
-
# binding.pry
-
3
if (@productnum.include?('805-052-')) && (@productnum.split('-')[2].to_i >= 05)
-
3
return '+'
-
end
-
end
-
nil # if nothing matched
-
end
-
# Check if a specific VHDVS (UVS256) channel assignment is _HC variety (high-current)
-
# If the specific VHDVS channel is _HC variety, returns a "_HC" string, otherwise nil.
-
2
def is_vhdvs_hc(chanmapname, pinname, sitenum)
-
3
if sitenum <= @max_site
-
3
if @channelmap[chanmapname][sitenum][pinname].channel.downcase.include?('hc')
-
3
return '_HC'
-
end
-
end
-
nil # if nothing matched
-
end
-
-
2
def assign_dc_instr_pins(dc_pins)
-
123
if !dc_pins.is_a?(Array)
-
@dc_pins = [] << dc_pins
-
else
-
123
@dc_pins = dc_pins
-
end
-
end
-
-
2
def assign_digsrc_pins(digsrc_pins)
-
125
if !digsrc_pins.is_a?(Array)
-
@digsrc_pins = [] << digsrc_pins
-
else
-
125
@digsrc_pins = digsrc_pins
-
end
-
end
-
-
2
def assign_digcap_pins(digcap_pins)
-
123
if !digcap_pins.is_a?(Array)
-
123
@digcap_pins = [] << digcap_pins
-
else
-
@digcap_pins = digcap_pins
-
end
-
end
-
-
2
def get_dc_instr_pins
-
20
@dc_pins
-
end
-
-
2
def get_digsrc_pins
-
20
@digsrc_pins
-
end
-
-
2
def get_digcap_pins
-
20
@digcap_pins
-
end
-
-
2
def flows
-
parser.flows
-
end
-
-
# Main accessor to all content parsed from existing test program sheets found in the
-
# supplied directory or in Origen.config.test_program_output_directory
-
2
def parser(prog_dir = Origen.config.test_program_output_directory)
-
unless prog_dir
-
fail 'You must supply the directory containing the test program sheets, or define it via Origen.config.test_program_output_directory'
-
end
-
@parser ||= IGXLBasedTester::Parser.new
-
@parsed_dir ||= false
-
if @parsed_dir != prog_dir
-
@parser.parse(prog_dir)
-
@parsed_dir = prog_dir
-
end
-
@parser
-
end
-
-
# Capture a vector to the tester HRAM.
-
#
-
# This method applies a store vector (stv) opcode to the previous vector, note that is does
-
# not actually generate a new vector.
-
#
-
# Sometimes when generating vectors within a loop you may want to apply a stv opcode
-
# retrospectively to a previous vector, passing in an offset option will allow you
-
# to do this.
-
#
-
# On J750 the pins argument is ignored since the tester only supports whole vector capture.
-
#
-
# @example
-
# $tester.cycle # This is the vector you want to capture
-
# $tester.store # This applies the STV opcode
-
#
-
# $tester.cycle # This one gets stored
-
# $tester.cycle
-
# $tester.cycle
-
# $tester.store(:offset => -2) # Just realized I need to capture that earlier vector
-
2
def store(*pins)
-
31
options = pins.last.is_a?(Hash) ? pins.pop : {}
-
31
options = { offset: 0
-
}.merge(options)
-
31
update_vector microcode: 'stv', offset: options[:offset]
-
31
last_vector(options[:offset]).contains_capture = true unless @inhibit_vectors
-
end
-
2
alias_method :to_hram, :store
-
2
alias_method :capture, :store
-
-
# Capture the next vector generated to HRAM
-
#
-
# This method applies a store vector (stv) opcode to the next vector to be generated,
-
# note that is does not actually generate a new vector.
-
#
-
# On J750 the pins argument is ignored since the tester only supports whole vector capture.
-
#
-
# @example
-
# $tester.store_next_cycle
-
# $tester.cycle # This is the vector that will be captured
-
2
def store_next_cycle(*pins)
-
4
options = pins.last.is_a?(Hash) ? pins.pop : {}
-
4
options = {
-
}.merge(options)
-
-
4
unless @inhibit_vectors
-
3
preset_next_vector microcode: 'stv' do |vector|
-
3
vector.contains_capture = true
-
end
-
end
-
end
-
2
alias_method :store!, :store_next_cycle
-
-
# @api private
-
2
def remove_store_from_vector(vector)
-
super
-
vector.microcode = nil
-
end
-
-
# Call a subroutine.
-
#
-
# This method applies a call subroutine opcode to the previous vector, it does not
-
# generate a new vector.
-
#
-
# Subroutines should always be called through this method as it ensures a running
-
# log of called subroutines is maintained and which then gets output in the pattern
-
# header to import the right dependencies.
-
#
-
# An offset option is available to make the call on earlier vectors.
-
#
-
# ==== Examples
-
# $tester.call_subroutine("mysub")
-
# $tester.call_subroutine("my_other_sub", :offset => -1)
-
2
def call_subroutine(name, options = {})
-
options = {
-
44
offset: 0
-
}.merge(options)
-
44
unless @inhibit_vectors
-
34
called_subroutines << name.to_s.chomp unless called_subroutines.include?(name.to_s.chomp) || @inhibit_vectors
-
34
update_vector microcode: "call #{name}", offset: options[:offset]
-
end
-
end
-
-
# Start a subroutine.
-
#
-
# Generates a global subroutine label. Global is used to adhere to the best practice of
-
# containing all subroutines in dedicated patterns, e.g. global_subs.atp
-
#
-
# ==== Examples
-
# $tester.start_subroutine("wait_for_done")
-
# < generate your subroutine vectors here >
-
# $tester.end_subroutine
-
2
def start_subroutine(name, options = {})
-
48
unless @inhibit_vectors
-
46
local_subroutines << name.to_s.chomp unless local_subroutines.include?(name.to_s.chomp) || @inhibit_vectors
-
46
if $tester.ultraflex? && (name =~ /keep_?alive/ || options[:keep_alive])
-
1
microcode "keepalive subr #{name}:"
-
else
-
45
microcode "global subr #{name}:"
-
end
-
end
-
end
-
-
# End a subroutine.
-
#
-
# Generates a return opcode on the last vector.
-
#
-
# ==== Examples
-
# $tester.start_subroutine("wait_for_done")
-
# < generate your subroutine vectors here >
-
# $tester.end_subroutine
-
# cond: whether return is conditional on a flag (to permit to mix subrs together)
-
2
def end_subroutine(cond = false, options = {})
-
48
(cond, options) = false, cond if cond.is_a?(Hash)
-
48
if cond
-
update_vector microcode: 'if (flag) return'
-
else
-
48
update_vector microcode: 'return'
-
end
-
end
-
-
# Do a frequency measure.
-
#
-
# Write the necessary micro code to do a frequency measure on the given pin,
-
# optionally supply a read code to pass information to the tester.
-
#
-
# ==== Examples
-
# $tester.freq_count($top.pin(:d_out)) # Freq measure on pin "d_out"
-
# $tester.freq_count($top.pin(:d_out):readcode => 10)
-
2
def freq_count(pin, options = {})
-
5
options = { readcode: false
-
}.merge(options)
-
-
5
set_code(options[:readcode]) if options[:readcode]
-
5
cycle(microcode: "#{@microcode[:set_flag]} (cpuA)")
-
5
cycle(microcode: "#{@microcode[:set_flag]} (cpuA)")
-
5
cycle(microcode: "#{@microcode[:set_flag]} (cpuB)")
-
5
cycle(microcode: "#{@microcode[:set_flag]} (cpuC)")
-
5
cycle(microcode: 'freq_loop_1:')
-
5
cycle(microcode: 'if (cpuA) jump freq_loop_1')
-
5
pin.drive_lo
-
5
delay(2000)
-
5
pin.dont_care
-
5
cycle(microcode: "freq_loop_2: #{@microcode[:enable]} (#{@flags[1]})")
-
5
cycle(microcode: 'if (flag) jump freq_loop_2')
-
5
cycle(microcode: "#{@microcode[:enable]} (#{@flags[2]})")
-
5
cycle(microcode: 'if (flag) jump freq_loop_1')
-
end
-
-
# * J750 Specific *
-
#
-
# Generates a single MTO opcode line for J750
-
#
-
# Codes implemented: xa load_preset, xa inc, ya load_preset, ya inc, stv_m0, stv_m1, stv_c<br>
-
2
def memory_test(options = {})
-
options = {
-
12
gen_vector: true, # Default generate vector not just MTO opcode
-
init_counter_x: false, # initialize counter X
-
inc_counter_x: false, # increment counter X
-
init_counter_y: false, # initialize counter X
-
inc_counter_y: false, # increment counter X
-
capture_vector: false, # capture vector to memory using all mem types
-
capture_vector_mem0: false, # capture vector to memory type 0, here for J750 will be stv_m0
-
capture_vector_mem1: false, # capture vector to memory type 1, here for J750 will be stv_m1
-
capture_vector_mem2: false, # capture vector to memory type 2, here for J750 will be stv_c
-
pin: false, # pin on which to drive or expect data, pass pin object here!
-
pin_data: false, # pin data (:none, :drive, :expect)
-
}.merge(options)
-
-
12
mto_opcode = ''
-
-
12
if options[:init_counter_x]
-
2
mto_opcode += ' xa load_preset'
-
end
-
12
if options[:inc_counter_x]
-
4
mto_opcode += ' xa inc'
-
end
-
12
if options[:init_counter_y]
-
2
mto_opcode += ' ya load_preset'
-
end
-
12
if options[:inc_counter_y]
-
4
mto_opcode += ' ya inc'
-
end
-
12
if options[:capture_vector]
-
2
mto_opcode += ' stv_m0 stv_m1 stv_c'
-
end
-
12
if options[:capture_vector_mem0]
-
mto_opcode += ' stv_m0'
-
end
-
12
if options[:capture_vector_mem1]
-
mto_opcode += ' stv_m1'
-
end
-
12
if options[:capture_vector_mem2]
-
mto_opcode += ' stv_c'
-
end
-
-
12
unless mto_opcode.eql?('')
-
10
mto_opcode = '(mto:' + mto_opcode + ')'
-
end
-
-
12
if options[:gen_vector]
-
12
if options[:pin]
-
2
case options[:pin_data]
-
when :drive
-
# store current pin state
-
cur_pin_state = options[:pin].state.to_sym
-
options[:pin].drive_mem
-
when :expect
-
# store current pin state
-
2
cur_pin_state = options[:pin].state.to_sym
-
2
options[:pin].expect_mem
-
end
-
end
-
12
cycle(microcode: "#{mto_opcode}")
-
12
if options[:pin]
-
# restore previous pin state
-
2
case options[:pin_data]
-
when :drive
-
options[:pin].state = cur_pin_state
-
when :expect
-
2
options[:pin].state = cur_pin_state
-
end
-
end
-
else
-
microcode "#{mto_opcode}"
-
end
-
end
-
-
# Generates a match loop on up to two pins.
-
#
-
# This method is not really intended to be called directly, rather you should call
-
# via Tester#wait e.g. $tester.wait(:match => true).
-
#
-
# The timeout should be provided in cycles, however when called via the wait method the
-
# time-based helpers (time_in_us, etc) will be converted to cycles for you.
-
# The following options are available to tailor the match loop behavior, defaults in
-
# parenthesis:
-
# * :pin - The pin object to match on (*required*)
-
# * :state - The pin state to match on, :low or :high (*required*)
-
# * :pin2 (nil) - Optionally supply a second pin to match on
-
# * :state2 (nil) - State for the second pin (required if :pin2 is supplied)
-
# * :check_for_fails (false) - Flushes the pipeline and handshakes with the tester (passing readcode 100) prior to the match (to allow binout of fails encountered before the match)
-
# * :force_fail_on_timeout (true) - Force a vector mis-compare if the match loop times out
-
# * :on_timeout_goto ("") - Optionally supply a label to branch to on timeout, by default will continue from the end of the match loop
-
# * :on_pin_match_goto ("") - Optionally supply a label to branch to when pin 1 matches, by default will continue from the end of the match loop
-
# * :on_pin2_match_goto ("") - Optionally supply a label to branch to when pin 2 matches, by default will continue from the end of the match loop
-
# * :multiple_entries (false) - Supply an integer to generate multiple entries into the match (each with a unique readcode), this can be useful when debugging patterns with multiple matches
-
# * :force_fail_on_timeout (true) - force pattern to fail if timeout occurs
-
# * :global_loops (false) - whether match loop loops should use global labels
-
# * :manual_stop (false) - whether to use extra cpuB flag to resolve IG-XL v.3.50.xx bug where VBT clears cpuA immediately
-
# at start of PatFlagFunc instead of at end. Use will have to manually clear cpuB to resume this pattern.
-
# ==== Examples
-
# $tester.wait(:match => true, :time_in_us => 5000, :pin => $top.pin(:done), :state => :high)
-
2
def match(pin, state, timeout, options = {})
-
options = {
-
26
check_for_fails: false,
-
on_timeout_goto: false,
-
pin2: false,
-
state2: false,
-
on_pin_match_goto: false,
-
multiple_entries: false,
-
force_fail_on_timeout: true,
-
global_loops: false,
-
manual_stop: false,
-
clr_fail_post_match: false
-
}.merge(options)
-
26
options[:on_block_match_goto] ||= options.delete(:on_pin_match_goto)
-
-
26
match_block(timeout, options) do |match_conditions, fail_conditions|
-
# Define match conditions
-
26
match_conditions.add do
-
26
state == :low ? pin.expect_lo : pin.expect_hi
-
26
cc "Check if #{pin.name} is #{state == :low ? 'low' : 'high'}"
-
26
cycle
-
26
pin.dont_care
-
end
-
-
26
if options[:pin2]
-
10
match_conditions.add do
-
10
state == :low ? pin.expect_hi : pin.expect_lo
-
10
options[:state2] == :low ? options[:pin2].expect_lo : options[:pin2].expect_hi
-
10
cc "Check if #{options[:pin2].name} is #{options[:state2] == :low ? 'low' : 'high'}"
-
10
cycle
-
10
options[:pin2].dont_care
-
10
pin.dont_care
-
end
-
end
-
-
# Define fail conditions
-
26
fail_conditions.add do
-
26
state == :low ? pin.expect_lo : pin.expect_hi
-
26
cc "Check if #{pin.name} is #{state == :low ? 'low' : 'high'}"
-
26
if options[:pin2]
-
10
options[:state2] == :low ? options[:pin2].expect_lo : options[:pin2].expect_hi
-
10
cc "Check if #{options[:pin2].name} is #{options[:state2] == :low ? 'low' : 'high'}"
-
end
-
26
cycle
-
26
pin.dont_care
-
26
options[:pin2].dont_care if options[:pin2]
-
end
-
end
-
end
-
-
# Call a match loop.
-
#
-
# Normally you would put your match loop in a global subs pattern, then you can
-
# call it via this method. This method automatically syncs match loop naming with
-
# the match generation flow, no arguments required.
-
#
-
# This is an IGXLBasedTester specific API.
-
#
-
# ==== Examples
-
# $tester.cycle
-
# $tester.call_match # Calls the match loop, or the first entry point if you have multiple
-
# $tester.cycle
-
# $tester.call_match # Calls the match loop, or the second entry point if you have multiple
-
2
def call_match
-
6
@match_counter = @match_counter || 0
-
6
call_subroutine("match_done_#{@match_counter}")
-
6
@match_counter += 1 unless @match_counter == (@match_entries || 1) - 1
-
end
-
-
# Apply a label to the pattern.
-
#
-
# No additional vector is generated.
-
# Arguments:
-
# name : label name
-
# global : (optional) whether to apply global label, default=false
-
#
-
# ==== Examples
-
# $tester.label("something_significant")
-
# $tester.label("something_significant",true) # apply global label
-
2
def label(name, global = false)
-
17
global_opt = (global) ? 'global ' : ''
-
17
microcode global_opt + name + ':' unless @inhibit_vectors
-
end
-
-
# * J750 Specific *
-
#
-
# Set a readcode.
-
#
-
# Use the set an explicit readcode for communicating with the tester. This method
-
# will generate an additional vector.
-
#
-
# ==== Examples
-
# $tester.set_code(55)
-
2
def set_code(code)
-
53
cycle(microcode: "set_code #{code}")
-
end
-
-
# Branch execution to the given point.
-
#
-
# This generates a new vector with a jump instruction to a given label. This method
-
# will generate an additional vector.
-
#
-
# ==== Examples
-
# $tester.branch_to("something_significant")
-
2
def branch_to(label)
-
7
cycle(microcode: "jump #{label}")
-
end
-
2
alias_method :branch, :branch_to
-
-
# Add loop to the pattern.
-
#
-
# Pass in a name for the loop and the number of times to execute it, all vectors
-
# generated by the given block will be captured in the loop.
-
#
-
# Optional arguments: global - whether to apply global label (default=false)
-
# label_first - whether to apply loop label before loop vector or not
-
#
-
# ==== Examples
-
# $tester.loop_vectors("pulse_loop", 3) do # Do this 3 times...
-
# $tester.cycle
-
# some_other_method_to_generate_vectors
-
# end
-
2
def loop_vectors(name, number_of_loops, global = false, label_first = false)
-
8
if number_of_loops > 1
-
5
@loop_counters ||= {}
-
5
if @loop_counters[name]
-
2
@loop_counters[name] += 1
-
else
-
3
@loop_counters[name] = 0
-
end
-
5
loop_name = @loop_counters[name] == 0 ? name : "#{name}_#{@loop_counters[name]}"
-
5
if label_first
-
2
global_opt = (global) ? 'global ' : ''
-
2
microcode "#{global_opt}#{loop_name}: "
-
end
-
5
cycle(microcode: "loopA #{number_of_loops}")
-
5
unless label_first
-
3
global_opt = (global) ? 'global ' : ''
-
3
cycle(microcode: "#{global_opt}#{loop_name}: ")
-
end
-
5
yield
-
5
cycle(microcode: "end_loopA #{loop_name}")
-
else
-
3
yield
-
end
-
end
-
2
alias_method :loop_vector, :loop_vectors
-
-
# An internal method called by Origen Pattern Create to create the pattern header
-
2
def pattern_header(options = {})
-
options = {
-
85
instruments: {}, # Provide instruments here if desired as a hash (e.g. "mto" => "dgen_2bit")
-
subroutine_pat: false,
-
svm_only: true, # Whether 'svm_only' can be specified
-
group: false, # If true the end pattern is intended to run within a pattern group
-
high_voltage: false, # Supply a pin name here to declare it as an HV instrument (not yet defined)
-
freq_counter: false, # Supply a pin name here to declare it as a frequency counter
-
memory_test: false, # If true, define 2-bit MTO DGEN as instrument
-
}.merge(options)
-
-
85
if level_period?
-
microcode "import tset #{min_period_timeset.name};"
-
else
-
85
called_timesets.each do |timeset|
-
109
microcode "import tset #{timeset.name};"
-
end
-
end
-
85
unless options[:group] # Withhold imports for pattern groups, is this correct?
-
85
called_subroutines.each do |sub_name|
-
# Don't import any called subroutines that are declared in the current pattern
-
32
microcode "import svm_subr #{sub_name};" unless local_subroutines.include?(sub_name)
-
end
-
end
-
-
# If memory test, then add to instruments hash
-
85
if options[:memory_test]
-
2
options[:instruments].merge!('mto' => 'dgen_2bit')
-
end
-
-
85
if options[:svm_only]
-
65
microcode "svm_only_file = #{options[:subroutine_pat] ? 'yes' : 'no'};"
-
end
-
-
85
microcode "opcode_mode = #{@opcode_mode};"
-
85
microcode "digital_inst = #{options[:digital_inst]};" if options[:digital_inst]
-
85
microcode 'compressed = yes;' # if $dut.gzip_patterns
-
85
if tester.j750? && options[:freq_counter]
-
# pin setup type => freq_counter is only for the J750.
-
# UltraFLEX has frequency counter capability behind every pin.
-
# need to make sure the pin_setup freq_count is defined after opcode_mode extended since freq count only work in extended mode
-
if @opcode_mode == :extended
-
microcode "pin_setup = {#{options[:freq_counter]} freq_count;}"
-
else
-
fail 'pin_setup freq_count can only work in extended mode'
-
end
-
end
-
-
# Take care of any instruments
-
85
options[:instruments] = options[:instruments].merge(@pushed_instrument_configs)
-
85
if options[:instruments].length > 0
-
21
microcode 'instruments = {'
-
21
options[:instruments].each do |pins, instrument|
-
104
if "#{pins}" == 'nil'
-
16
microcode " #{instrument};"
-
88
elsif instrument == 'digsrc'
-
32
microcode " #{pins}:#{instrument} #{options[:digsrc_width]}:#{options[:digsrc_bit_order]}:#{options[:digsrc_mode]}:format=#{options[:digsrc_format]}:#{options[:digsrc_site_uniqueness]}:#{options[:digsrc_auto_cond]};"
-
56
elsif instrument == 'digcap'
-
16
microcode " #{pins}:#{instrument} #{options[:digcap_width]}:#{options[:digcap_bit_order]}:#{options[:digcap_mode]}:format=#{options[:digcap_format]}:data_type=#{options[:digcap_data_type]}:#{options[:digcap_auto_cond]}:#{options[:digcap_auto_trig_enable]}:#{options[:digcap_store_stv]}:#{options[:digcap_receive_data]};"
-
else
-
40
microcode " #{pins}:#{instrument};"
-
end
-
end
-
21
microcode '}'
-
end
-
-
85
options[:high_voltage] = @use_hv_pin
-
85
microcode "pin_setup = {#{options[:high_voltage]} high_voltage;}" if options[:high_voltage]
-
85
microcode ''
-
-
85
pin_list = ordered_pins.map(&:name).join(', ')
-
-
# here indicate pattern header specific stuff
-
85
yield pin_list
-
85
if ordered_pins.size > 0
-
679
max_pin_name_length = ordered_pins.map(&:name).max { |a, b| a.length <=> b.length }.length
-
764
pin_widths = ordered_pins.map { |p| p.size - 1 }
-
-
85
max_pin_name_length.times do |i|
-
6734
cc((' ' * 93) + ordered_pins.map.with_index { |p, x| ((p.name[i] || ' ') + ' ' * pin_widths[x]).gsub('_', '-') }.join(' '))
-
end
-
end
-
end
-
-
# An internal method called by Origen to generate the pattern footer
-
2
def pattern_footer(options = {})
-
options = {
-
84
subroutine_pat: false,
-
end_in_ka: false,
-
end_with_halt: false,
-
end_module: true
-
}.merge(options)
-
84
$tester.align_to_last
-
# cycle(:microcode => "#{$dut.end_of_pattern_label}:") if $dut.end_of_pattern_label
-
84
if options[:end_in_ka]
-
3
keep_alive(options)
-
else
-
81
if options[:end_with_halt]
-
1
$tester.cycle microcode: 'halt'
-
else
-
80
if options[:end_module]
-
62
$tester.cycle microcode: 'end_module' unless options[:subroutine_pat]
-
else
-
18
$tester.cycle
-
end
-
end
-
end
-
84
microcode '}'
-
end
-
-
# Returns an array of subroutines called while generating the current pattern
-
2
def called_subroutines
-
151
@called_subroutines ||= []
-
end
-
-
# Returns an array of subroutines created by the current pattern
-
2
def local_subroutines # :nodoc:
-
124
@local_subroutines ||= []
-
end
-
-
# This is an internal method use by Origen which returns a fully formatted vector
-
# You can override this if you wish to change the output formatting at vector level
-
2
def format_vector(vec)
-
13148
timeset = vec.timeset ? "> #{vec.timeset.name}" : ''
-
13148
pin_vals = vec.pin_vals ? "#{vec.pin_vals} ;" : ''
-
13148
if vec.repeat > 1
-
3036
microcode = "repeat #{vec.repeat}"
-
else
-
10112
microcode = vec.microcode ? vec.microcode : ''
-
end
-
13148
if vec.pin_vals && ($_testers_enable_vector_comments || vector_comments)
-
comment = " // #{vec.number}:#{vec.cycle} #{vec.inline_comment}"
-
else
-
13148
comment = vec.inline_comment.empty? ? '' : " // #{vec.inline_comment}"
-
end
-
-
13148
"#{microcode.ljust(65)}#{timeset.ljust(31)}#{pin_vals}#{comment}"
-
end
-
-
# Override this to force the formatting to match the v1 J750 model (easier diffs)
-
2
def push_microcode(code) # :nodoc:
-
1396
stage.store(code.ljust(65) + ''.ljust(31)) unless @inhibit_vectors
-
end
-
2
alias_method :microcode, :push_microcode
-
-
# All vectors generated with the supplied block will have all pins set
-
# to the repeat previous state. Any pins that are changed state within
-
# the block will still update to the supplied value.
-
# ==== Example
-
# # All pins except invoke will be assigned the repeat previous code
-
# # in the generated vector. On completion of the block they will
-
# # return to their previous state, except for invoke which will
-
# # retain the value assigned within the block.
-
# $tester.repeat_previous do
-
# $top.pin(:invoke).drive(1)
-
# $tester.cycle
-
# end
-
2
def repeat_previous
-
4
pinmap = Origen.pin_bank.pins
-
112
pinmap.each { |id, pin| pin.repeat_previous = true }
-
4
yield
-
112
pinmap.each { |id, pin| pin.repeat_previous = false }
-
end
-
-
2
def ignore_fails(*pins)
-
4
pins.each(&:suspend)
-
4
yield
-
4
pins.each(&:resume)
-
end
-
-
2
def enable_flag(options = {})
-
options = { flagnum: 4, # default flag to use
-
}.merge(options)
-
-
if options[:flagnum] > @flags.length
-
abort "ERROR! Invalid flag value passed to 'enable_flag' method!\n"
-
end
-
flagname = @flags[options[:flagnum] - 1]
-
update_vector(microcode: "#{@microcode[:enable]}(#{flagname})")
-
end
-
-
2
def set_flag(options = {})
-
options = { flagnum: 4, # default flag to use
-
}.merge(options)
-
-
if options[:flagnum] > @flags.length
-
abort "ERROR! Invalid flag value passed to 'set_flag' method!\n"
-
end
-
flagname = @flags[options[:flagnum] - 1]
-
update_vector(microcode: "#{@microcode[:set_flag]}(#{flagname})")
-
end
-
-
2
def cycle(options = {})
-
# handle overlay if requested
-
23684
ovly_style = nil
-
23684
if options.key?(:overlay)
-
26
ovly_style = options[:overlay][:overlay_style].nil? ? @overlay_style : options[:overlay][:overlay_style]
-
26
overlay_str = options[:overlay][:overlay_str]
-
-
# route the overlay request to the appropriate method
-
26
case ovly_style
-
when :subroutine, :default
-
5
subroutine_overlay(overlay_str, options)
-
5
ovly_style = :subroutine
-
when :label, :global_label
-
12
options[:dont_compress] = true
-
12
unless @overlay_history.key?(overlay_str)
-
# J750 behavior is local label not global
-
4
label "#{overlay_str}", (ovly_style == :global_label)
-
4
@overlay_history[overlay_str] = { is_label: true }
-
end
-
when :digsrc
-
9
if ultraflex?
-
8
cur_pin_state = options[:overlay][:pins].state.to_sym
-
8
options[:overlay][:pins].drive_mem
-
8
options = digsrc_overlay(options)
-
else
-
1
ovly_style = overlay_style_warn(options[:overlay][:overlay_str], options)
-
end
-
else
-
ovly_style = overlay_style_warn(options[:overlay][:overlay_str], options)
-
end # case ovly_style
-
else
-
23658
@overlay_subr = nil
-
end # of handle overlay
-
-
23684
options_overlay = options.delete(:overlay) if options.key?(:overlay)
-
23684
unless ovly_style == :subroutine
-
23678
if @mask_vector
-
# tack on masking opcodes
-
1288
super(options.merge(microcode: "#{options[:microcode]} #{@microcode[:mask_vector]}"))
-
else
-
22390
super(options)
-
end
-
end # unless ovly_style
-
-
23683
unless options_overlay.nil?
-
26
options_overlay[:pins].state = cur_pin_state if ovly_style == :digsrc
-
# stage = :body if ovly_style == :subroutine # always set stage back to body in case subr overlay was selected
-
end
-
end
-
-
# Warn user of unsupported overlay style
-
2
def overlay_style_warn(overlay_str, options)
-
1
Origen.log.warn("Unrecognized overlay style :#{@overlay_style}, defaulting to subroutine")
-
1
Origen.log.warn('Available overlay styles :label, :global_label, :subroutine') if j750? || j750_hpt?
-
1
Origen.log.warn('Available overlay styles :digsrc, :digsrc_subroutine, :label, :global_label, :subroutine') if ultraflex?
-
1
subroutine_overlay(overlay_str, options)
-
1
@overlay_style = :subroutine # Just give 1 warning
-
end
-
-
# Call this method at the start of any digsrc overlay operations, this method
-
# takes care of all the microcodes and delays that's needed for digsrc overlay
-
# Required arguments:
-
# pins
-
# Optionsal arguments:
-
# options[:dssc_mode] = :single or :dual, anything else wil be
-
# treated as if it's operating in :quad mode
-
2
def digsrc_start(pins, options = {})
-
options = {
-
2
dssc_mode: :single # defaults dssc_mode to single mode
-
}.merge(options)
-
2
if pins.size > 1
-
2
microcode "((#{format_multiple_instrument_pins(pins)}):DigSrc = Start)"
-
else
-
microcode "((#{pin}):DigSrc = Start)"
-
end
-
2
if options[:dssc_mode] == :single
-
2
$tester.cycle(repeat: 145) # minimum of 144 cycles, adding 1 for safey measures
-
elsif options[:dssc_mode] == :dual
-
$tester.cycle(repeat: 289) # minimum of 288 cycles, adding 1 for safety measures
-
else
-
$tester.cycle(repeat: 577) # minimum of 577 cycles, adding 1 for safety measures
-
end
-
end
-
-
# Call this method at the end of each digscr overlay operation to clear the pattern
-
# memory pipeline, so that the pattern is ready to do the next digsrc overlay operation.
-
# Required arguments:
-
# pins
-
2
def digsrc_stop(pins, options = {})
-
2
if pins.size > 1
-
2
microcode "((#{format_multiple_instrument_pins(pins)}):DigSrc = Stop)"
-
else
-
microcode "((#{pins}):DigSrc = Stop)"
-
end
-
end
-
-
# Call this method before each tester cycle to insert the digsrc overlay microcode
-
2
def digsrc_send(pins)
-
72
microcode "((#{format_multiple_instrument_pins(pins)}):DigSrc = SEND)"
-
end
-
-
# Call this method before each tester cycle to inser the digcap overlay microcode
-
2
def digcap_store(pins)
-
microcode "((#{format_multiple_instrument_pins(pins)}):DigCap = STORE)"
-
end
-
-
2
def apply_digsrc_settings(options = {})
-
123
options.merge!(digsrc_width: 1) if options[:digsrc_width].nil? # default to digsrc 1
-
123
options.merge!(digsrc_bit_order: :lsb) if options[:digsrc_bit_order].nil? # default to lsb
-
123
options.merge!(digsrc_mode: :serial) if options[:digsrc_mode].nil? # default to serial mode
-
123
options.merge!(digsrc_format: :binary) if options[:digsrc_format].nil? # default to binary
-
123
options.merge!(digsrc_site_uniqueness: :unique_sites) if options[:digsrc_site_uniqueness].nil? # default to unique sites
-
123
options.merge!(digsrc_data_type: :default) if options[:digsrc_data_type].nil? # default to default
-
123
options.merge!(digsrc_auto_cond: :auto_cond_disable) if options[:digsrc_auto_cond].nil? # default to disable
-
123
@digsrc_settings = options
-
end
-
-
2
def apply_digcap_settings(options = {})
-
123
options.merge!(digcap_width: 8) if options[:digcap_width].nil? # default to digcap 8
-
123
options.merge!(digcap_bit_order: :lsb) if options[:digcap_bit_order].nil? # default to lsb
-
123
options.merge!(digcap_mode: :serial) if options[:digcap_mode].nil? # default to serial mode
-
123
options.merge!(digcap_site_uniqueness: :unique_sites) if options[:digcap_site_uniqueness].nil? # default to unique sites
-
123
options.merge!(digcap_format: :binary) if options[:digcap_format].nil? # default to binary
-
123
options.merge!(digcap_data_type: :default) if options[:digcap_data_type].nil? # default to default
-
123
options.merge!(digcap_auto_cond: :auto_cond_disable) if options[:digcap_auto_cond].nil? # default to disable
-
123
options.merge!(digcap_auto_trig_enable: :auto_trig_disable) if options[:digcap_auto_trig_enable].nil? # default to disable
-
123
options.merge!(digcap_store_stv: :store_stv_disable) if options[:digcap_store_stv].nil? # default to disable
-
123
options.merge!(digcap_receive_data: :store_stv_disable) if options[:digcap_receive_data].nil? # default to logic
-
123
@digcap_settings = options
-
end
-
-
# Call this method if there are more than one pin/pin groups used with an instrument,
-
# this method will format an array of pins into the correct format required by igxl
-
# pattern microcodes.
-
2
def format_multiple_instrument_pins(pins, options = {})
-
76
return_value = ''
-
76
pins.each do |pin|
-
152
return_value += "#{pin}"
-
152
return_value += ',' unless pins.last == pin
-
end
-
76
return_value
-
end
-
-
2
def mask_fails(setclr)
-
102
@mask_vector = setclr
-
end
-
-
# Similar to push_microcode, but for the instrument statement in the pattern header
-
#
-
# @example
-
# tester.push_instrument 'SAR_IN_1', 'UltraSource'
-
# # results in the below line added
-
# # instruments = {
-
# # SAR_IN_1:UltraSource;
-
# # }
-
2
def push_instrument(pin_spec, instrument_def)
-
@pushed_instrument_configs[pin_spec] = instrument_def
-
end
-
-
# Implement subroutine overlay, called by tester.cycle
-
2
def subroutine_overlay(sub_name, options = {})
-
6
if @overlay_subr != sub_name
-
# unless last staged vector already has the subr call do the following
-
5
i = -1
-
5
i -= 1 until stage.bank[i].is_a?(OrigenTesters::Vector)
-
5
if stage.bank[i].microcode !~ /call #{sub_name}/
-
-
# check for repeat on new last vector, unroll 1 if needed
-
5
if stage.bank[i].repeat > 1
-
1
v = OrigenTesters::Vector.new
-
1
v.pin_vals = stage.bank[i].pin_vals
-
1
v.timeset = stage.bank[i].timeset
-
1
stage.bank[i].repeat -= 1
-
1
stage.store(v)
-
1
i = -1
-
end
-
-
# mark last vector as dont_compress
-
5
stage.bank[i].dont_compress = true
-
# insert subroutine call
-
5
call_subroutine sub_name
-
end # if microcode not placed
-
5
@overlay_subr = sub_name
-
end
-
-
# stage = sub_name
-
end # subroutine_overlay
-
-
# Disable the automatic addition of the digsrc start command at the beginning of the pattern
-
#
-
# @example
-
# tester.digsrc_skip_start :pin_or_group_name
-
#
-
2
def digsrc_skip_start(pin_or_group)
-
2
pin_or_group = dut.pin(pin_or_group).name
-
2
if @overlay_history[pin_or_group].nil?
-
2
@overlay_history[pin_or_group] = { count: 0, is_digsrc: true, start_applied: true }
-
else
-
Origen.log.warn 'tester.digsrc_skip_start must be called before any overlay actions on the pin'
-
end
-
end
-
-
# Perform digsrc overlay (called by tester.cycle)
-
2
def digsrc_overlay(options = {})
-
8
options[:overlay] = { change_data: true }.merge(options[:overlay])
-
8
pin_name = dut.pin(options[:overlay][:pins]).name
-
8
repeat_count = options[:repeat].nil? ? 1 : options[:repeat]
-
-
8
if options[:overlay][:change_data]
-
# add the send microcode
-
6
microcode "((#{pin_name}):DigSrc = SEND)"
-
-
# keep track of amount of digsrc used for header comment
-
6
if @overlay_history[pin_name].nil?
-
2
@overlay_history[pin_name] = { count: repeat_count, is_digsrc: true }
-
else
-
4
@overlay_history[pin_name][:count] += repeat_count
-
end
-
-
# ensure no unwanted repeats on the send vector
-
6
options[:dont_compress] = true
-
-
# ensure start microcode is placed at the beginning of the pattern
-
6
if @overlay_history[pin_name][:start_applied].nil?
-
# insert start microcode at the beginning of the pattern
-
2
stage.insert_from_start "((#{pin_name}):DigSrc = Start)", 0
-
2
@overlay_history[pin_name][:start_applied] = true
-
-
# get the first vector of the pattern
-
2
i = 0
-
2
i += 1 until stage.bank[i].is_a?(OrigenTesters::Vector)
-
2
first_vector = stage.bank[i]
-
-
# insert a copy of the first vector with no repeats
-
2
unless first_vector.inline_comment == 'added for digsrc start opcode'
-
1
v = OrigenTesters::Vector.new
-
1
v.pin_vals = stage.bank[i].pin_vals
-
1
v.timeset = stage.bank[i].timeset
-
1
v.inline_comment = 'added for digsrc start opcode'
-
1
v.dont_compress = true
-
1
stage.insert_from_start v, i
-
-
# decrement repeat count of previous first vector if > 1
-
1
first_vector.repeat -= 1 if first_vector.repeat > 1
-
end
-
-
# get cycle count up to this point, add repeat to beginning if needed
-
2
cycle_count = -1
-
29
stage.bank.each { |v| cycle_count += v.repeat if v.is_a?(OrigenTesters::Vector) }
-
2
if cycle_count < @dssc_send_delay
-
1
d = OrigenTesters::Vector.new
-
1
d.pin_vals = first_vector.pin_vals
-
1
d.timeset = first_vector.timeset
-
1
d.inline_comment = 'added for dssc start to send delay'
-
1
d.repeat = @dssc_send_delay - cycle_count
-
-
# get the first vector of the pattern
-
1
i = 0
-
1
i += 1 until stage.bank[i].is_a?(OrigenTesters::Vector)
-
-
# insert new vector after the first vector
-
1
stage.insert_from_start d, i + 1
-
end
-
-
end # of place start microcode
-
-
end # if options[:change_data]
-
8
options
-
end # digsrc overlay
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class ACSpecsets
-
2
include ::OrigenTesters::Generator
-
-
2
attr_accessor :ac_specs
-
2
attr_accessor :ac_specsets
-
-
2
OUTPUT_PREFIX = 'SpecsAC'
-
# OUTPUT_POSTFIX = 'SpecsAC'
-
-
2
def initialize # :nodoc:
-
## Hash Autovivification
-
25
l = ->(h, k) { h[k] = Hash.new(&l) }
-
-
1
@ac_specs = []
-
1
@ac_specsets = Hash.new(&l)
-
end
-
-
# Assigns an AC spec value object to the given variable for this specset
-
# The attrs hash is expected to defined as follows:
-
# attrs = {
-
# specset: :specset_name, # if not defined, specset = :default
-
# # Spec selectors that contain both the scope and value of the spec
-
# nom: { typ: 1.8 }, # typ is an example of the UFlex scope, nom is the spec selector
-
# min: { min: 1.7 }, # Users can defined any number of selectors in this fashion
-
# max: { max: 1.9 }
-
# }
-
2
def add(spec, attrs = {})
-
attrs = {
-
9
specset: :default
-
}.merge(attrs)
-
-
9
specset = attrs.delete(:specset)
-
-
9
@ac_specs << spec unless @ac_specs.include?(spec)
-
-
9
attrs.each do |selector, value|
-
9
@ac_specsets[specset][spec][selector] = value
-
end
-
end
-
-
# Prepare the spec information for file output
-
2
def format_uflex_ac_spec(data, options = {})
-
63
case data
-
when NilClass
-
51
data_new = 0
-
when Fixnum, Float
-
case
-
when data == 0
-
data_new = data.to_s
-
when data.abs < 1e-9
-
data_new = (data * 1_000_000_000_000).round(4).to_s + '*ps'
-
when data.abs < 1e-6
-
data_new = (data * 1_000_000_000).round(4).to_s + '*ns'
-
when data.abs < 1e-3
-
data_new = (data * 1_000_000).round(4).to_s + '*us'
-
when data.abs < 1
-
data_new = (data * 1_000).round(4).to_s + '*ms'
-
else
-
data_new = data.to_s
-
end
-
data_new = data_new.gsub(/^/, '=')
-
when String
-
12
data_new = data.gsub(/^/, '=').gsub(/(\W)([a-zA-Z])/, '\1_\2')
-
# Remove underscores from unit designations
-
12
data_new.gsub!(/(\W)_(nS|uS|mS|S)(\W)/i, '\1\2\3')
-
12
data_new.gsub!(/(\W)_(nS|uS|mS|S)$/i, '\1\2')
-
else
-
Origen.log.error "Unknown class type (#{data.class}) for spec value: #{data}"
-
fail
-
end
-
63
data_new
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class CustomTestInstance
-
2
attr_accessor :type, :index, :version, :append_version, :finalize
-
-
# Returns the object representing the test instance library that the
-
# given test instance is defined in
-
2
attr_reader :library
-
-
2
def self.define
-
# Generate accessors for all attributes and their aliases
-
6
attrs.each do |attr|
-
660
writer = "#{attr}=".to_sym
-
660
reader = attr.to_sym
-
660
attr_reader attr.to_sym unless method_defined? reader
-
660
attr_writer attr.to_sym unless method_defined? writer
-
end
-
-
# Define the common aliases now, the instance type specific ones will
-
# be created when the instance type is known
-
6
self::TEST_INSTANCE_ALIASES.each do |_alias, val|
-
24
writer = "#{_alias}=".to_sym
-
24
reader = _alias.to_sym
-
24
unless val.is_a? Hash
-
24
unless method_defined? writer
-
18
define_method("#{_alias}=") do |v|
-
send("#{val}=", v)
-
end
-
end
-
24
unless method_defined? reader
-
18
define_method("#{_alias}") do
-
send(val)
-
end
-
end
-
end
-
end
-
end
-
-
2
def self.attrs
-
15
@attrs ||= begin
-
6
attrs = self::TEST_INSTANCE_ATTRS.dup
-
-
6
self::TEST_INSTANCE_EXTRA_ARGS.times do |i|
-
580
attrs << "arg#{i}"
-
end
-
6
attrs << 'comment'
-
6
attrs
-
end
-
end
-
-
2
def initialize(name, options = {})
-
9
@append_version = true
-
9
self.name = name
-
# Add any methods
-
9
if options[:methods][:methods]
-
9
methods = options[:methods][:methods]
-
9
@finalize = methods[:finalize]
-
9
methods.each do |method_name, function|
-
18
unless method_name == :finalize
-
9
var_name = "@#{method_name}".gsub(/=|\?/, '_')
-
9
instance_variable_set(var_name, function)
-
9
define_singleton_method method_name do |*args|
-
9
instance_variable_get(var_name).call(self, *args)
-
end
-
end
-
end
-
end
-
# Create attributes corresponding to the test method type represented
-
# by this method instance
-
9
options[:methods].each do |attr, arg_default|
-
63
arg_default = [arg_default] unless arg_default.is_a?(Array)
-
63
unless attr == :aliases || attr == :methods
-
45
clean_attr = clean_attr_name(attr)
-
45
arg = arg_default[0]
-
45
default = arg_default[1]
-
45
allowed = arg_default[2]
-
45
aliases = [clean_attr]
-
45
aliases << clean_attr.underscore if clean_attr.underscore != clean_attr
-
45
aliases.each do |alias_|
-
45
define_singleton_method("#{alias_}=") do |v|
-
36
if allowed
-
9
unless allowed.include?(v)
-
fail "Cannot set #{alias_} to #{v}, valid values are: #{allowed.join(', ')}"
-
end
-
end
-
36
instance_variable_set("@#{arg}", v)
-
end
-
45
define_singleton_method(alias_) do
-
instance_variable_get("@#{arg}")
-
end
-
end
-
45
send("#{arg}=", default)
-
end
-
end
-
9
if options[:methods][:aliases]
-
9
options[:methods][:aliases].each do |alias_, attr|
-
27
clean_attr = clean_attr_name(attr)
-
27
define_singleton_method("#{alias_}=") do |v|
-
9
send("#{clean_attr}=", v)
-
end
-
27
define_singleton_method(alias_) do
-
send(clean_attr)
-
end
-
end
-
end
-
# Set the defaults
-
9
self.class::TEST_INSTANCE_DEFAULTS.each do |k, v|
-
18
send("#{k}=", v) if self.respond_to?("#{k}=", v)
-
end
-
# Finally set any initial values that have been supplied
-
9
options[:attrs].each do |k, v|
-
send("#{k}=", v) if respond_to?("#{k}=")
-
end
-
end
-
-
2
def ==(other_instance)
-
9
self.class == other_instance.class &&
-
unversioned_name.to_s == other_instance.unversioned_name.to_s &&
-
self.class.attrs.all? do |attr|
-
# Exclude test name, already examined above and don't want to include
-
# the version in the comparison
-
if attr == 'test_name'
-
true
-
else
-
send(attr) == other_instance.send(attr)
-
end
-
end
-
end
-
-
# Returns the fully formatted test instance for insertion into an instance sheet
-
2
def to_s(override_name = nil)
-
9
l = "\t"
-
9
self.class.attrs.each do |attr|
-
990
if attr == 'test_name' && override_name
-
l += "#{override_name}\t"
-
else
-
990
l += "#{send(attr)}\t"
-
end
-
end
-
9
"#{l}"
-
end
-
-
2
def name
-
39
if version && @append_version
-
"#{@test_name}_v#{version}"
-
else
-
39
@test_name.to_s
-
end
-
end
-
2
alias_method :test_name, :name
-
-
2
def name=(val)
-
9
self.test_name = val
-
end
-
-
2
def unversioned_name
-
63
@test_name.to_s
-
end
-
-
2
private
-
-
2
def clean_attr_name(name)
-
72
name.to_s.gsub(/\.|-/, '_')
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class DCSpecsets
-
2
include ::OrigenTesters::Generator
-
-
2
attr_accessor :dc_specs
-
2
attr_accessor :dc_specsets
-
-
2
OUTPUT_PREFIX = 'SpecsDC'
-
# OUTPUT_POSTFIX = 'SpecsDC'
-
-
2
def initialize # :nodoc:
-
## Hash Autovivification
-
25
l = ->(h, k) { h[k] = Hash.new(&l) }
-
-
1
@dc_specs = []
-
1
@dc_specsets = Hash.new(&l)
-
end
-
-
# Assigns a DC spec value object to the given variable for this specset
-
# The attrs hash is expected to defined as follows:
-
# attrs = {
-
# specset: :specset_name, # if not defined, specset = :default
-
# # Spec selectors that contain both the scope and value of the spec
-
# nom: { typ: 1.8 }, # typ is an example of the UFlex scope, nom is the spec selector
-
# min: { min: 1.7 }, # Users can defined any number of selectors in this fashion
-
# max: { max: 1.9 }
-
# }
-
2
def add(spec, attrs = {})
-
attrs = {
-
38
specset: :default
-
}.merge(attrs)
-
-
38
specset = attrs.delete(:specset)
-
-
38
@dc_specs << spec unless @dc_specs.include?(spec)
-
-
38
attrs.each do |selector, value|
-
114
@dc_specsets[specset][spec][selector] = value
-
end
-
end
-
-
# Prepare the spec information for file output
-
2
def format_uflex_dc_spec(data, options = {})
-
options = {
-
63
spec: nil
-
}.update(options)
-
-
63
case options[:spec]
-
when /(voh|vol|vt|vcl|vch|vdd)/i
-
36
spec_type = 'volt'
-
when /(ioh|iol)/i
-
spec_type = 'curr'
-
else
-
27
spec_type = nil
-
end
-
-
63
case data
-
when NilClass
-
51
data_new = 0
-
when Fixnum, Float
-
case
-
when data == 0
-
data_new = data.to_s
-
when data.abs < 1e-6
-
data_new = (data * 1_000_000_000).round(4).to_s + '*nV' if spec_type == 'volt'
-
data_new = (data * 1_000_000_000).round(4).to_s + '*nA' if spec_type == 'curr'
-
data_new = data.to_s if spec_type.nil?
-
when data.abs < 1e-3
-
data_new = (data * 1_000_000).round(4).to_s + '*uV' if spec_type == 'volt'
-
data_new = (data * 1_000_000).round(4).to_s + '*uA' if spec_type == 'curr'
-
data_new = data.to_s if spec_type.nil?
-
when data.abs < 1
-
data_new = data.to_s + '*V' if spec_type == 'volt'
-
data_new = (data * 1_000).round(4).to_s + '*mA' if spec_type == 'curr'
-
data_new = data.to_s if spec_type.nil?
-
else
-
data_new = data.to_s + '*V' if spec_type == 'volt'
-
data_new = data.to_s + '*A' if spec_type == 'curr'
-
data_new = data.to_s if spec_type.nil?
-
end
-
data_new = data_new.gsub(/^/, '=')
-
when String
-
12
data_new = data.gsub(/^/, '=').gsub(/(\W)([a-zA-Z])/, '\1_\2')
-
# Remove underscores from unit designations
-
12
data_new.gsub!(/(\W)_(nV|uV|mV|V|nA|uA|mA|A)(\W)/i, '\1\2\3')
-
12
data_new.gsub!(/(\W)_(nV|uV|mV|V|nA|uA|mA|A)$/i, '\1\2')
-
else
-
Origen.log.error "Unknown class type (#{data.class}) for spec value: #{data}"
-
fail
-
end
-
63
data_new
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class Edge
-
2
attr_accessor :d_src, :d_fmt, :d0_edge, :d1_edge, :d2_edge, :d3_edge # Input pin timing information
-
2
attr_accessor :c_mode, :c1_edge, :c2_edge # Output pin timing information
-
2
attr_accessor :t_res, :clk_per
-
-
2
def initialize(options = {}) # :nodoc:
-
options = {
-
4
d_src: 'PAT', # source of the channel drive data (e.g. pattern, drive_hi, drive_lo, etc.)
-
d_fmt: 'NR', # drive data format (NR, RL, RH, etc.)
-
d0_edge: '', # time at which the input drive is turned on
-
d1_edge: '', # time of the initial data drive edge
-
d2_edge: '', # time of the return format data drive edge
-
d3_edge: '', # time at which the input drive is turned off
-
c_mode: 'Edge', # output compare mode
-
c1_edge: '', # time of the initial output compare edge
-
c2_edge: '', # time of the final output compare edge (window compare)
-
t_res: 'Machine', # timing resolution (possibly ATE-specific)
-
clk_per: '' # clock period equation - for use with MCG
-
}.merge(options)
-
4
@d_src = options[:d_src]
-
4
@d_fmt = options[:d_fmt]
-
4
@d0_edge = options[:d0_edge]
-
4
@d1_edge = options[:d1_edge]
-
4
@d2_edge = options[:d2_edge]
-
4
@d3_edge = options[:d3_edge]
-
4
@c_mode = options[:c_mode]
-
4
@c1_edge = options[:c1_edge]
-
4
@c2_edge = options[:c2_edge]
-
4
@t_res = options[:t_res]
-
4
@clk_per = options[:clk_per]
-
end
-
-
2
def ==(edge)
-
if edge.is_a? Edge
-
d_src == edge.d_src &&
-
d_fmt == edge.d_fmt &&
-
d0_edge == edge.d0_edge &&
-
d1_edge == edge.d1_edge &&
-
d2_edge == edge.d2_edge &&
-
d3_edge == edge.d3_edge &&
-
c_mode == edge.c_mode &&
-
c1_edge == edge.c1_edge &&
-
c2_edge == edge.c2_edge &&
-
t_res == edge.t_res &&
-
clk_per == edge.clk_per
-
else
-
super
-
end
-
end
-
-
2
def platform
-
Origen.interface.platform
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class Edges
-
2
include ::OrigenTesters::Generator
-
-
2
attr_accessor :edges
-
-
2
def initialize(options = {}) # :nodoc:
-
1
@edges = Hash.new do |h, k|
-
4
h[k] = {}
-
end
-
end
-
-
# Defines a new Edge object for the category and pin name
-
2
def add(grp, pin, options = {})
-
4
grp = grp.to_sym unless grp.is_a? Symbol
-
4
pin = pin.to_sym unless pin.is_a? Symbol
-
4
edges[grp][pin] = platform::Edge.new(options)
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class Edgeset
-
2
attr_accessor :period, :t_mode # Edgeset information
-
2
attr_accessor :pins
-
2
attr_accessor :spec_sheet
-
2
attr_accessor :name
-
-
2
def initialize(name, pin, edge, attrs = {}) # :nodoc:
-
attrs = {
-
4
period: '', # tester cycle duration
-
t_mode: '', # timing mode (possibly ATE-specific)
-
spec_sheet: 'default' # defines which specset sheet to put variables in (e.g. func, scan) when generating specset files
-
}.merge(attrs)
-
4
@period = attrs[:period]
-
4
@t_mode = attrs[:t_mode]
-
4
@spec_sheet = attrs[:spec_sheet]
-
4
@pins = { pin => edge }
-
4
self.name = name
-
end
-
-
# Assigns a timing edge object to the given pin for this edgeset
-
2
def add_edge(pin, edge)
-
12
if @pins.key?(pin)
-
Origen.log.error "Pin #{pin} already exists in edgeset"
-
fail
-
else
-
12
@pins[pin] = edge
-
end
-
end
-
-
2
def platform
-
Origen.interface.platform
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class Edgesets
-
2
include ::OrigenTesters::Generator
-
-
2
attr_accessor :es
-
2
attr_accessor :es_sheet_pins
-
2
attr_accessor :ts_basic
-
-
2
OUTPUT_PREFIX = 'ES'
-
# OUTPUT_POSTFIX = 'ES'
-
-
2
def initialize(options = {}) # :nodoc:
-
2
@es = {}
-
2
@ts_basic = options[:timeset_basic]
-
end
-
-
2
def add(esname, pin, edge, options = {})
-
16
esname = esname.to_sym unless esname.is_a? Symbol
-
16
pin = pin.to_sym unless pin.is_a? Symbol
-
16
@es.key?(esname) ? @es[esname].add_edge(pin, edge) : @es[esname] = platform::Edgeset.new(esname, pin, edge, options)
-
16
@es_sheet_pins = options[:es_sheet_pins] unless @es_sheet_pins
-
16
@es
-
end
-
-
2
def finalize(options = {})
-
end
-
-
# Populate an array of pins based on the pin or pingroup
-
2
def get_pin_objects(grp)
-
12
pins = []
-
12
if Origen.top_level.pin(grp).is_a?(Origen::Pins::Pin) ||
-
Origen.top_level.pin(grp).is_a?(Origen::Pins::FunctionProxy)
-
12
pins << Origen.top_level.pin(grp)
-
elsif Origen.top_level.pin(grp).is_a?(Origen::Pins::PinCollection)
-
Origen.top_level.pin(grp).each do |pin|
-
pins << pin
-
end
-
else
-
Origen.log.error "Could not find pin class: #{grp} #{Origen.top_level.pin(grp).class}"
-
end
-
12
pins
-
end
-
-
# Equality check to compare full contents of edge object
-
2
def edges_eql?(edge1, edge2)
-
edge1 == edge2
-
end
-
-
# Globally modify text within the edge object
-
2
def gsub_edges!(edge, old_val, new_val)
-
edge.d_src = edge.d_src.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
edge.d_fmt = edge.d_fmt.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
edge.d0_edge = edge.d0_edge.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
edge.d1_edge = edge.d1_edge.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
edge.d2_edge = edge.d2_edge.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
edge.d3_edge = edge.d3_edge.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
edge.c_mode = edge.c_mode.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
edge.c1_edge = edge.c1_edge.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
edge.c2_edge = edge.c2_edge.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
edge.t_res = edge.t_res.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
edge.clk_per = edge.clk_per.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
end
-
-
# Prepare the edge information for ES/TS file output
-
2
def format_uflex_edge(data, line_cnt, options = {})
-
options = {
-
88
no_disable: false
-
}.merge(options)
-
-
88
if data !~ /^\s*$/
-
34
data = data.gsub(/^/, '=')
-
end
-
88
data = data.gsub(/(\W)([a-zA-Z])/, '\1_\2')
-
-
88
case data
-
when /_d0_edge|_d_on/
-
data = data.gsub(/_d0_edge|_d_on/, "F#{line_cnt}")
-
when /_d1_edge|_d_data/
-
8
data = data.gsub(/_d1_edge|_d_data/, "G#{line_cnt}")
-
when /_d2_edge|_dret/
-
data = data.gsub(/_d2_edge|_dret/, "H#{line_cnt}")
-
when /_d3_edge|_d_off/
-
data = data.gsub(/_d3_edge|_d_off/, "I#{line_cnt}")
-
when /_c1_edge|_c_open/
-
data = data.gsub(/_c1_edge|_c_open/, "K#{line_cnt}")
-
when /_c2_edge|_c_close/
-
data = data.gsub(/_c2_edge|_c_close/, "L#{line_cnt}")
-
when /^\s*$/
-
54
options[:no_disable] ? data = '' : data = 'disable'
-
else
-
26
data
-
end
-
end
-
-
# Prepare the edge information for TSB file output
-
2
def format_uflex_edge_tsb(data, line_cnt, options = {})
-
options = {
-
64
no_disable: false
-
}.merge(options)
-
-
64
if data !~ /^\s*$/
-
31
data = data.gsub(/^/, '=')
-
end
-
64
data = data.gsub(/(\W)([a-zA-Z])/, '\1_\2')
-
-
64
case data
-
when /_d0_edge|_d_on/
-
data = data.gsub(/_d0_edge|_d_on/, "I#{line_cnt}")
-
when /_d1_edge|_d_data/
-
8
data = data.gsub(/_d1_edge|_d_data/, "J#{line_cnt}")
-
when /_d2_edge|_dret/
-
data = data.gsub(/_d2_edge|_dret/, "K#{line_cnt}")
-
when /_d3_edge|_d_off/
-
data = data.gsub(/_d3_edge|_d_off/, "L#{line_cnt}")
-
when /_c1_edge|_c_open/
-
data = data.gsub(/_c1_edge|_c_open/, "N#{line_cnt}")
-
when /_c2_edge|_c_close/
-
data = data.gsub(/_c2_edge|_c_close/, "O#{line_cnt}")
-
when /^\s*$/
-
33
options[:no_disable] ? data = '' : data = 'disable'
-
else
-
23
data
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class Flow < ATP::Formatter
-
2
include OrigenTesters::Flow
-
-
2
OUTPUT_POSTFIX = 'flow'
-
-
2
attr_reader :branch
-
2
attr_reader :stack
-
2
attr_reader :context
-
# Keeps a note of the context under which flags where set
-
2
attr_reader :set_flags
-
2
attr_accessor :current_flag
-
2
attr_accessor :current_enable
-
-
2
class FlowLineAPI
-
2
def initialize(flow)
-
2
@flow = flow
-
end
-
-
2
def method_missing(method, *args, &block)
-
2
if Base::FlowLine::DEFAULTS.key?(method.to_sym)
-
2
line = @flow.platform::FlowLine.new(method, *args)
-
2
@flow.render(line)
-
2
line
-
else
-
super
-
end
-
end
-
-
2
def respond_to?(method)
-
!!Base::FlowLine::DEFAULTS.key?(method.to_sym)
-
end
-
end
-
-
2
class TestCounter < ATP::Processor
-
2
def run(node)
-
85
@tests = 0
-
85
process(node)
-
85
@tests
-
end
-
-
2
def on_test(node)
-
186
@tests += 1
-
end
-
end
-
-
# Returns the API to manually generate an IG-XL flow line
-
2
def ultraflex
-
2
@flow_line_api ||= FlowLineAPI.new(self)
-
end
-
2
alias_method :uflex, :ultraflex
-
2
alias_method :j750, :ultraflex
-
-
2
def number_of_tests_in(node)
-
85
@test_counter ||= TestCounter.new
-
85
@test_counter.run(node)
-
end
-
-
# Will be called at the end to transform the final flow model into an array
-
# of lines to be rendered to the IG-XL flow sheet
-
2
def format
-
23
@lines = []
-
23
@stack = { jobs: [] }
-
23
@context = []
-
23
@set_flags = {}
-
23
ast = atp.ast(unique_id: sig, optimization: :igxl)
-
23
process(ast)
-
23
lines
-
end
-
-
2
def on_flow(node)
-
23
name, *nodes = *node
-
23
process_all(nodes)
-
end
-
-
2
def on_test(node)
-
2108
line = new_line(:test) { |l| process_all(node) }
-
-
# In IG-XL you can't set the same flag in case of pass or fail, that situation should
-
# never occur unless the user has manually set up that condition
-
1054
if line.flag_fail && line.flag_fail == line.flag_pass
-
fail "You can't set the same flag on test pass and fail in IG-XL!"
-
else
-
1054
completed_lines << line
-
end
-
end
-
-
2
def on_cz(node)
-
15
setup, test = *node
-
15
completed_lines << new_line(:cz, cz_setup: setup) do |line|
-
15
process_all(test)
-
end
-
end
-
-
2
def on_name(node)
-
987
current_line.tname = node.to_a[0] if current_line
-
end
-
-
2
def on_number(node)
-
1060
if Origen.tester.diff_friendly_output?
-
current_line.tnum = 0
-
else
-
1060
current_line.tnum = node.to_a[0]
-
end
-
end
-
-
2
def on_object(node)
-
1079
instance = node.to_a[0]
-
1079
if instance.is_a?(String)
-
163
current_line.instance_variable_set('@ignore_missing_instance', true)
-
end
-
1079
current_line.parameter = instance
-
end
-
-
2
def on_continue(node)
-
273
current_line.result = 'None' if current_line
-
end
-
-
2
def on_set_flag(node)
-
365
flag = clean_flag(node.to_a[0])
-
365
set_previously = !!set_flags[flag]
-
365
set_flags[flag] = context.dup
-
365
if current_line
-
273
if branch == :on_fail
-
193
current_line.flag_fail = flag
-
else
-
80
current_line.flag_pass = flag
-
end
-
else
-
92
if !set_previously && !global_flags.include?(flag)
-
58
completed_lines << platform::FlowLine.new(:defaults, flag_fail: flag)
-
end
-
92
completed_lines << new_line(:flag_true, parameter: flag)
-
end
-
end
-
-
2
def on_set_result(node)
-
280
bin = node.find(:bin).try(:value)
-
280
desc = node.find(:bin).to_a[1]
-
280
sbin = node.find(:softbin).try(:value)
-
280
if current_line
-
253
if branch == :on_fail
-
253
current_line.bin_fail = bin
-
253
current_line.sort_fail = sbin
-
253
current_line.comment = desc
-
253
current_line.result = 'Fail'
-
else
-
current_line.bin_pass = bin
-
current_line.sort_pass = sbin
-
current_line.comment = desc
-
current_line.result = 'Pass'
-
end
-
else
-
27
line = new_line(:set_device)
-
27
if node.to_a[0] == 'pass'
-
6
line.bin_pass = bin
-
6
line.sort_pass = sbin
-
6
line.result = 'Pass'
-
else
-
21
line.bin_fail = bin
-
21
line.sort_fail = sbin
-
21
line.result = 'Fail'
-
end
-
27
line.comment = desc
-
27
completed_lines << line
-
end
-
end
-
-
2
def on_on_fail(node)
-
437
@branch = :on_fail
-
437
process_all(node)
-
437
@branch = nil
-
end
-
-
2
def on_on_pass(node)
-
80
@branch = :on_pass
-
80
process_all(node)
-
80
@branch = nil
-
end
-
-
2
def on_if_job(node)
-
48
jobs, *nodes = *node
-
48
jobs = clean_job(jobs)
-
48
state = node.type == :if_job
-
48
unless state
-
36
jobs = jobs.map { |j| "!#{j}" }
-
end
-
48
stack[:jobs] << [stack[:jobs].last, jobs].compact.join(',')
-
48
context << stack[:jobs].last
-
48
process_all(node)
-
48
stack[:jobs].pop
-
48
context.pop
-
end
-
2
alias_method :on_unless_job, :on_if_job
-
-
2
def on_if_flag(node)
-
323
flag, *nodes = *node
-
323
orig = current_flag
-
323
state = node.type == :if_flag
-
323
if flag.is_a?(Array)
-
20
or_flag = flag.join('_OR_')
-
20
or_flag = "NOT_#{flag}" unless state
-
20
flag.each do |f|
-
40
if current_flag
-
fail 'Not implemented yet!'
-
else
-
40
set_previously = !!set_flags[or_flag]
-
40
set_flags[or_flag] = context
-
40
self.current_flag = [f, state]
-
40
unless set_previously
-
20
completed_lines << platform::FlowLine.new(:defaults, flag_fail: or_flag)
-
end
-
40
completed_lines << new_line(:flag_true, parameter: or_flag)
-
40
self.current_flag = nil
-
end
-
end
-
20
flag = or_flag
-
end
-
323
flag = clean_flag(flag)
-
-
# If a flag condition is currently active
-
323
if current_flag
-
# If the current flag condition also gated the setting of this node's flag, then we
-
# don't need to create an AND flag
-
48
if !set_flags[flag] || (set_flags[flag] && set_flags[flag].hash != context.hash)
-
31
and_flag = clean_flag(flag_to_s(*current_flag) + '_AND_' + flag_to_s(flag, state))
-
# If the AND flag has already been created and set in this context (for a previous test),
-
# no need to re-create it
-
31
if !set_flags[and_flag] || (set_flags[and_flag].hash != context.hash)
-
31
set_previously = !!set_flags[and_flag]
-
31
set_flags[and_flag] = context
-
31
existing_flag = current_flag
-
31
self.current_flag = nil
-
31
unless set_previously
-
31
completed_lines << platform::FlowLine.new(:defaults, flag_fail: and_flag)
-
end
-
31
completed_lines << new_line(:flag_true, parameter: and_flag)
-
31
self.current_flag = [flag, !state]
-
31
completed_lines << new_line(:flag_false, parameter: and_flag)
-
31
self.current_flag = [existing_flag[0], !existing_flag[1]]
-
31
completed_lines << new_line(:flag_false, parameter: and_flag)
-
end
-
31
flag = and_flag
-
end
-
end
-
-
# Update the currently active flag condition, this will be added as a condition to all
-
# lines created from children of this node
-
323
self.current_flag = [flag, state]
-
323
context << current_flag
-
323
process_all(node)
-
323
context.pop
-
323
self.current_flag = orig
-
end
-
2
alias_method :on_unless_flag, :on_if_flag
-
-
2
def on_if_any_sites_flag(node)
-
15
flag, *nodes = *node
-
15
state = [:if_any_sites_flag, :if_all_sites_flag].include?(node.type)
-
15
flag = clean_flag(flag)
-
-
# If a flag condition is currently active
-
15
if current_flag
-
fail 'Nesting of if_any_sites/if_all_sites conditions with other flag conditions is not supported yet, please create a ticket here if you need this functionality: https://github.com/Origen-SDK/origen_testers/issues'
-
end
-
-
# Update the currently active flag condition, this will be added as a condition to all
-
# lines created from children of this node
-
15
if node.type.to_s =~ /any/
-
9
self.current_flag = [flag, state, :any]
-
else
-
6
self.current_flag = [flag, state, :all]
-
end
-
15
context << current_flag
-
15
process_all(node)
-
15
context.pop
-
15
self.current_flag = nil
-
end
-
2
alias_method :on_if_all_sites_flag, :on_if_any_sites_flag
-
-
2
def on_if_enabled(node)
-
116
flag, *nodes = *node
-
116
orig = current_enable
-
116
value = node.type == :if_enabled
-
116
if flag.is_a?(Array)
-
9
flag.map! { |a_flag| clean_enable(a_flag) }
-
3
if flag.size > 1
-
3
or_flag = flag.join('_OR_')
-
3
flag.each do |f|
-
6
completed_lines << new_line(:enable_flow_word, parameter: or_flag, enable: f)
-
end
-
3
flag = or_flag
-
else
-
flag = flag.first
-
end
-
else
-
113
flag = clean_enable(flag)
-
end
-
116
if value
-
# IG-XL docs say that enable words are not optimized for test time, so branch around
-
# large blocks to minimize enable word evaluation
-
85
if number_of_tests_in(node) > 5
-
6
label = generate_unique_label
-
6
branch_if_enable(flag) do
-
6
completed_lines << new_line(:goto, parameter: label, enable: nil)
-
end
-
6
context << flag
-
6
process_all(node)
-
6
context.pop
-
6
completed_lines << new_line(:nop, label: label, enable: nil)
-
else
-
79
if current_enable
-
9
and_flag = "#{current_enable}_AND_#{flag}"
-
9
label = generate_unique_label
-
9
branch_if_enable(current_enable) do
-
9
completed_lines << new_line(:goto, parameter: label, enable: nil)
-
end
-
9
completed_lines << new_line(:enable_flow_word, parameter: and_flag, enable: flag)
-
9
completed_lines << new_line(:nop, label: label, enable: nil)
-
9
self.current_enable = and_flag
-
9
context << and_flag
-
9
process_all(node)
-
9
context.pop
-
9
self.current_enable = orig
-
else
-
70
self.current_enable = flag
-
70
context << flag
-
70
process_all(node)
-
70
context.pop
-
70
self.current_enable = orig
-
end
-
end
-
else
-
# IG-XL does not have a !enable option, so generate a branch around the tests
-
# to be skipped unless the required flag is enabled
-
31
context << "!#{flag}"
-
31
branch_if_enable(flag) do
-
31
process_all(node)
-
end
-
31
context.pop
-
end
-
end
-
2
alias_method :on_unless_enabled, :on_if_enabled
-
-
2
def branch_if_enable(word)
-
46
label = generate_unique_label
-
46
completed_lines << new_line(:goto, parameter: label, enable: word)
-
46
yield
-
46
completed_lines << new_line(:nop, label: label, enable: nil)
-
end
-
-
2
def on_enable(node)
-
6
completed_lines << new_line(:enable_flow_word, parameter: node.value)
-
end
-
-
2
def on_disable(node)
-
3
completed_lines << new_line(:disable_flow_word, parameter: node.value)
-
end
-
-
2
def on_log(node)
-
293
completed_lines << new_line(:logprint, parameter: node.to_a[0].gsub(' ', '_'))
-
end
-
-
2
def on_render(node)
-
4
completed_lines << node.to_a[0]
-
end
-
-
2
def new_line(type, attrs = {})
-
attrs = {
-
1760
job: stack[:jobs].last,
-
enable: current_enable
-
}.merge(attrs)
-
1760
line = platform::FlowLine.new(type, attrs)
-
1760
if current_flag
-
# If any/all sites condition
-
517
if current_flag[2]
-
18
line.group_sense = 'not' unless current_flag[1]
-
18
line.group_specifier = "#{current_flag[2]}-active"
-
18
line.group_name = clean_flag(current_flag[0])
-
18
line.group_condition = 'flag-true'
-
else
-
499
line.device_sense = 'not' unless current_flag[1]
-
499
line.device_name = clean_flag(current_flag[0])
-
499
line.device_condition = 'flag-true'
-
end
-
end
-
1760
open_lines << line
-
1760
yield line if block_given?
-
1760
open_lines.pop
-
1760
line
-
end
-
-
# Any completed lines should be pushed to the array that this returns
-
2
def completed_lines
-
1942
lines
-
end
-
-
2
def open_lines
-
10251
@open_lines ||= []
-
end
-
-
2
def current_line
-
6701
open_lines.last
-
end
-
-
2
def clean_job(job)
-
111
[job].flatten.map { |j| j.to_s.upcase }
-
end
-
-
2
def flag_to_s(flag, state)
-
62
if state
-
59
flag
-
else
-
3
"NOT_#{flag}"
-
end
-
end
-
-
2
private
-
-
2
def clean_enable(flag)
-
119
flag = flag.to_s
-
119
if flag[0] == '$'
-
6
flag[0] = ''
-
6
flag
-
else
-
113
if tester.literal_enables
-
8
flag
-
else
-
105
flag.downcase
-
end
-
end
-
end
-
-
2
def clean_flag(flag)
-
# Added .dup to below line to get an unfrozen copy of the string, corrects a run time error
-
1251
flag = flag.to_s.dup
-
1251
if flag[0] == '$'
-
60
flag[0] = ''
-
end
-
1251
flag
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class FlowLine
-
2
attr_accessor :type, :id, :cz_setup # cz_setup is a virtual attrib since it is not part of the regular flow line
-
# cz_setup combine with instance name when characterize opcode is used
-
-
# Map any aliases to the official names here, multiple aliases for a given attribute
-
# are allowed
-
ALIASES = {
-
2
bin: :bin_fail,
-
softbin: :sort_fail,
-
soft_bin: :sort_fail,
-
sbin: :sort_fail,
-
name: :tname,
-
number: :tnum,
-
if_enable: :enable,
-
if_enabled: :enable,
-
enabled: :enable,
-
hi_limit: :hilim,
-
hi: :hilim,
-
lo_limit: :lolim,
-
lo: :lolim,
-
# Aliases can also be used to set defaults on multiple attributes like this,
-
# use :value to refer to the value passed in to the given alias
-
flag_false: { device_condition: 'flag-false',
-
device_name: :value
-
},
-
flag_true: { device_condition: 'flag-true',
-
device_name: :value
-
},
-
flag_false_any: { group_specifier: 'any-active',
-
group_condition: 'flag-false',
-
group_name: :value
-
},
-
flag_false_all: { group_specifier: 'all-active',
-
group_condition: 'flag-false',
-
group_name: :value
-
},
-
flag_true_any: { group_specifier: 'any-active',
-
group_condition: 'flag-true',
-
group_name: :value
-
},
-
flag_true_all: { group_specifier: 'all-active',
-
group_condition: 'flag-true',
-
group_name: :value
-
},
-
flag_clear: { device_condition: 'flag-clear',
-
device_name: :value
-
}
-
}
-
-
# Assign attribute defaults here, generally this should match whatever defaults
-
# Teradyne has set whenever you create a new test instance, etc.
-
DEFAULTS = {
-
2
test: {
-
opcode: 'Test',
-
result: 'Fail'
-
},
-
test_defer_limits: {
-
opcode: 'Test-defer-limits',
-
result: 'Fail'
-
},
-
cz: {
-
opcode: 'characterize',
-
result: 'None'
-
},
-
goto: {
-
opcode: 'goto'
-
},
-
nop: {
-
opcode: 'nop'
-
},
-
set_device: {
-
opcode: 'set-device'
-
},
-
set_error_bin: {
-
opcode: 'set-error-bin'
-
},
-
enable_flow_word: {
-
opcode: 'enable-flow-word'
-
},
-
disable_flow_word: {
-
opcode: 'disable-flow-word'
-
},
-
logprint: {
-
opcode: 'logprint'
-
},
-
use_limit: {
-
opcode: 'Use-Limit',
-
result: 'Fail'
-
},
-
flag_false: {
-
opcode: 'flag-false'
-
},
-
flag_false_all: {
-
opcode: 'flag-false-all'
-
},
-
flag_true: {
-
opcode: 'flag-true'
-
},
-
flag_true_all: {
-
opcode: 'flag-true-all'
-
},
-
defaults: {
-
opcode: 'defaults'
-
}
-
}
-
-
2
def self.define
-
# Generate accessors for all attributes and their aliases
-
4
self::TESTER_FLOWLINE_ATTRS.each do |attr|
-
118
writer = "#{attr}=".to_sym
-
118
reader = attr.to_sym
-
118
attr_reader attr.to_sym unless method_defined? reader
-
118
attr_writer attr.to_sym unless method_defined? writer
-
end
-
-
4
ALIASES.each do |_alias, val|
-
80
if val.is_a? Hash
-
28
if ((self::TESTER_FLOWLINE_ATTRS.map(&:to_sym)) & val.keys) == val.keys
-
28
writer = "#{_alias}=".to_sym
-
28
unless method_defined? writer
-
28
define_method("#{_alias}=") do |v|
-
val.each do |k, _v|
-
myval = _v == :value ? v : _v
-
send("#{k}=", myval)
-
end
-
end
-
end
-
end
-
else
-
-
52
if self::TESTER_FLOWLINE_ATTRS.include? "#{val}"
-
44
writer = "#{_alias}=".to_sym
-
44
reader = _alias.to_sym
-
44
unless method_defined? writer
-
44
define_method("#{_alias}=") do |v|
-
20
send("#{val}=", v)
-
end
-
end
-
44
unless method_defined? reader
-
44
define_method("#{_alias}") do
-
20
send(val)
-
end
-
end
-
end
-
end
-
end
-
end
-
-
2
def initialize(type, attrs = {})
-
1871
@ignore_missing_instance = attrs.delete(:instance_not_available)
-
1871
self.cz_setup = attrs.delete(:cz_setup)
-
1871
@type = type
-
# Set the defaults
-
1871
DEFAULTS[@type.to_sym].each do |k, v|
-
2942
send("#{k}=", v) if self.respond_to?("#{k}=")
-
end
-
# Then the values that have been supplied
-
1871
attrs.each do |k, v|
-
4293
send("#{k}=", v) if self.respond_to?("#{k}=")
-
end
-
# override test numbers if diff-friendly output desired
-
1871
if Origen.tester.diff_friendly_output?
-
self.tnum = 0
-
end
-
end
-
-
2
def parameter=(value)
-
1714
if (@type == :test || @test == :cz) && !@ignore_missing_instance
-
901
if value.is_a?(String) || value.is_a?(Symbol)
-
fail "You must supply the actual test instance object for #{value} when adding it to the flow"
-
end
-
end
-
1714
@parameter = value
-
end
-
-
2
def parameter
-
# When referring to the test instance take the opportunity to refresh the current
-
# version of the test instance
-
1921
@parameter = Origen.interface.identity_map.current_version_of(@parameter)
-
end
-
-
# Returns the fully formatted flow line for insertion into a flow sheet
-
2
def to_s
-
1911
l = "\t"
-
1911
self.class::TESTER_FLOWLINE_ATTRS.each do |attr|
-
55117
if attr == 'parameter'
-
1911
ins = parameter
-
1911
if ins.respond_to?(:name)
-
926
l += "#{ins.name}"
-
else
-
985
l += "#{ins}"
-
end
-
1911
if type == :cz && cz_setup
-
15
l += " #{cz_setup}\t"
-
else
-
1896
l += "\t"
-
end
-
else
-
53206
l += "#{send(attr)}\t"
-
end
-
end
-
1911
"#{l}"
-
end
-
-
2
def unless_enable=(*args)
-
end
-
2
alias_method :unless_enabled=, :unless_enable=
-
-
2
def continue_pass
-
self.result = 'Pass'
-
end
-
-
2
def debug_assume_pass
-
self.debug_assume = 'Pass'
-
end
-
-
2
def debug_assume_fail
-
self.debug_assume = 'Fail'
-
end
-
-
# def debug_sites
-
# self.debug_sites = "All"
-
# end
-
-
2
def set_flag_on_pass
-
self.flag_pass = "#{id}_PASSED"
-
end
-
-
2
def set_flag_on_ran
-
self.flag_pass = "#{id}_RAN"
-
end
-
-
2
def run_if_any_passed(parent)
-
parent.continue_on_fail
-
self.flag_true_any = parent.set_flag_on_pass
-
end
-
-
2
def run_if_all_passed(parent)
-
parent.continue_on_fail
-
self.flag_true_all = parent.set_flag_on_pass
-
end
-
-
2
def run_if_any_failed(parent)
-
parent.continue_on_fail
-
self.flag_true_any = parent.set_flag_on_fail
-
end
-
-
2
def run_if_all_failed(parent)
-
parent.continue_on_fail
-
self.flag_true_all = parent.set_flag_on_fail
-
end
-
-
2
def run_if_all_(args)
-
# code
-
end
-
-
2
def id
-
@id || "#{parameter}_#{unique_counter}"
-
end
-
-
2
def unique_counter
-
@unique_counter ||= self.class.unique_counter
-
end
-
-
2
def self.unique_counter
-
@ix ||= -1
-
@ix += 1
-
end
-
-
2
def test?
-
@type == :test
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
module Generator
-
2
extend ActiveSupport::Concern
-
-
2
autoload :Placeholder, 'origen_testers/generator/placeholder'
-
-
2
included do
-
102
include Interface # adds the interface helpers/Origen hook-up
-
end
-
-
# This is just to give all interfaces an initialize that takes
-
# one argument. The super is important for cases where this module
-
# is included late via Testers::ProgramGenerators
-
2
def initialize(options = {})
-
99
super
-
end
-
-
2
def add_til(name, methods)
-
3
custom_tils[name] = methods
-
end
-
2
alias_method :add_test_instance_library, :add_til
-
-
# @api private
-
2
def at_flow_start
-
102
unless Origen.interface.resources_mode?
-
98
flow.at_flow_start if flow
-
end
-
102
@@pinmaps_filename = nil
-
102
@@test_instances_filename = nil
-
102
@@patsets_filename = nil
-
102
@@patgroups_filename = nil
-
102
@@edgesets_filename = nil
-
102
@@timesets_filename = nil
-
102
@@levelsets_filename = nil
-
102
@@ac_specsets_filename = nil
-
102
@@dc_specsets_filename = nil
-
102
@@global_specs_filename = nil
-
102
@@jobs_filename = nil
-
102
@@references_filename = nil
-
end
-
-
# @api private
-
2
def at_run_start
-
5
flow.at_run_start
-
5
@@pinmap_sheets = nil
-
5
@@test_instance_sheets = nil
-
5
@@patset_sheets = nil
-
5
@@flow_sheets = nil
-
5
@@patgroup_sheets = nil
-
5
@@edgeset_sheets = nil
-
5
@@timeset_sheets = nil
-
5
@@levelset_sheets = nil
-
5
@@ac_specset_sheets = nil
-
5
@@dc_specset_sheets = nil
-
5
@@global_spec_sheets = nil
-
5
@@job_sheets = nil
-
5
@@reference_sheets = nil
-
end
-
2
alias_method :reset_globals, :at_run_start
-
-
# Convenience method to allow the current name for the test instance,
-
# patsets, patgroups and timesets sheets to be set to the same value.
-
#
-
# # my j750 interface
-
#
-
# resources_filename = "common"
-
#
-
# # The above is equivalent to:
-
#
-
# pinmaps_filename = "common"
-
# test_instances_filename = "common"
-
# patsets_filename = "common"
-
# patgroups_filename = "common"
-
# edgesets_filename = "common"
-
# timesets_filename = "common"
-
# levelsets_filename = "common"
-
# ac_specsets_filename = "common"
-
# dc_specsets_filename = "common"
-
# global_specs_filename = "common"
-
# jobs_filename = "common"
-
# references_filename = "common"
-
2
def resources_filename=(name)
-
39
self.pinmaps_filename = name
-
39
self.test_instances_filename = name
-
39
self.patsets_filename = name
-
39
self.patgroups_filename = name
-
39
self.edgesets_filename = name
-
39
self.timesets_filename = name
-
39
self.levelsets_filename = name
-
39
self.ac_specsets_filename = name
-
39
self.dc_specsets_filename = name
-
39
self.global_specs_filename = name
-
39
self.jobs_filename = name
-
39
self.references_filename = name
-
39
self.pattern_references_name = name
-
end
-
-
# Set the name of the current pinmap sheet. This does not change
-
# the name of the current sheet, but rather sets the name of the sheet that
-
# will be generated the next time you access pinmaps.
-
2
def pinmaps_filename=(name)
-
39
@pinmaps_filename = name
-
39
@@pinmaps_filename = name
-
end
-
-
# Set the name of the current test instances sheet. This does not change
-
# the name of the current sheet, but rather sets the name of the sheet that
-
# will be generated the next time you access test_instances.
-
2
def test_instances_filename=(name)
-
39
@test_instances_filename = name
-
39
@@test_instances_filename = name
-
end
-
-
# Set the name of the current pattern sets sheet. This does not change
-
# the name of the current sheet, but rather sets the name of the sheet that
-
# will be generated the next time you access patsets.
-
2
def patsets_filename=(name)
-
39
@patsets_filename = name
-
39
@@patsets_filename = name
-
end
-
-
# Set the name of the current pattern groups sheet. This does not change
-
# the name of the current sheet, but rather sets the name of the sheet that
-
# will be generated the next time you access patgroups.
-
2
def patgroups_filename=(name)
-
39
@patgroups_filename = name
-
39
@@patgroups_filename = name
-
end
-
-
# Set the name of the current edgesets sheet. This does not change
-
# the name of the current sheet, but rather sets the name of the sheet that
-
# will be generated the next time you access patgroups.
-
2
def edgesets_filename=(name)
-
39
@edgesets_filename = name
-
39
@@edgesets_filename = name
-
end
-
-
# Set the name of the current timesets sheet. This does not change
-
# the name of the current sheet, but rather sets the name of the sheet that
-
# will be generated the next time you access patgroups.
-
2
def timesets_filename=(name)
-
39
@timesets_filename = name
-
39
@@timesets_filename = name
-
end
-
-
# Set the name of the current levelsets sheet. This does not change
-
# the name of the current sheet, but rather sets the name of the sheet that
-
# will be generated the next time you access patgroups.
-
2
def levelsets_filename=(name)
-
39
@levelsets_filename = name
-
39
@@levelsets_filename = name
-
end
-
-
# Set the name of the current AC specsets sheet. This does not change
-
# the name of the current sheet, but rather sets the name of the sheet that
-
# will be generated the next time you access patgroups.
-
2
def ac_specsets_filename=(name)
-
39
@ac_specsets_filename = name
-
39
@@ac_specsets_filename = name
-
end
-
-
# Set the name of the current DC specsets sheet. This does not change
-
# the name of the current sheet, but rather sets the name of the sheet that
-
# will be generated the next time you access patgroups.
-
2
def dc_specsets_filename=(name)
-
39
@dc_specsets_filename = name
-
39
@@dc_specsets_filename = name
-
end
-
-
# Set the name of the global specs sheet. This does not change
-
# the name of the current sheet, but rather sets the name of the sheet that
-
# will be generated the next time you access patgroups.
-
2
def global_specs_filename=(name)
-
39
@global_specs_filename = name
-
39
@@global_specs_filename = name
-
end
-
-
# Set the name of the jobs sheet. This does not change
-
# the name of the current sheet, but rather sets the name of the sheet that
-
# will be generated the next time you access patgroups.
-
2
def jobs_filename=(name)
-
39
@jobs_filename = name
-
39
@@jobs_filename = name
-
end
-
-
# Set the name of the references sheet. This does not change
-
# the name of the current sheet, but rather sets the name of the sheet that
-
# will be generated the next time you access patgroups.
-
2
def references_filename=(name)
-
39
@references_filename = name
-
39
@@references_filename = name
-
end
-
-
# Returns the name of the current pinmaps sheet
-
2
def pinmaps_filename
-
@@pinmaps_filename ||= @pinmaps_filename || 'global'
-
end
-
-
# Returns the name of the current test instances sheet
-
2
def test_instances_filename
-
993
@@test_instances_filename ||= @test_instances_filename || 'global'
-
end
-
-
# Returns the name of the current pat sets sheet
-
2
def patsets_filename
-
969
@@patsets_filename ||= @patsets_filename || 'global'
-
end
-
-
# Returns the name of the current pat groups sheet
-
2
def patgroups_filename
-
@@patgroups_filename ||= @patgroups_filename || 'global'
-
end
-
-
# Returns the name of the current edgesets sheet
-
2
def edgesets_filename
-
@@edgesets_filename ||= @edgesets_filename || 'global'
-
end
-
-
# Returns the name of the current timesets sheet
-
2
def timesets_filename
-
@@timesets_filename ||= @timesets_filename || 'global'
-
end
-
-
# Returns the name of the current levelsets sheet
-
2
def levelsets_filename
-
@@levelsets_filename ||= @levelsets_filename || 'global'
-
end
-
-
# Returns the name of the current AC specset sheet
-
2
def ac_specsets_filename
-
@@ac_specsets_filename ||= @ac_specsets_filename || 'global'
-
end
-
-
# Returns the name of the current DC specset sheet
-
2
def dc_specsets_filename
-
@@dc_specsets_filename ||= @dc_specsets_filename || 'global'
-
end
-
-
# Returns the name of the current global spec sheet
-
2
def global_specs_filename
-
@@global_specs_filename ||= @global_specs_filename || 'global'
-
end
-
-
# Returns the name of the current job sheet
-
2
def jobs_filename
-
@@jobs_filename ||= @jobs_filename || 'global'
-
end
-
-
# Returns the name of the current references sheet
-
2
def references_filename
-
@@references_filename ||= @references_filename || 'global'
-
end
-
-
# Returns a hash containing all pinmap sheets
-
2
def pinmap_sheets
-
205
@@pinmap_sheets ||= {}
-
end
-
-
# Returns a hash containing all test instance sheets
-
2
def test_instance_sheets
-
2185
@@test_instance_sheets ||= {}
-
end
-
-
# Returns a hash containing all pat set sheets
-
2
def patset_sheets
-
2139
@@patset_sheets ||= {}
-
end
-
-
# Returns a hash containing all flow sheets
-
2
def flow_sheets
-
6267
@@flow_sheets ||= {}
-
end
-
-
# Returns a hash containing all pat group sheets
-
2
def patgroup_sheets
-
201
@@patgroup_sheets ||= {}
-
end
-
-
# Returns a hash containing all edgeset sheets
-
2
def edgeset_sheets
-
233
@@edgeset_sheets ||= {}
-
end
-
-
# Returns a hash containing all timeset sheets
-
2
def timeset_sheets
-
231
@@timeset_sheets ||= {}
-
end
-
-
# Returns a hash containing all levelset sheets
-
2
def levelset_sheets
-
211
@@levelset_sheets ||= {}
-
end
-
-
# Returns a hash containing all AC specsets sheets
-
2
def ac_specset_sheets
-
241
@@ac_specset_sheets ||= {}
-
end
-
-
# Returns a hash containing all DC specsets sheets
-
2
def dc_specset_sheets
-
221
@@dc_specset_sheets ||= {}
-
end
-
-
# Returns a hash containing all global spec sheets
-
2
def global_spec_sheets
-
207
@@global_spec_sheets ||= {}
-
end
-
-
# Returns a hash containing all job sheets
-
2
def job_sheets
-
203
@@job_sheets ||= {}
-
end
-
-
# Returns a hash containing all reference sheets
-
2
def reference_sheets
-
203
@@reference_sheets ||= {}
-
end
-
-
# Returns an array containing all sheet generators where a sheet generator is a flow,
-
# test instance, patset, pat group, edgeset, timeset, AC/DC/Global spec, job,
-
# or reference sheet.
-
# All Origen program generators must implement this method
-
2
def sheet_generators # :nodoc:
-
199
g = []
-
# Generate all of these sheets verbatim
-
199
[pinmap_sheets, flow_sheets, test_instance_sheets, patset_sheets,
-
patgroup_sheets, levelset_sheets, ac_specset_sheets, dc_specset_sheets,
-
global_spec_sheets, job_sheets, reference_sheets].each do |sheets|
-
2189
sheets.each do |name, sheet|
-
1112
g << sheet
-
end
-
end
-
# Choose whether to generate edgeset/timset or timeset_basic sheets
-
# * Skip edgeset sheet generation when timeset_basic is selected
-
199
[edgeset_sheets, timeset_sheets].each do |sheets|
-
398
sheets.each do |name, sheet|
-
43
next if sheet.class.name =~ /Edgesets$/ && sheet.ts_basic
-
33
g << sheet
-
end
-
end
-
199
g
-
end
-
-
# Returns an array containing all flow sheet generators.
-
# All Origen program generators must implement this method
-
2
def flow_generators
-
g = []
-
flow_sheets.each do |name, sheet|
-
g << sheet
-
end
-
g
-
end
-
-
# Returns the current pinmaps sheet (as defined by the current value of
-
# pinmaps_filename).
-
#
-
# Pass in a filename argument to have a specific sheet returned instead.
-
#
-
# If the sheet does not exist yet it will be created.
-
2
def pinmaps(filename = pinmaps_filename)
-
2
f = filename.to_sym
-
2
return pinmap_sheets[f] if pinmap_sheets[f]
-
2
p = platform::Pinmap.new
-
2
p.filename = f
-
2
pinmap_sheets[f] = p
-
end
-
2
alias_method :pin_maps, :pinmaps
-
-
# Returns the current test instances sheet (as defined by the current value of
-
# test_instances_filename).
-
#
-
# Pass in a filename argument to have a specific sheet returned instead.
-
#
-
# If the sheet does not exist yet it will be created.
-
2
def test_instances(filename = test_instances_filename)
-
992
f = filename.to_sym
-
992
return test_instance_sheets[f] if test_instance_sheets[f]
-
14
t = platform::TestInstances.new
-
14
t.filename = f
-
14
test_instance_sheets[f] = t
-
end
-
-
# Returns the current pattern sets sheet (as defined by the current value of
-
# patsets_filename).
-
#
-
# Pass in a filename argument to have a specific sheet returned instead.
-
#
-
# If the sheet does not exist yet it will be created.
-
2
def patsets(filename = patsets_filename)
-
969
f = filename.to_sym
-
969
return patset_sheets[f] if patset_sheets[f]
-
14
p = platform::Patsets.new
-
14
p.filename = f
-
14
patset_sheets[f] = p
-
end
-
2
alias_method :pat_sets, :patsets
-
2
alias_method :pattern_sets, :patsets
-
-
# Returns the current pattern subroutine sheet (as defined by the current value of
-
# patsubrs_filename).
-
#
-
# Pass in a filename argument to have a specific sheet returned instead.
-
#
-
# If the sheet does not exist yet it will be created.
-
2
def patsubrs(filename = patsubrs_filename)
-
f = filename.to_sym
-
return patsubr_sheets[f] if patsubr_sheets[f]
-
p = platform::Patsubrs.new
-
p.filename = f
-
patsubr_sheets[f] = p
-
end
-
2
alias_method :pat_subrs, :patsubrs
-
2
alias_method :pattern_subrs, :patsubrs
-
-
# Returns the current flow sheet (as defined by the name of the current top
-
# level flow source file).
-
#
-
# Pass in a filename argument to have a specific sheet returned instead.
-
#
-
# If the sheet does not exist yet it will be created.
-
2
def flow(filename = nil)
-
3034
if filename || Origen.file_handler.current_file
-
3033
filename ||= Origen.file_handler.current_file.basename('.rb').to_s
-
# DH here need to reset the flow!!
-
3033
f = filename.to_sym
-
3033
return flow_sheets[f] if flow_sheets[f] # will return flow if already existing
-
30
p = platform::Flow.new
-
30
p.inhibit_output if Origen.interface.resources_mode?
-
30
p.filename = f
-
30
flow_sheets[f] = p
-
end
-
end
-
-
# Returns the current pattern groups sheet (as defined by the current value of
-
# patgroups_filename).
-
#
-
# Pass in a filename argument to have a specific sheet returned instead.
-
#
-
# If the sheet does not exist yet it will be created.
-
2
def patgroups(filename = patgroups_filename)
-
f = filename.to_sym
-
return patgroup_sheets[f] if patgroup_sheets[f]
-
p = platform::Patgroups.new
-
p.filename = f
-
patgroup_sheets[f] = p
-
end
-
2
alias_method :pat_groups, :patgroups
-
2
alias_method :pattern_groups, :patgroups
-
-
# Returns the current collection of edges that are defined. These are
-
# used in support of creating edgeset/timeset sheets. They do not have
-
# an associated sheet of their own.
-
2
def edges
-
20
@@edges ||= platform::Edges.new
-
end
-
2
alias_method :edge_collection, :edges
-
-
# Returns the current edgesets sheet (as defined by the current value of
-
# edgesets_filename).
-
#
-
# Pass in a filename argument to have a specific sheet returned instead.
-
#
-
# If the sheet does not exist yet it will be created.
-
2
def edgesets(filename = edgesets_filename, options = {})
-
options = {
-
16
timeset_basic: false
-
}.merge(options)
-
-
16
f = filename.to_sym
-
16
return edgeset_sheets[f] if edgeset_sheets[f]
-
2
e = platform::Edgesets.new(options)
-
2
e.filename = f
-
2
edgeset_sheets[f] = e
-
end
-
2
alias_method :edge_sets, :edgesets
-
-
# Returns the current timesets or timesets_basic sheet (as defined by the current value of
-
# timesets_filename).
-
#
-
# Pass in a filename argument to have a specific sheet returned instead.
-
#
-
# If the sheet does not exist yet it will be created.
-
2
def timesets(filename = timesets_filename, options = {})
-
options = {
-
16
timeset_basic: false
-
}.merge(options)
-
-
16
f = filename.to_sym
-
16
return timeset_sheets[f] if timeset_sheets[f]
-
2
case options[:timeset_basic]
-
when true
-
1
t = platform::TimesetsBasic.new(options)
-
when false
-
1
t = platform::Timesets.new(options)
-
end
-
2
t.filename = f
-
2
timeset_sheets[f] = t
-
end
-
2
alias_method :time_sets, :timesets
-
2
alias_method :timing_sets, :timesets
-
-
# Returns the current collection of levels that are defined. These are
-
# used in support of creating levelset sheets. They do not have
-
# an associated sheet of their own.
-
2
def levels
-
9
@@levels ||= platform::Levels.new
-
end
-
2
alias_method :level_collection, :levels
-
-
# Returns the current levelsets sheet (as defined by the current value of
-
# levelsets_filename).
-
#
-
# Pass in a filename argument to have a specific sheet returned instead.
-
#
-
# If the sheet does not exist yet it will be created.
-
2
def levelsets(filename = levelsets_filename)
-
6
f = filename.to_sym
-
6
return levelset_sheets[f] if levelset_sheets[f]
-
1
t = platform::Levelset.new
-
1
t.filename = f
-
1
levelset_sheets[f] = t
-
end
-
2
alias_method :time_sets, :timesets
-
2
alias_method :timing_sets, :timesets
-
-
# Returns the current AC specset sheet (as defined by the current value of
-
# ac_specsets_filename).
-
#
-
# Pass in a filename argument to have a specific sheet returned instead.
-
#
-
# If the sheet does not exist yet it will be created.
-
2
def ac_specsets(filename = ac_specsets_filename)
-
20
f = filename.to_sym
-
20
return ac_specset_sheets[f] if ac_specset_sheets[f]
-
1
s = platform::ACSpecsets.new
-
1
s.filename = f
-
1
ac_specset_sheets[f] = s
-
end
-
-
# Returns the current DC specset sheet (as defined by the current value of
-
# dc_specsets_filename).
-
#
-
# Pass in a filename argument to have a specific sheet returned instead.
-
#
-
# If the sheet does not exist yet it will be created.
-
2
def dc_specsets(filename = dc_specsets_filename)
-
10
f = filename.to_sym
-
10
return dc_specset_sheets[f] if dc_specset_sheets[f]
-
1
s = platform::DCSpecsets.new
-
1
s.filename = f
-
1
dc_specset_sheets[f] = s
-
end
-
-
# Returns the current global spec sheet (as defined by the current value of
-
# global_specs_filename).
-
#
-
# Pass in a filename argument to have a specific sheet returned instead.
-
#
-
# If the sheet does not exist yet it will be created.
-
2
def global_specs(filename = global_specs_filename)
-
4
f = filename.to_sym
-
4
return global_spec_sheets[f] if global_spec_sheets[f]
-
1
s = platform::GlobalSpecs.new
-
1
s.filename = f
-
1
global_spec_sheets[f] = s
-
end
-
-
# Returns the current job sheet (as defined by the current value of
-
# jobs_filename).
-
#
-
# Pass in a filename argument to have a specific sheet returned instead.
-
#
-
# If the sheet does not exist yet it will be created.
-
2
def program_jobs(filename = jobs_filename)
-
2
f = filename.to_sym
-
2
return job_sheets[f] if job_sheets[f]
-
1
j = platform::Jobs.new
-
1
j.filename = f
-
1
job_sheets[f] = j
-
end
-
-
# Returns the current reference sheet (as defined by the current value of
-
# references_filename).
-
#
-
# Pass in a filename argument to have a specific sheet returned instead.
-
#
-
# If the sheet does not exist yet it will be created.
-
2
def references(filename = references_filename)
-
2
f = filename.to_sym
-
2
return reference_sheets[f] if reference_sheets[f]
-
1
r = platform::References.new
-
1
r.filename = f
-
1
reference_sheets[f] = r
-
end
-
-
2
private
-
-
# Custom test instance libraries
-
2
def custom_tils
-
329
@custom_tils ||= {}
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class GlobalSpecs
-
2
include ::OrigenTesters::Generator
-
-
2
attr_accessor :global_specs
-
-
2
OUTPUT_PREFIX = 'SpecsGlobal'
-
# OUTPUT_POSTFIX = 'SpecsGlobal'
-
-
2
def initialize # :nodoc:
-
## Hash Autovivification
-
5
l = ->(h, k) { h[k] = Hash.new(&l) }
-
1
@global_specs = Hash.new(&l)
-
end
-
-
# Assigns a global spec value object to the given variable
-
# The attrs hash is expected to defined as follows:
-
# attrs = {
-
# job: nil,
-
# value: 0
-
# }
-
2
def add(spec, attrs = {})
-
attrs = {
-
4
job: :nil,
-
value: 0
-
}.merge(attrs)
-
-
4
@global_specs[spec][attrs.delete(:job)] = attrs
-
end
-
-
# Prepare the spec information for file output
-
2
def format_uflex_global_spec(data, options = {})
-
options = {
-
4
spec: nil
-
}.update(options)
-
-
4
case options[:spec]
-
when /fgb_/i
-
spec_type = 'freq'
-
when /vgb_/i
-
spec_type = 'volt'
-
else
-
4
spec_type = nil
-
end
-
-
4
case data
-
when NilClass
-
data_new = 0
-
when Fixnum, Float
-
case
-
when data == 0
-
data_new = data.to_s
-
when data.abs < 1e-6
-
data_new = (data * 1_000_000_000).round(4).to_s + '*nV' if spec_type == 'volt'
-
data_new = data.to_s if spec_type.nil?
-
when data.abs < 1e-3
-
data_new = (data * 1_000_000).round(4).to_s + '*uV' if spec_type == 'volt'
-
data_new = data.to_s if spec_type.nil?
-
when data.abs < 1
-
data_new = (data * 1_000).round(4).to_s + '*mV' if spec_type == 'volt'
-
data_new = data.to_s if spec_type.nil?
-
else
-
data_new = data.to_s + '*V' if spec_type == 'volt'
-
data_new = data.to_s if spec_type.nil?
-
end
-
data_new = data_new.gsub(/^/, '=')
-
when String
-
4
data_new = data.gsub(/^/, '=').gsub(/(\W)([a-zA-Z])/, '\1_\2')
-
# Remove underscores from unit designations
-
4
data_new.gsub!(/(\W)_(nV|uV|mV|V|nA|uA|mA|A)(\W)/i, '\1\2\3')
-
4
data_new.gsub!(/(\W)_(nV|uV|mV|V|nA|uA|mA|A)$/i, '\1\2')
-
else
-
Origen.log.error "Unknown class type (#{data.class}) for spec value: #{data}"
-
fail
-
end
-
4
data_new
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class Job
-
2
attr_accessor :name
-
2
attr_accessor :pinmap
-
2
attr_accessor :instances
-
2
attr_accessor :flows
-
2
attr_accessor :ac_specs
-
2
attr_accessor :dc_specs
-
2
attr_accessor :patsets
-
2
attr_accessor :patgroups
-
2
attr_accessor :bintables
-
2
attr_accessor :cz
-
2
attr_accessor :test_procs
-
2
attr_accessor :mix_sig_timing
-
2
attr_accessor :wave_defs
-
2
attr_accessor :psets
-
2
attr_accessor :signals
-
2
attr_accessor :port_map
-
2
attr_accessor :fract_bus
-
2
attr_accessor :concurrent_seq
-
2
attr_accessor :comment
-
-
2
def initialize(jname, options = {}) # :nodoc:
-
2
@name = jname
-
2
options[:pinmap] ? @pinmap = [options[:pinmap]] : @pinmap = []
-
2
options[:instances] ? @instances = [options[:instances]] : @instances = []
-
2
options[:flows] ? @flows = [options[:flows]] : @flows = []
-
2
options[:ac_specs] ? @ac_specs = [options[:ac_specs]] : @ac_specs = []
-
2
options[:dc_specs] ? @dc_specs = [options[:dc_specs]] : @dc_specs = []
-
2
options[:patsets] ? @patsets = [options[:patsets]] : @patsets = []
-
2
options[:patgroups] ? @patgroups = [options[:patgroups]] : @patgroups = []
-
2
options[:bintables] ? @bintables = [options[:bintables]] : @bintables = []
-
2
options[:cz] ? @cz = [options[:cz]] : @cz = []
-
2
options[:test_procs] ? @test_procs = [options[:test_procs]] : @test_procs = []
-
2
options[:mix_sig_timing] ? @mix_sig_timing = [options[:mix_sig_timing]] : @mix_sig_timing = []
-
2
options[:wave_defs] ? @wave_defs = [options[:wave_defs]] : @wave_defs = []
-
2
options[:psets] ? @psets = [options[:psets]] : @psets = []
-
2
options[:signals] ? @signals = [options[:signals]] : @signals = []
-
2
options[:port_map] ? @port_map = [options[:port_map]] : @port_map = []
-
2
options[:fract_bus] ? @fract_bus = [options[:fract_bus]] : @fract_bus = []
-
2
options[:concurrent_seq] ? @concurrent_seq = [options[:concurrent_seq]] : @concurrent_seq = []
-
2
options[:comment] ? @comment = options[:instances] : @comment = nil
-
end
-
-
# Assigns job information for the given object
-
2
def add_job_info(jname, options = {})
-
@pinmap.push(options[:pinmap]) if options[:pinmap]
-
@instances.push(options[:instances]) if options[:instances]
-
@flows.push(options[:flows]) if options[:flows]
-
@ac_specs.push(options[:ac_specs]) if options[:ac_specs]
-
@dc_specs.push(options[:dc_specs]) if options[:dc_specs]
-
@patsets.push(options[:patsets]) if options[:patsets]
-
@patgroups.push(options[:patgroups]) if options[:patgroups]
-
@bintables.push(options[:bintables]) if options[:bintables]
-
@cz.push(options[:cz]) if options[:cz]
-
@test_procs.push(options[:test_procs]) if options[:test_procs]
-
@mix_sig_timing.push(options[:mix_sig_timing]) if options[:mix_sig_timing]
-
@wave_defs.push(options[:wave_defs]) if options[:wave_defs]
-
@psets.push(options[:psets]) if options[:psets]
-
@signals.push(options[:signals]) if options[:signals]
-
@port_map.push(options[:port_map]) if options[:port_map]
-
@fract_bus.push(options[:fract_bus]) if options[:fract_bus]
-
@concurrent_seq.push(options[:concurrent_seq]) if options[:concurrent_seq]
-
@comment = options[:instances] if options[:instances]
-
end
-
-
2
def platform
-
Origen.interface.platform
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class Jobs
-
2
include ::OrigenTesters::Generator
-
2
attr_accessor :jobs
-
-
2
OUTPUT_PREFIX = nil
-
2
OUTPUT_POSTFIX = nil
-
-
2
def initialize # :nodoc:
-
1
@jobs = {}
-
end
-
-
2
def add(jname, options = {})
-
2
@jobs.key?(jname) ? @jobs[jname].add_job_info(jname, options) : @jobs[jname] = platform::Job.new(jname, options)
-
2
@jobs[jname]
-
end
-
-
2
def finalize(options = {})
-
1
@jobs.each do |_key, job|
-
2
job.pinmap = job.pinmap.flatten.uniq
-
2
job.instances = job.instances.flatten.uniq
-
2
job.flows = job.flows.flatten.uniq
-
2
job.ac_specs = job.ac_specs.flatten.uniq
-
2
job.dc_specs = job.dc_specs.flatten.uniq
-
2
job.patsets = job.patsets.flatten.uniq
-
2
job.patgroups = job.patgroups.flatten.uniq
-
2
job.bintables = job.bintables.flatten.uniq
-
2
job.cz = job.cz.flatten.uniq
-
2
job.test_procs = job.test_procs.flatten.uniq
-
2
job.mix_sig_timing = job.mix_sig_timing.flatten.uniq
-
2
job.wave_defs = job.wave_defs.flatten.uniq
-
2
job.psets = job.psets.flatten.uniq
-
2
job.signals = job.signals.flatten.uniq
-
2
job.port_map = job.port_map.flatten.uniq
-
2
job.fract_bus = job.fract_bus.flatten.uniq
-
2
job.concurrent_seq = job.concurrent_seq.flatten.uniq
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class PinLevelSingle
-
2
attr_accessor :vil, :vih # Input level information
-
2
attr_accessor :vol, :voh # Output level information
-
2
attr_accessor :vcl, :vch # Clamp level information
-
2
attr_accessor :vt # Termination level information
-
2
attr_accessor :voutlotyp, :vouthityp, :dmode
-
-
2
def initialize(options = {}) # :nodoc:
-
options = {
-
2
vil: 0, # Input drive low
-
vih: 1.8, # Input drive high
-
vol: 1.0, # Output compare low
-
voh: 0.8, # Output compare high
-
vcl: -1, # Voltage clamp low
-
vch: 2.5, # Voltage clamp high
-
vt: 0.9, # Termination voltage
-
voutlotyp: 0, #
-
vouthityp: 0, #
-
dmode: 'Largeswing-VT' # Driver mode (possibly ATE-specific)
-
}.merge(options)
-
2
@vil = options[:vil]
-
2
@vih = options[:vih]
-
2
@vol = options[:vol]
-
2
@voh = options[:voh]
-
2
@vcl = options[:vcl]
-
2
@vch = options[:vch]
-
2
@vt = options[:vt]
-
2
@voutlotyp = options[:voutlotyp]
-
2
@vouthityp = options[:vouthityp]
-
2
@dmode = options[:dmode]
-
end
-
-
2
def ==(level)
-
if level.is_a? PinLevelSingle
-
vil == level.vil &&
-
vih == level.vih &&
-
vol == level.vol &&
-
voh == level.voh &&
-
vcl == level.vcl &&
-
vch == level.vch &&
-
vt == level.vt &&
-
voutlotyp == level.voutlotyp &&
-
vouthityp == level.vouthityp &&
-
dmode == level.dmode
-
else
-
super
-
end
-
end
-
-
2
def platform
-
Origen.interface.platform
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class SupplyLevel
-
2
attr_accessor :vmain, :valt # Supply level information
-
2
attr_accessor :ifold # Clamp current information
-
2
attr_accessor :delay # Supply power-up delay
-
-
2
def initialize(options = {}) # :nodoc:
-
options = {
-
1
vmain: 1.8, # Main supply voltage
-
valt: 1.8, # Alternate supply voltage
-
ifold: 1, # Supply clamp current
-
delay: 0 # Supply power-up delay
-
}.merge(options)
-
1
@vmain = options[:vmain]
-
1
@valt = options[:valt]
-
1
@ifold = options[:ifold]
-
1
@delay = options[:delay]
-
end
-
-
2
def ==(level)
-
if level.is_a? PinLevelSingle
-
vmain == level.vmain &&
-
valt == level.valt &&
-
ifold == level.ifold &&
-
delay == level.delay
-
else
-
super
-
end
-
end
-
-
2
def platform
-
Origen.interface.platform
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class Levels
-
2
include ::OrigenTesters::Generator
-
-
# If levels are defined for a power group then this will return the level object
-
2
attr_accessor :pwr_group
-
# If levels are defined for a pin group then this will return the level object
-
2
attr_accessor :pin_group
-
-
2
def initialize(options = {}) # :nodoc:
-
1
@pwr_group = Hash.new { |h, k| h[k] = {} }
-
1
@pin_group = Hash.new { |h, k| h[k] = {} }
-
end
-
-
# Defines a new Power Level category for the given pin/group
-
2
def add_power_level(cat, options = {})
-
1
cat = cat.to_sym unless cat.is_a? Symbol
-
1
pwr_group[cat] = platform::SupplyLevel.new(options)
-
end
-
-
# Defines a new Single-Ended Pin Level category for the given pin/group
-
2
def add_se_pin_level(cat, options = {})
-
2
cat = cat.to_sym unless cat.is_a? Symbol
-
2
pin_group[cat] = platform::PinLevelSingle.new(options)
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class Levelset
-
2
include ::OrigenTesters::Generator
-
-
2
attr_accessor :pins
-
2
attr_accessor :spec_sheet
-
2
attr_accessor :ls_sheet_pins
-
-
# Levelset name
-
2
attr_accessor :name
-
-
2
OUTPUT_PREFIX = 'LV'
-
# OUTPUT_POSTFIX = 'LV'
-
-
2
def initialize(options = {}) # :nodoc:
-
1
@pins = {}
-
end
-
-
# rubocop:disable Metrics/ParameterLists
-
-
# Adds a pin level to the given levelset
-
2
def add(lsname, pin, level, options = {})
-
options = {
-
6
spec_sheet: 'default' # defines which specset sheet to put variables in (e.g. func, scan) when generating specset files
-
}.merge(options)
-
6
lsname = lsname.to_sym unless lsname.is_a? Symbol
-
6
pin = pin.to_sym unless pin.is_a? Symbol
-
-
6
add_level(pin, level)
-
6
@name = lsname
-
6
@spec_sheet = options[:spec_sheet]
-
6
@ls_sheet_pins = options[:ls_sheet_pins] unless @ls_sheet_pins
-
end
-
-
# Assigns a level object to the given pin for this levelset
-
2
def add_level(pin, level)
-
6
if @pins.key?(pin)
-
Origen.log.error "Pin #{pin} already exists in levelset"
-
else
-
6
@pins[pin] = level
-
end
-
end
-
-
2
def finalize(options = {})
-
end
-
-
# Populate an array of pins based on the pin or pingroup
-
2
def get_pin_objects(grp)
-
8
pins = []
-
8
if Origen.top_level.pin(grp).is_a?(Origen::Pins::Pin) ||
-
Origen.top_level.pin(grp).is_a?(Origen::Pins::FunctionProxy)
-
8
pins << Origen.top_level.pin(grp)
-
elsif Origen.top_level.pin(grp).is_a?(Origen::Pins::PinCollection)
-
Origen.top_level.pin(grp).each do |pin|
-
pins << pin
-
end
-
else
-
Origen.log.error "Could not find pin class: #{grp} #{Origen.top_level.pin(grp).class}"
-
end
-
8
pins
-
end
-
-
# Equality check to compare full contents of 2 level objects
-
2
def levels_eql?(level1, level2)
-
level1 == level2
-
end
-
-
# Globally modify text within the level object
-
2
def gsub_levels!(level, old_val, new_val)
-
# determine if object is a power level (conatins :vmain) or a SE pin level (:vil)
-
if level.respond_to?(:vmain)
-
level.vmain = level.vmain.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
level.valt = level.valt.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
level.ifold = level.ifold.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
# level.delay = level.delay.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
elsif level.respond_to?(:vil)
-
level.vil = level.vil.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
level.vih = level.vih.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
level.vol = level.vol.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
level.voh = level.voh.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
level.vcl = level.vcl.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
level.vch = level.vch.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
level.vt = level.vt.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
level.voutlotyp = level.voutlotyp.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
level.vouthityp = level.vouthityp.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
level.dmode = level.dmode.gsub(/#{Regexp.escape(old_val)}/, new_val)
-
end
-
end
-
-
2
def format_uflex_level(data, options = {})
-
44
options = {
-
}.merge(options)
-
-
44
if data !~ /^\s*$/
-
44
data = data.gsub(/^/, '=')
-
end
-
44
data = data.gsub(/(\W)([a-zA-Z])/, '\1_\2')
-
44
data = data.gsub(/(\*\s*)_([kmun]{0,1}[AVs]{1}\W)/, '\1\2')
-
44
data = data.gsub(/(\*\s*)_([kmun]{0,1}[AVs]{1})$/, '\1\2')
-
end
-
-
2
def platform
-
Origen.interface.platform
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class Patgroup
-
2
attr_accessor :index
-
-
2
class Pattern
-
2
ATTRS = %w(group_name pattern_file comment)
-
-
ALIASES = {
-
2
pattern: :pattern_file
-
}
-
-
2
DEFAULTS = {
-
}
-
-
# Generate accessors for all attributes and their aliases
-
2
ATTRS.each do |attr|
-
6
attr_accessor attr.to_sym
-
end
-
-
2
ALIASES.each do |_alias, val|
-
2
define_method("#{_alias}=") do |v|
-
send("#{val}=", v)
-
end
-
2
define_method("#{_alias}") do
-
send(val)
-
end
-
end
-
-
2
def initialize(patgroup, attrs = {})
-
# Set the defaults
-
DEFAULTS.each do |k, v|
-
send("#{k}=", v)
-
end
-
# Then the values that have been supplied
-
self.group_name = patgroup
-
attrs.each do |k, v|
-
send("#{k}=", v)
-
end
-
end
-
-
2
def to_s
-
l = "\t"
-
ATTRS.each do |attr|
-
l += "#{send(attr)}\t"
-
end
-
"#{l}"
-
end
-
end
-
-
# Specify multiple patterns by passing an array of attributes
-
# as the 2nd argument:
-
#
-
# Patset.new("mrd1_pgrp", :pattern => "nvm_mrd1.PAT")
-
#
-
# Patset.new("mrd1_pgrp", [{:pattern => "nvm_mrd1.PAT"},
-
# {:pattern => "nvm_global_subs.PAT},
-
# ])
-
2
def initialize(name, attrs = {})
-
attrs = [attrs] unless attrs.is_a? Array
-
attrs.each do |pattrs|
-
if pattrs[:pattern]
-
pat = Pathname.new(pattrs[:pattern].gsub('\\', '/')).basename('.*').to_s
-
Origen.interface.referenced_patterns << pat
-
end
-
lines << Pattern.new(name, pattrs)
-
end
-
self.name = name
-
end
-
-
2
def ==(other_patgroup)
-
self.class == other_patgroup.class &&
-
name.to_s == other_patgroup.name.to_s &&
-
sorted_pattern_files == other_patgroup.sorted_pattern_files
-
end
-
-
2
def name
-
@name
-
end
-
-
2
def name=(n)
-
@name = n
-
lines.each { |l| l.group_name = n }
-
n
-
end
-
-
# Returns all lines in the pattern set
-
2
def lines
-
@lines ||= []
-
end
-
-
# Returns all pattern files in the pattern set in alphabetical order
-
2
def sorted_pattern_files
-
@lines.map(&:file_name).sort
-
end
-
-
# Returns the fully formatted pattern group for insertion into a patgroups sheet
-
2
def to_s
-
l = ''
-
lines.each do |line|
-
l += "#{line}\r\n"
-
end
-
l.chomp
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class Patgroups
-
2
include ::OrigenTesters::Generator
-
-
2
OUTPUT_POSTFIX = 'patgroups'
-
-
2
def add(name, options = {})
-
p = platform::Patgroup.new(name, options)
-
collection << p
-
p
-
end
-
-
2
def finalize(options = {})
-
uniq!
-
sort!
-
end
-
-
# Present the patgroups in the final sheet in alphabetical order
-
2
def sort!
-
collection.sort_by!(&:name)
-
end
-
-
# Removes all duplicate patgroups
-
2
def uniq!
-
uniques = []
-
collection.each do |patgroup|
-
unless uniques.any? { |p| p == patgroup }
-
uniques << patgroup
-
end
-
end
-
self.collection = uniques
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class Patset
-
2
attr_accessor :index
-
-
# Specify multiple patterns by passing an array of attributes
-
# as the 2nd argument:
-
#
-
# Patset.new("mrd1_pset", :pattern => "nvm_mrd1.PAT")
-
#
-
# Patset.new("mrd1_pset", [{:pattern => "nvm_mrd1.PAT"},
-
# {:pattern => "nvm_global_subs.PAT, :start_label => "subr"}
-
# ])
-
2
def initialize(name, attrs = {})
-
969
attrs = [attrs] unless attrs.is_a? Array
-
969
attrs.each do |pattrs|
-
1932
if pattrs[:pattern]
-
1932
pat = Pathname.new(pattrs[:pattern].gsub('\\', '/')).basename('.*').to_s
-
1932
Origen.interface.referenced_patterns << pat
-
end
-
1932
lines << platform::PatsetPattern.new(name, pattrs)
-
end
-
969
self.name = name
-
end
-
-
2
def ==(other_patset)
-
13008
self.class == other_patset.class &&
-
name.to_s == other_patset.name.to_s &&
-
sorted_pattern_files == other_patset.sorted_pattern_files
-
end
-
-
2
def name
-
26332
@name
-
end
-
-
2
def name=(n)
-
969
@name = n
-
2901
lines.each { |l| l.pattern_set = n }
-
969
n
-
end
-
-
# Returns all lines in the pattern set
-
2
def lines
-
3217
@lines ||= []
-
end
-
-
# Returns all pattern files in the pattern set in alphabetical order
-
2
def sorted_pattern_files
-
1306
@lines.map(&:file_name).sort
-
end
-
-
# Returns the fully formatted pattern set for insertion into a patset sheet
-
2
def to_s
-
l = ''
-
lines.each do |line|
-
l += "#{line}\r\n"
-
end
-
l.chomp
-
end
-
-
2
def platform
-
1932
Origen.interface.platform
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class PatsetPattern
-
ALIASES = {
-
2
pattern: :file_name
-
}
-
-
2
def self.define
-
# Generate accessors for all attributes and their aliases
-
4
self::PATSET_ATTRS.each do |attr|
-
26
writer = "#{attr}=".to_sym
-
26
reader = attr.to_sym
-
26
attr_reader attr.to_sym unless method_defined? reader
-
26
attr_writer attr.to_sym unless method_defined? writer
-
end
-
-
4
ALIASES.each do |_alias, val|
-
4
writer = "#{_alias}=".to_sym
-
4
reader = _alias.to_sym
-
4
unless method_defined? writer
-
4
define_method("#{_alias}=") do |v|
-
1932
send("#{val}=", v)
-
end
-
end
-
4
unless method_defined? reader
-
4
define_method("#{_alias}") do
-
send(val)
-
end
-
end
-
end
-
end
-
-
2
def initialize(patset, attrs = {})
-
# Set the defaults
-
1932
self.class::PATSET_DEFAULTS.each do |k, v|
-
680
send("#{k}=", v)
-
end
-
# Then the values that have been supplied
-
1932
self.pattern_set = patset
-
1932
attrs.each do |k, v|
-
2895
send("#{k}=", v)
-
end
-
end
-
-
2
def to_s
-
626
l = "\t"
-
626
self.class::PATSET_ATTRS.each do |attr|
-
3814
l += "#{send(attr)}\t"
-
end
-
626
"#{l}"
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class Patsets
-
2
include ::OrigenTesters::Generator
-
-
2
OUTPUT_POSTFIX = 'patsets'
-
-
2
def add(name, options = {})
-
969
p = platform::Patset.new(name, options)
-
969
collection << p
-
969
p
-
end
-
-
2
def finalize(options = {})
-
14
uniq!
-
14
sort!
-
end
-
-
# Present the patsets in the final sheet in alphabetical order
-
2
def sort!
-
14
collection.sort_by!(&:name)
-
end
-
-
# Removes all duplicate patsets
-
2
def uniq!
-
14
uniques = []
-
14
collection.each do |patset|
-
13977
unless uniques.any? { |p| p == patset }
-
316
uniques << patset
-
end
-
end
-
14
self.collection = uniques
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class Patsubr
-
2
attr_accessor :index
-
-
# Specify multiple patterns by passing an array of attributes
-
# as the 2nd argument:
-
#
-
# Patset.new("mrd1_pset", :pattern => "nvm_mrd1.PAT")
-
#
-
# Patset.new("mrd1_pset", [{:pattern => "nvm_mrd1.PAT"},
-
# {:pattern => "nvm_global_subs.PAT, :start_label => "subr"}
-
# ])
-
2
def initialize(name, attrs = {})
-
attrs = [attrs] unless attrs.is_a? Array
-
attrs.each do |pattrs|
-
if pattrs[:pattern]
-
pat = Pathname.new(pattrs[:pattern].gsub('\\', '/')).basename('.*').to_s
-
Origen.interface.referenced_patterns << pat
-
end
-
lines << platform::PatsubrPattern.new(name, pattrs)
-
end
-
self.name = name
-
end
-
-
2
def ==(other_patset)
-
self.class == other_patset.class &&
-
name.to_s == other_patset.name.to_s &&
-
sorted_pattern_files == other_patset.sorted_pattern_files
-
end
-
-
2
def name
-
@name
-
end
-
-
2
def name=(n)
-
@name = n
-
lines.each { |l| l.pattern_set = n }
-
n
-
end
-
-
# Returns all lines in the pattern set
-
2
def lines
-
@lines ||= []
-
end
-
-
# Returns all pattern files in the pattern set in alphabetical order
-
2
def sorted_pattern_files
-
@lines.map(&:file_name).sort
-
end
-
-
# Returns the fully formatted pattern set for insertion into a patset sheet
-
2
def to_s
-
l = ''
-
lines.each do |line|
-
l += "#{line}\r\n"
-
end
-
l.chomp
-
end
-
-
2
def platform
-
Origen.interface.platform
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class PatsubrPattern
-
ALIASES = {
-
2
pattern: :file_name
-
}
-
-
2
def self.define
-
# Generate accessors for all attributes and their aliases
-
4
self::PATSUBR_ATTRS.each do |attr|
-
8
writer = "#{attr}=".to_sym
-
8
reader = attr.to_sym
-
8
attr_reader attr.to_sym unless method_defined? reader
-
8
attr_writer attr.to_sym unless method_defined? writer
-
end
-
-
4
ALIASES.each do |_alias, val|
-
4
writer = "#{_alias}=".to_sym
-
4
reader = _alias.to_sym
-
4
unless method_defined? writer
-
4
define_method("#{_alias}=") do |v|
-
send("#{val}=", v)
-
end
-
end
-
4
unless method_defined? reader
-
4
define_method("#{_alias}") do
-
send(val)
-
end
-
end
-
end
-
end
-
-
2
def initialize(patsubr, attrs = {})
-
# Set the defaults
-
self.class::PATSUBR_DEFAULTS.each do |k, v|
-
send("#{k}=", v)
-
end
-
# Then the values that have been supplied
-
self.pattern_subr = patsubr
-
attrs.each do |k, v|
-
send("#{k}=", v)
-
end
-
end
-
-
2
def to_s
-
l = "\t"
-
self.class::PATSUBR_ATTRS.each do |attr|
-
l += "#{send(attr)}\t"
-
end
-
"#{l}"
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class Patsubrs
-
2
include ::OrigenTesters::Generator
-
-
2
OUTPUT_POSTFIX = 'patsubrs'
-
-
2
def add(name, options = {})
-
p = Patsubr.new(name, options)
-
collection << p
-
p
-
end
-
-
2
def finalize(options = {})
-
uniq!
-
sort!
-
end
-
-
# Present the patsubrs in the final sheet in alphabetical order
-
2
def sort!
-
collection.sort_by!(&:name)
-
end
-
-
# Removes all duplicate patsubrs
-
2
def uniq!
-
uniques = []
-
collection.each do |patsubr|
-
unless uniques.any? { |p| p == patsubr }
-
uniques << patsubr
-
end
-
end
-
self.collection = uniques
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class Pinmap
-
2
include ::OrigenTesters::Generator
-
-
2
attr_accessor :pins
-
2
attr_accessor :pin_groups
-
2
attr_accessor :power_pins
-
2
attr_accessor :utility_pins
-
-
2
PIN_TYPES = ['I/O', 'I', 'O']
-
2
PWR_TYPES = ['Power']
-
2
UTL_TYPES = ['Utility', 'I/O', 'I', 'O']
-
-
2
def initialize # :nodoc:
-
2
@pins = {}
-
5
@pin_groups = Hash.new { |h, k| h[k] = {} }
-
2
@power_pins = {}
-
2
@utility_pins = {}
-
end
-
-
2
def add_pin(pin_name, attrs = {})
-
attrs = {
-
10
type: 'I/O',
-
comment: ''
-
}.merge(attrs)
-
10
pin_name = pin_name.to_sym unless pin_name.is_a? Symbol
-
10
if PIN_TYPES.include? attrs[:type]
-
10
type = attrs[:type]
-
else
-
Origen.log.error "Pinmap individual pin type '#{attrs[:type]}' must be set to one of the following: #{PIN_TYPES.join(', ')} for pin '#{pin_name}'"
-
fail
-
end
-
10
@pins[pin_name] = { type: type, comment: attrs[:comment] }
-
end
-
-
2
def add_group_pin(grp_name, pin_name, attrs = {})
-
attrs = {
-
9
type: 'I/O',
-
comment: ''
-
}.merge(attrs)
-
9
grp_name = grp_name.to_sym unless grp_name.is_a? Symbol
-
9
pin_name = pin_name.to_sym unless pin_name.is_a? Symbol
-
9
if PIN_TYPES.include? attrs[:type]
-
9
type = attrs[:type]
-
else
-
Origen.log.error "Pinmap group pin type '#{attrs[:type]}' must be set to one of the following: #{PIN_TYPES.join(', ')} for pin '#{pin_name}'"
-
fail
-
end
-
9
@pin_groups[grp_name][pin_name] = { type: attrs[:type], comment: attrs[:comment] }
-
end
-
-
2
def add_power_pin(pin_name, attrs = {})
-
attrs = {
-
5
type: 'Power',
-
comment: ''
-
}.merge(attrs)
-
5
pin_name = pin_name.to_sym unless pin_name.is_a? Symbol
-
5
if PWR_TYPES.include? attrs[:type]
-
5
type = attrs[:type]
-
else
-
Origen.log.error "Pinmap powerpin type '#{attrs[:type]}' must be set to one of the following: #{PWR_TYPES.join(', ')} for pin '#{pin_name}'"
-
fail
-
end
-
5
@power_pins[pin_name] = { type: attrs[:type], comment: attrs[:comment] }
-
end
-
-
2
def add_utility_pin(pin_name, attrs = {})
-
attrs = {
-
4
type: 'Utility',
-
comment: ''
-
}.merge(attrs)
-
4
pin_name = pin_name.to_sym unless pin_name.is_a? Symbol
-
4
if UTL_TYPES.include? attrs[:type]
-
4
type = attrs[:type]
-
else
-
Origen.log.error "Pinmap utility pin type '#{attrs[:type]}' must be set to one of the following: #{UTL_TYPES.join(', ')} for pin '#{pin_name}'"
-
fail
-
end
-
4
@utility_pins[pin_name] = { type: attrs[:type], comment: attrs[:comment] }
-
end
-
-
2
def finalize(options = {})
-
end
-
-
2
def platform
-
1
Origen.interface.platform
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class References
-
2
include ::OrigenTesters::Generator
-
2
attr_accessor :references
-
-
2
OUTPUT_PREFIX = nil
-
2
OUTPUT_POSTFIX = nil
-
-
2
def initialize # :nodoc:
-
1
@references = []
-
end
-
-
2
def add(reference, options = {})
-
options = {
-
2
comment: nil
-
}.merge(options)
-
-
2
@references << { ref: reference, comment: options[:comment] }
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class TestInstance
-
2
attr_accessor :type, :index, :version, :append_version, :finalize, :meta
-
-
2
def self.define
-
# Generate accessors for all attributes and their aliases
-
6
attrs.each do |attr|
-
660
writer = "#{attr}=".to_sym
-
660
reader = attr.to_sym
-
660
attr_reader attr.to_sym unless method_defined? reader
-
660
attr_writer attr.to_sym unless method_defined? writer
-
end
-
-
# Define the common aliases now, the instance type specific ones will
-
# be created when the instance type is known
-
6
self::TEST_INSTANCE_ALIASES.each do |_alias, val|
-
66
writer = "#{_alias}=".to_sym
-
66
reader = _alias.to_sym
-
66
unless val.is_a? Hash
-
24
unless method_defined? writer
-
18
define_method("#{_alias}=") do |v|
-
4
send("#{val}=", v)
-
end
-
end
-
24
unless method_defined? reader
-
18
define_method("#{_alias}") do
-
send(val)
-
end
-
end
-
end
-
end
-
end
-
-
2
def self.attrs
-
1158
@attrs ||= begin
-
6
attrs = self::TEST_INSTANCE_ATTRS.dup
-
-
6
self::TEST_INSTANCE_EXTRA_ARGS.times do |i|
-
580
attrs << "arg#{i}"
-
end
-
6
attrs << 'comment'
-
6
attrs
-
end
-
end
-
-
2
def initialize(name, type, attrs = {})
-
969
@type = type
-
969
@append_version = true
-
969
self.name = name
-
# Build the type specific accessors (aliases)
-
969
self.class::TEST_INSTANCE_ALIASES[@type.to_sym].each do |_alias, val|
-
53043
define_singleton_method("#{_alias}=") do |v|
-
12076
send("#{val}=", v) if self.respond_to?("#{val}=", v)
-
end
-
53043
define_singleton_method("#{_alias}") do
-
2687
send(val) if self.respond_to?(val)
-
end
-
end
-
# Set the defaults
-
969
self.class::TEST_INSTANCE_DEFAULTS[@type.to_sym].each do |k, v|
-
13836
send("#{k}=", v) if self.respond_to?("#{k}=", v)
-
end
-
# Then the values that have been supplied
-
969
attrs.each do |k, v|
-
21
send("#{k}=", v) if self.respond_to?("#{k}=", v)
-
end
-
end
-
-
2
def inspect
-
"<TestInstance: #{name}, Type: #{type}>"
-
end
-
-
2
def ==(other_instance)
-
14564
self.class == other_instance.class &&
-
unversioned_name.to_s == other_instance.unversioned_name.to_s &&
-
self.class.attrs.all? do |attr|
-
# Exclude test name, already examined above and don't want to include
-
# the version in the comparison
-
73138
if attr == 'test_name'
-
790
true
-
else
-
72348
send(attr) == other_instance.send(attr)
-
end
-
end
-
end
-
-
2
def self.new_empty(name, attrs = {})
-
new(name, :empty, attrs)
-
end
-
-
2
def self.new_functional(name, attrs = {})
-
new(name, :functional, attrs)
-
end
-
-
2
def self.new_board_pmu(name, attrs = {})
-
new(name, :board_pmu, attrs)
-
end
-
-
2
def self.new_pin_pmu(name, attrs = {})
-
new(name, :pin_pmu, attrs)
-
end
-
-
2
def self.new_apmu_powersupply(name, attrs = {})
-
new(name, :apmu_powersupply, attrs)
-
end
-
-
2
def self.new_powersupply(name, attrs = {})
-
new(name, :powersupply, attrs)
-
end
-
-
2
def self.new_dcvi_powersupply(name, attrs = {})
-
new(name, :dcvi_powersupply, attrs)
-
end
-
-
2
def self.new_mto_memory(name, attrs = {})
-
new(name, :mto_memory, attrs)
-
end
-
-
# Returns the fully formatted test instance for insertion into an instance sheet
-
2
def to_s(override_name = nil)
-
362
l = "\t"
-
362
self.class.attrs.each do |attr|
-
39837
if attr == 'test_name' && override_name
-
18
l += "#{override_name}\t"
-
else
-
39819
l += "#{send(attr)}\t"
-
end
-
end
-
362
"#{l}"
-
end
-
-
2
def name
-
7735
if version && @append_version
-
1429
"#{@test_name}_v#{version}"
-
else
-
6306
@test_name.to_s
-
end
-
end
-
2
alias_method :test_name, :name
-
-
2
def name=(val)
-
969
self.test_name = val
-
end
-
-
2
def unversioned_name
-
28448
@test_name.to_s
-
end
-
-
# Set the cpu wait flags for the given test instance
-
# instance.set_wait_flags(:a)
-
# instance.set_wait_flags(:a, :c)
-
2
def set_wait_flags(*flags)
-
# This method is tester-specific and must be overridden by the child class
-
fail 'The #{self.class} class has not defined a set_wait_flags method!'
-
end
-
-
# Set and enable the hi limit of a parametric test instance, passing in
-
# nil or false as the lim parameter will disable the hi limit.
-
2
def set_hi_limit(lim)
-
if lim
-
self.hi_limit = lim
-
end
-
self
-
end
-
2
alias_method :hi_limit=, :set_hi_limit
-
-
# Set and enable the hi limit of a parametric test instance, passing in
-
# nil or false as the lim parameter will disable the hi limit.
-
2
def set_lo_limit(lim)
-
if lim
-
self.lo_limit = lim
-
end
-
self
-
end
-
2
alias_method :lo_limit=, :set_lo_limit
-
-
# Set the current range of the test instance, the following are valid:
-
#
-
# Board PMU
-
# * 2uA
-
# * 20uA
-
# * 200uA
-
# * 2mA
-
# * 20mA
-
# * 200mA
-
# * :smart
-
#
-
# Pin PMU
-
# * 200nA
-
# * 2uA
-
# * 20uA
-
# * 200uA
-
# * 2mA
-
# * :auto
-
# * :smart
-
#
-
# Examples
-
# instance.set_irange(:smart)
-
# instance.set_irange(:ua => 2)
-
# instance.set_irange(2.uA) # Same as above
-
# instance.set_irange(:ma => 200)
-
# instance.set_irange(0.2) # Same as above
-
# instance.set_irange(:a => 0.2) # Same as above
-
2
def set_irange(r = nil, options = {})
-
r, options = nil, r if r.is_a?(Hash)
-
unless r
-
if r = options.delete(:na) || options.delete(:nA)
-
r = r / 1_000_000_000
-
elsif r = options.delete(:ua) || options.delete(:uA)
-
r = r / 1_000_000.0
-
elsif r = options.delete(:ma) || options.delete(:mA)
-
r = r / 1000.0
-
elsif r = options.delete(:a) || options.delete(:A)
-
else
-
fail "Can't determine requested irange!"
-
end
-
end
-
-
if @type == :board_pmu
-
if r == :smart
-
self.irange = 6
-
else
-
self.irange = case
-
when r > 0.02 then 5
-
when r > 0.002 then 4
-
when r > 0.0002 then 3
-
when r > 0.00002 then 2
-
when r > 0.000002 then 1
-
else 0
-
end
-
end
-
-
elsif @type == :powersupply
-
if r == :smart
-
self.irange = 6
-
elsif r == :auto
-
self.irange = 5
-
else
-
self.irange = case
-
when r > 0.25 then 4 # between 250mA - 1A
-
when r > 0.1 then 7 # between 100mA - 250mA
-
when r > 0.01 then 0 # between 10mA - 100mA
-
when r > 0.0005 then 1 # between 500ua - 10mA
-
when r > 0.00005 then 2 # between 50ua - 500u
-
when r > 0.000005 then 3 # between 5u - 50u
-
else 8
-
end
-
end
-
-
else # :pin_pmu
-
if r == :smart
-
self.irange = 5
-
elsif r == :auto
-
fail 'Auto range not available in FIMV mode!' if self.fimv?
-
self.irange = 6
-
else
-
if fimv?
-
self.irange = case
-
when r > 0.0002 then 2
-
else 4
-
end
-
else
-
self.irange = case
-
when r > 0.0002 then 2
-
when r > 0.00002 then 4
-
when r > 0.000002 then 0
-
when r > 0.0000002 then 1
-
else 3
-
end
-
end
-
end
-
end
-
-
self
-
end
-
-
# Set the voltage range of the test instance, the following are valid:
-
#
-
# Board PMU
-
# * 2V
-
# * 5V
-
# * 10V
-
# * 24V
-
# * :auto
-
# * :smart
-
#
-
# Examples
-
# instance.set_vrange(:auto)
-
# instance.set_vrange(:v => 5)
-
# instance.set_vrange(5) # Same as above
-
2
def set_vrange(r = nil, options = {})
-
r, options = nil, r if r.is_a?(Hash)
-
if r == :smart
-
self.vrange = 4
-
elsif r == :auto
-
self.vrange = 5
-
elsif !r
-
if r = options.delete(:v) || options.delete(:V)
-
else
-
fail "Can't determine requested vrange!"
-
end
-
end
-
self.vrange = case
-
when r > 10 then 3
-
when r > 5 then 2
-
when r > 2 then 1
-
else 0
-
end
-
self
-
end
-
-
# Returns true if instance configured for force current, measure voltage
-
2
def fimv?
-
measure_mode == 1
-
end
-
-
# Returns true if instance configured for force voltage, measure current
-
2
def fvmi?
-
66
measure_mode == 0
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class TestInstanceGroup
-
2
attr_accessor :name, :version, :append_version
-
-
2
include Enumerable
-
-
2
def initialize(name, options = {})
-
12
@name = name
-
12
@store = []
-
12
@append_version = true
-
end
-
-
2
def name
-
97
if unversioned_name
-
97
if version && @append_version
-
85
"#{unversioned_name}_v#{version}"
-
else
-
12
unversioned_name.to_s
-
end
-
end
-
end
-
-
2
def unversioned_name
-
257
if @name
-
257
if @name =~ /grp$/
-
@name
-
else
-
257
"#{@name}_grp"
-
end
-
end
-
end
-
-
2
def <<(instance)
-
36
@store << instance
-
end
-
-
2
def size
-
24
@store.size
-
end
-
-
2
def each
-
162
@store.each { |ins| yield ins }
-
end
-
-
2
def ==(other_instance_group)
-
242
self.class == other_instance_group.class &&
-
unversioned_name.to_s == other_instance_group.unversioned_name.to_s &&
-
size == other_instance_group.size &&
-
self.all? do |ins|
-
78
other_instance_group.any? { |other_ins| ins == other_ins }
-
end
-
end
-
-
2
def finalize
-
12
lambda do |group|
-
6
each do |ti|
-
18
ti.finalize.call(ti) if ti.finalize
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class TestInstances
-
2
include OrigenTesters::Generator
-
-
2
autoload :CustomTil, 'origen_testers/igxl_based_tester/base/test_instances/custom_til'
-
-
2
OUTPUT_POSTFIX = 'instances'
-
-
2
class IndexedString < ::String
-
2
attr_accessor :index
-
-
2
def name
-
12
self
-
end
-
end
-
-
2
def add(name, type, options = {})
-
options = {
-
978
test_instance_class: platform::TestInstance
-
}.merge(options)
-
klass =
-
978
if type.is_a?(Symbol) || type.is_a?(String)
-
969
ins = options.delete(:test_instance_class).new(name, type, options)
-
else
-
9
ins = type
-
end
-
978
if @current_group
-
36
@current_group << ins
-
else
-
942
collection << ins
-
end
-
978
c = Origen.interface.consume_comments
-
978
Origen.interface.descriptions.add_for_test_definition(name, c)
-
978
ins
-
end
-
-
# IG-XL doesn't have a formal instance group type and instead declares them anonymously
-
# whenever test instances of the same name appear consecutively in the test instance sheet.
-
# However when it comes to generating a test program life becomes much easier if we have
-
# a way to explicitly declare instances as part of a group - this makes duplicate tracking
-
# and sorting of the test instance sheet much easier.
-
#
-
# Use this method to generate instance groups via a block. Within the block you should
-
# generate instances as normal and they will automatically be assigned to the current group.
-
# Note that the name of the instances generated within the group is discarded and replaced
-
# with the name of the group. Origen automatically appends "grp" to this name to highlight
-
# instances that were generated as part of the group.
-
#
-
# test_instances.group("erase_all_blocks") do |group|
-
# # Generate instances here as normal
-
# test_instances.functional("erase_blk0")
-
# test_instances.functional("erase_blk1")
-
# end
-
#
-
# The group object is passed into the block but usually you should not need to interact
-
# with this directly except maybe to set the name if it is not yet established at the point
-
# where the group is initiated:
-
#
-
# test_instances.group do |group|
-
# # Generate instances here as normal
-
# group.name = "group_blah"
-
# end
-
#
-
# A common way to generate groups is to create a helper method in your application which
-
# is responsible for creating groups as required:
-
#
-
# def group_wrapper(name, options)
-
# if options[:by_block]
-
# test_instances.group(name) do |group|
-
# yield group
-
# end
-
# else
-
# yield
-
# end
-
# end
-
#
-
# In that case the group argument becomes quite useful for branching based on whether you
-
# are generating a group or standalone instances:
-
#
-
# group_wrapper(name, options) do |group|
-
# if group
-
# # Generate group instances
-
# else
-
# # Generate standalone instances
-
# end
-
# end
-
2
def group(name = nil, options = {})
-
12
name, options = nil, name if name.is_a?(Hash)
-
12
@current_group = platform::TestInstanceGroup.new(name, options)
-
12
collection << @current_group
-
12
yield @current_group
-
12
@current_group = nil
-
end
-
2
alias_method :add_group, :group
-
-
2
def finalize(options = {}) # :nodoc:
-
14
uniq!
-
14
sort_and_finalize!
-
end
-
-
2
def uniq! # :nodoc:
-
14
uniques = []
-
14
versions = {}
-
14
multi_version_tests = {}
-
14
collection.each do |instance|
-
# If a uniquely named instance is found add it, otherwise update the version
-
# of the current instance to match that of the existing instance that it duplicates
-
956
unless uniques.any? do |i|
-
13449
if i == instance
-
595
instance.version = i.version
-
595
true
-
else
-
12854
false
-
end
-
end
-
361
if instance.respond_to?(:version=)
-
359
versions[instance.unversioned_name] ||= 0
-
359
versions[instance.unversioned_name] += 1
-
359
if versions[instance.unversioned_name] > 1
-
40
multi_version_tests[instance.unversioned_name] = true
-
end
-
359
instance.version = versions[instance.unversioned_name]
-
end
-
361
uniques << instance
-
end
-
end
-
# This final loop disables the version identifier for tests that have only a single version,
-
# this makes it clearer when multiple versions exist - whenever you see a v1 you know there
-
# is at least a v2 also.
-
14
collection.map! do |instance|
-
956
if instance.respond_to?(:version=)
-
954
unless multi_version_tests[instance.unversioned_name]
-
695
instance.append_version = false
-
end
-
end
-
956
instance
-
end
-
14
self.collection = uniques
-
end
-
-
2
def sort_and_finalize! # :nodoc:
-
# Present the instances in the final sheet in alphabetical order
-
14
collection.map!.with_index do |ins, i|
-
361
if ins.is_a?(String) # Can happen if content has been rendered in from a template
-
2
ins = IndexedString.new(ins)
-
else
-
359
ins.finalize.call(ins) if ins.finalize
-
end
-
361
ins
-
end
-
1284
collection.sort! { |a, b| [a.name.to_s] <=> [b.name.to_s] }
-
end
-
-
2
def bpmu(name, options = {})
-
4
add(name, :board_pmu, options)
-
end
-
2
alias_method :board_pmu, :bpmu
-
-
2
def powersupply(name, options = {})
-
2
add(name, :powersupply, options)
-
end
-
2
alias_method :power_supply, :powersupply
-
-
2
def dcvi_powersupply(name, options = {})
-
1
add(name, :dcvi_powersupply, options)
-
end
-
-
2
def ppmu(name, options = {})
-
42
add(name, :pin_pmu, options)
-
end
-
2
alias_method :pin_pmu, :ppmu
-
-
2
def functional(name, options = {})
-
918
add(name, :functional, options)
-
end
-
-
2
def empty(name, options = {})
-
add(name, :empty, options)
-
end
-
-
2
def other(name, options = {})
-
add(name, :other, options)
-
end
-
-
2
def apmu_powersupply(name, options = {})
-
add(name, :apmu_powersupply, options)
-
end
-
-
2
def mto_memory(name, options = {})
-
2
add(name, :mto_memory, options)
-
end
-
-
# Creates an accessor for custom test method libraries the first time they are called
-
2
def method_missing(method, *args, &block)
-
3
custom_tils = Origen.interface.send(:custom_tils)
-
3
if custom_tils[method]
-
3
ti = CustomTil.new(self, custom_tils[method])
-
3
instance_variable_set "@#{method}", ti
-
3
define_singleton_method method do
-
9
instance_variable_get("@#{method}")
-
end
-
3
send(method)
-
else
-
super
-
end
-
end
-
-
2
def respond_to?(method)
-
323
!!Origen.interface.send(:custom_tils)[method] || super
-
end
-
end
-
end
-
end
-
end
-
1
module OrigenTesters
-
1
module IGXLBasedTester
-
1
class Base
-
1
class TestInstances
-
# Custom Test Instance library
-
1
class CustomTil
-
# Returns the test_instances object for the current flow
-
1
attr_reader :test_instances
-
1
attr_reader :definitions
-
-
1
def initialize(test_instances, definitions)
-
3
@test_instances = test_instances
-
3
@definitions = definitions
-
end
-
-
1
def method_missing(method, *args, &block)
-
9
if definitions[method]
-
9
name = args.shift
-
9
ti = platform::CustomTestInstance.new name, methods: definitions[method].dup,
-
9
attrs: (args.first || {}),
-
type: method,
-
library: self
-
9
test_instances.add(nil, ti)
-
9
ti
-
else
-
super
-
end
-
end
-
-
1
def platform
-
9
test_instances.platform
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class Timeset
-
2
attr_accessor :master_ts, :t_mode # Timeset information
-
2
attr_accessor :pins
-
2
attr_accessor :name
-
-
# Specify timeset information by providing a pin and its associated edge timing
-
2
def initialize(name, pin, edge, attrs = {}) # :nodoc:
-
attrs = {
-
4
master_ts: '', # master timeset name
-
t_mode: '' # timing mode (possibly ATE-specific)
-
}.merge(attrs)
-
4
@master_ts = attrs[:master_ts]
-
4
@t_mode = attrs[:t_mode]
-
4
@pins = { pin => edge }
-
4
self.name = name
-
end
-
-
# Assigns a timing edge object to the given pin for this timeset
-
2
def add_edge(pin, edge)
-
12
if @pins.key?(pin)
-
Origen.log.error "Pin #{pin} already exists in timeset"
-
fail
-
else
-
12
@pins[pin] = edge
-
end
-
end
-
-
2
def platform
-
Origen.interface.platform
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class Timesets
-
2
include ::OrigenTesters::Generator
-
-
2
attr_accessor :ts
-
2
attr_accessor :ts_sheet_pins
-
2
attr_accessor :ts_basic
-
-
2
OUTPUT_PREFIX = 'TS'
-
# OUTPUT_POSTFIX = 'TS'
-
-
2
def initialize(options = {}) # :nodoc:
-
1
@ts = {}
-
1
@ts_basic = options[:timeset_basic]
-
end
-
-
2
def add(tsname, pin, esname, options = {})
-
8
tsname = tsname.to_sym unless tsname.is_a? Symbol
-
8
pin = pin.to_sym unless pin.is_a? Symbol
-
8
esname = pin.to_sym unless esname.is_a? Symbol
-
8
@ts.key?(tsname) ? @ts[tsname].add_edge(pin, esname) : @ts[tsname] = platform::Timeset.new(tsname, pin, esname, options)
-
8
@ts_sheet_pins = options[:ts_sheet_pins] unless @ts_sheet_pins
-
8
@ts[tsname]
-
end
-
-
2
def finalize(options = {})
-
end
-
-
# Populate an array of pins based on the pin or pingroup
-
2
def get_pin_objects(grp)
-
20
pins = []
-
20
if Origen.top_level.pin(grp).is_a?(Origen::Pins::Pin) ||
-
Origen.top_level.pin(grp).is_a?(Origen::Pins::FunctionProxy)
-
20
pins << Origen.top_level.pin(grp)
-
elsif Origen.top_level.pin(grp).is_a?(Origen::Pins::PinCollection)
-
Origen.top_level.pin(grp).each do |pin|
-
pins << pin
-
end
-
else
-
Origen.log.error "Could not find pin class: #{grp} #{Origen.top_level.pin(grp).class}"
-
end
-
20
pins
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Base
-
2
class TimesetsBasic
-
2
include ::OrigenTesters::Generator
-
-
2
attr_accessor :ts
-
2
attr_accessor :ts_sheet_pins
-
2
attr_accessor :ts_basic
-
-
2
OUTPUT_PREFIX = 'TSB'
-
# OUTPUT_POSTFIX = 'TS'
-
-
2
def initialize(options = {}) # :nodoc:
-
1
@ts = {}
-
1
@ts_basic = options[:timeset_basic]
-
end
-
-
2
def add(tsname, pin, esname, options = {})
-
8
tsname = tsname.to_sym unless tsname.is_a? Symbol
-
8
pin = pin.to_sym unless pin.is_a? Symbol
-
8
esname = pin.to_sym unless esname.is_a? Symbol
-
8
@ts.key?(tsname) ? @ts[tsname].add_edge(pin, esname) : @ts[tsname] = platform::Timeset.new(tsname, pin, esname, options)
-
8
@ts_sheet_pins = options[:ts_sheet_pins] unless @ts_sheet_pins
-
8
@ts[tsname]
-
end
-
-
2
def finalize(options = {})
-
end
-
-
# Populate an array of pins based on the pin or pingroup
-
2
def get_pin_objects(grp)
-
20
pins = []
-
20
if Origen.top_level.pin(grp).is_a?(Origen::Pins::Pin) ||
-
Origen.top_level.pin(grp).is_a?(Origen::Pins::FunctionProxy)
-
20
pins << Origen.top_level.pin(grp)
-
elsif Origen.top_level.pin(grp).is_a?(Origen::Pins::PinCollection)
-
Origen.top_level.pin(grp).each do |pin|
-
pins << pin
-
end
-
else
-
Origen.log.error "Could not find pin class: #{grp} #{Origen.top_level.pin(grp).class}"
-
end
-
20
pins
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
# Currently, we aren't differentiating between J750 and UFLEX testers. They'll both use the same until
-
# there are difference that require forking the decompiler.
-
-
2
def self.suitable_decompiler_for(pattern: nil, tester: nil, **options)
-
28
if pattern && (Pathname(pattern).extname == ".#{OrigenTesters::IGXLBasedTester.pat_extension}")
-
17
OrigenTesters::IGXLBasedTester::Pattern
-
11
elsif tester && (tester == 'j750' || tester == 'uflex' || tester == 'ultraflex')
-
2
OrigenTesters::IGXLBasedTester::Pattern
-
end
-
end
-
2
extend OrigenTesters::Decompiler::API
-
2
register_decompiler(self)
-
-
2
class Pattern < OrigenTesters::Decompiler::Pattern
-
2
require_relative './decompiler/atp'
-
2
extend Atp
-
-
2
@platform = 'j750'
-
@splitter_config = {
-
2
pinlist_start: /\$tset/,
-
vectors_start: /^{/,
-
vectors_end: /^}/,
-
vectors_include_start_line: false,
-
vectors_include_end_line: false
-
}
-
-
@platform_tokens = {
-
2
comment_start: OrigenTesters::IGXLBasedTester.comment_char
-
}
-
end
-
-
2
def self._sample_direct_source_
-
[
-
'// Sample pattern text for the J750',
-
'// Source located at: lib/origen_testers/igxl_based_tester/decompiler',
-
'',
-
'import tset tp0;',
-
'svm_only_file = no;',
-
'opcode_mode = extended;',
-
'compressed = yes;',
-
'',
-
'vector ($tset, tclk, tdi, tdo, tms)',
-
'{',
-
'start_label pattern_st:',
-
'// Start of vector body',
-
'repeat 2 > tp0 X X X X ; // First Vector',
-
'repeat 5 > tp0 1 0 X 1 ;',
-
'end_module > tp0 X X X X ; // Last Vector',
-
'}'
-
]
-
end
-
-
2
def self.sample_direct_source
-
_sample_direct_source_.join("\n")
-
end
-
-
2
def self.write_sample_source
-
unless Dir.exist?(sample_source_atp.dirname)
-
Origen.log.info "Creating directory #{sample_source_atp.dirname}"
-
FileUtils.mkdir_p(sample_source_atp.dirname)
-
end
-
File.open(sample_source_atp, 'w').puts(sample_direct_source)
-
sample_source_atp
-
end
-
-
2
def self.sample_source_atp
-
Origen.app!.root.join('approved/j750/decompiler/sample/sample.atp')
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class Pattern
-
2
require_relative './nodes'
-
-
2
module Atp
-
2
def nodes_namespace
-
32719
OrigenTesters::IGXLBasedTester::Decompiler::Atp
-
end
-
-
2
def parse_frontmatter(raw_frontmatter:, context:)
-
20
in_header = true
-
20
header = []
-
20
comments = []
-
20
variable_assignments = {}
-
20
imports = {}
-
20
raw_frontmatter.each_with_index do |l, i|
-
438
if l =~ Regexp.new('^\s*//')
-
331
if in_header
-
# Header Comment
-
331
header << l.chomp
-
else
-
# Other Comment
-
comments << l.chomp
-
end
-
107
elsif !(l =~ Regexp.new(/=/)).nil?
-
# Variable Assignment
-
54
var, val = l.split('=').map(&:strip)
-
54
variable_assignments[var] = val.gsub(';', '')
-
53
elsif !(l =~ Regexp.new(/import/)).nil?
-
# Import
-
34
import, type, val = l.split(/\s+/)
-
34
imports[val.gsub(';', '')] = type
-
19
elsif l.strip.empty?
-
# Just whitespace. Ignore this, but don't throw an error
-
1
elsif !(l =~ Regexp.new(/vector/)).nil?
-
# line break between vector keyword and pinlist, ignore
-
else
-
1
Origen.app!.fail!("Unable to parse pattern frontmatter, at line: #{i}")
-
end
-
end
-
19
nodes_namespace::Frontmatter.new(context: self,
-
pattern_header: header,
-
variable_assignments: variable_assignments,
-
imports: imports,
-
comments: comments
-
)
-
end
-
-
2
def parse_pinlist(raw_pinlist:, context:)
-
19
raw_pinlist = raw_pinlist.join('')
-
19
OrigenTesters::Decompiler::Nodes::Pinlist.new(context: self,
-
pins: raw_pinlist[raw_pinlist.index('$') + 1..raw_pinlist.index(')') - 1].split(/,\s*/)[1..-1]
-
)
-
end
-
-
2
def parse_vector(raw_vector:, context:, meta:)
-
32701
if raw_vector =~ Regexp.new('^\s*//')
-
7489
nodes_namespace::CommentBlock.new(context: self,
-
comments: raw_vector.split("\n")
-
)
-
25212
elsif raw_vector.strip.size == 0
-
nodes_namespace::CommentBlock.new(context: self, comments: ['// blank line replaced with comment by origen convert'])
-
25212
elsif raw_vector =~ Regexp.new('^\s*start_label')
-
317
nodes_namespace::StartLabel.new(context: self,
-
start_label: raw_vector[raw_vector.index('start_label') + 11..-1].strip[0..-2]
-
)
-
24895
elsif raw_vector =~ Regexp.new('^\s*global')
-
213
contents = raw_vector.strip['global'.size + 1..-2].strip.split(/\s+/)
-
213
nodes_namespace::GlobalLabel.new(context: self,
-
label_type: contents[0],
-
label_name: contents[1]
-
)
-
# original elsif for label was updated to avoid confusing origen's eol comments for a label
-
# elsif raw_vector =~ Regexp.new(':(?!(.*>))')
-
24682
elsif raw_vector.split(';').first =~ Regexp.new(':(?!(.*>))')
-
2406
nodes_namespace::Label.new(context: self,
-
# Strip any whitespace from the vector and grab contents up to
-
# the ':' symbol.
-
label_name: raw_vector.strip[0..-2]
-
)
-
else
-
-
22276
opcode_plus_args = raw_vector[0..(raw_vector.index('>') - 1)].rstrip.split(/\s+/)
-
22275
timeset_plus_pins = raw_vector[(raw_vector.index('>') + 1)..(raw_vector.index(';') - 1)].strip.split(/\s+/)
-
22275
nodes_namespace::Vector.new(context: self,
-
timeset: timeset_plus_pins[0],
-
pin_states: timeset_plus_pins[1..-1],
-
22275
opcode: (opcode_plus_args[0] && opcode_plus_args[0].empty?) ? nil : opcode_plus_args[0],
-
opcode_arguments: opcode_plus_args[1..-1],
-
comment: begin
-
22275
if raw_vector =~ Regexp.new('//')
-
raw_vector[raw_vector.index('//') + 2..-1].strip
-
else
-
22275
''
-
end
-
end
-
)
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
module Decompiler
-
2
module Atp
-
2
class Vector < OrigenTesters::Decompiler::Nodes::Vector
-
2
PLATFORM_NODES = [:opcode, :opcode_arguments]
-
-
2
def initialize(**options)
-
22275
@opcode = options[:opcode]
-
22275
@opcode_arguments = options[:opcode_arguments] || []
-
22275
super(repeat: false, **options)
-
end
-
-
2
def repeat
-
423
opcode == 'repeat' ? opcode_arguments.first.to_i : 1
-
end
-
-
2
def opcode
-
@opcode
-
end
-
-
2
def opcode_arguments
-
@opcode_arguments
-
end
-
end
-
-
2
class StartLabel < OrigenTesters::Decompiler::Nodes::Node
-
2
PLATFORM_NODES = [:start_label]
-
-
2
def initialize(start_label:, context:)
-
317
@execute = false
-
317
@start_label = start_label
-
-
317
super(context: context, type: :start_label)
-
end
-
end
-
-
2
class Frontmatter < OrigenTesters::Decompiler::Nodes::Frontmatter
-
2
PLATFORM_NODES = [:variable_assignments, :imports]
-
-
2
def initialize(pattern_header:, comments:, variable_assignments:, imports:, context:)
-
19
@variable_assignments = variable_assignments
-
19
@imports = imports
-
-
19
super(pattern_header: pattern_header, comments: comments, context: context)
-
end
-
end
-
-
2
class CommentBlock < OrigenTesters::Decompiler::Nodes::CommentBlock
-
end
-
-
2
class Label < OrigenTesters::Decompiler::Nodes::Node
-
2
PLATFORM_NODES = [:label_name]
-
-
2
def initialize(label_name:, context:)
-
2406
@execute = false
-
2406
@label_name = label_name
-
-
2406
super(context: context, type: :label)
-
end
-
end
-
-
2
class GlobalLabel < OrigenTesters::Decompiler::Nodes::Node
-
2
PLATFORM_NODES = [:label_type, :label_name]
-
-
2
def initialize(label_type:, label_name:, context:)
-
213
@execute = false
-
213
@label_type = label_type
-
213
@label_name = label_name
-
-
213
super(context: context, type: :global_label)
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
# Tester model to generate .atp patterns for the Teradyne J750
-
#
-
# == Basic Usage
-
# $tester = Testers::J750.new
-
# $tester.cycle # Generate a vector
-
#
-
# Many more methods exist to generate J750 specific micro-code, see below for
-
# details.
-
#
-
# Also note that this class inherits from the base Tester class and so all methods
-
# described there are also available.
-
2
class J750 < Base
-
2
require 'origen_testers/igxl_based_tester/j750/generator.rb'
-
-
2
attr_accessor :use_hv_pin
-
2
attr_accessor :software_version
-
-
2
def self.hpt_mode
-
1
@@hpt_mode
-
end
-
2
def self.hpt_mode?
-
@@hpt_mode
-
end
-
-
# Returns a new J750 instance, normally there would only ever be one of these
-
# assigned to the global variable such as $tester by your target.
-
2
def initialize(options = {})
-
201
super(options)
-
201
@pipeline_depth = 34 # for extended mode is vectors, for normal mode is vector pairs (54 for J750Ex)
-
201
@use_hv_pin = false # allows to use high voltage for a pin for all patterns
-
201
@software_version = '3.50.40'
-
201
@name = 'j750'
-
201
@@hpt_mode = false
-
201
@opcode_mode = :extended
-
201
@loop_bits_max = 16 # maximum loop bit length
-
-
201
@flags = %w(cpuA cpuB cpuC cpuD)
-
201
@microcode[:enable] = 'enable'
-
201
@microcode[:set_flag] = 'set_cpu'
-
201
@microcode[:mask_vector] = 'ign ifc icc'
-
201
@microcode[:keepalive] = 'keep_alive'
-
end
-
-
2
def pattern_header(options = {})
-
65
super(options) do |pin_list|
-
65
microcode "vector ($tset, #{pin_list})"
-
65
microcode '{'
-
65
unless options[:subroutine_pat]
-
63
microcode 'start_label pattern_st:'
-
end
-
end
-
end
-
-
2
def pattern_footer(options = {})
-
65
super(options)
-
end
-
-
# Generates a match loop based on vector condition passed in via block
-
#
-
# This method is not really intended to be called directly, rather you should call
-
# via Tester#wait:
-
# e.g. $tester.wait(:match => true) do
-
# reg(:status_reg).bit(:done).read(1)! # vector condition that you want to match
-
# end
-
#
-
# The timeout should be provided in cycles, however when called via the wait method the
-
# time-based helpers (time_in_us, etc) will be converted to cycles for you.
-
#
-
# The following options are available to tailor the match loop behavior, defaults in
-
# parenthesis:
-
# * :check_for_fails (false) - Flushes the pipeline and handshakes with the tester (passing readcode 100) prior to the match (to allow binout of fails encountered before the match)
-
# * :force_fail_on_timeout (true) - Force a vector mis-compare if the match loop times out
-
# * :on_timeout_goto ("") - Optionally supply a label to branch to on timeout, by default will continue from the end of the match loop
-
# * :on_block_match_goto ("") - Optionally supply a label to branch to when block condition is met, by default will continue from the end of the match loop.
-
# A hash will also be accepted for this argument to supply a specific label (or no label) for each block e.g. <code>{0 => "on_block_0_fail"}</code>
-
# * :multiple_entries (false) - Supply an integer to generate multiple entries into the match (each with a unique readcode), this can be useful when debugging patterns with multiple matches
-
# * :force_fail_on_timeout (true) - force pattern to fail if timeout occurs
-
# * :global_loops (false) - whether match loop loops should use global labels
-
# * :manual_stop (false) - whether to use extra cpuB flag to resolve IG-XL v.3.50.xx bug where VBT clears cpuA immediately
-
# at start of PatFlagFunc instead of at end. Use will have to manually clear cpuB to resume this pattern.
-
# ==== Examples
-
# $tester.wait(:match => true, :time_in_us => 5000, :pin => $top.pin(:done), :state => :high) do
-
# <vectors>
-
# end
-
2
def match_block(timeout, options = {}, &block)
-
options = {
-
28
check_for_fails: false,
-
on_timeout_goto: false,
-
on_block_match_goto: false,
-
multiple_entries: false,
-
force_fail_on_timeout: true,
-
global_loops: false,
-
manual_stop: false,
-
clr_fail_post_match: false
-
}.merge(options)
-
-
28
unless block_given?
-
fail 'ERROR: block not passed to match_block!'
-
end
-
-
# Create BlockArgs objects in order to receive multiple blocks
-
28
match_conditions = Origen::Utility::BlockArgs.new
-
28
fail_conditions = Origen::Utility::BlockArgs.new
-
-
# yield object to calling routine to get populated with blocks
-
28
if block.arity > 0
-
18
yield match_conditions, fail_conditions
-
else
-
# for backwards compatibility with Origen core call to match_block
-
10
match_conditions.add(&block)
-
10
fail_conditions.add(&block)
-
end
-
-
# Flush the pipeline first and then pass control to the program to bin out any failures
-
# prior to entering the match loop
-
28
if options[:check_for_fails]
-
18
if options[:multiple_entries]
-
2
@match_entries.times do |i|
-
20
microcode "global subr match_done_#{i}:"
-
20
set_code(i + 100)
-
20
cycle(microcode: 'jump call_tester') unless i == @match_entries - 1
-
end
-
2
microcode 'call_tester:'
-
else
-
16
set_code(100)
-
end
-
18
cc 'Wait for any prior failures to propagate through the pipeline'
-
18
cycle(microcode: 'pipe_minus 1')
-
18
cc 'Now handshake with the tester to bin out and parts that have failed before they got here'
-
18
handshake(manual_stop: options[:manual_stop])
-
end
-
-
# Now do the main match loop
-
28
cc 'Start the match loop'
-
-
28
global_opt = (options[:global_loops]) ? 'global ' : ''
-
28
microcode "#{global_opt}match_outer_loop_#{@unique_counter}:"
-
28
cycle # (:microcode => "loopB #{outer_loop_count} ign ifc icc")
-
28
set_loopb_vector = last_vector
-
-
28
microcode "#{global_opt}match_inner_loop_#{@unique_counter}:"
-
28
cycle # (:microcode => "loopA #{inner_loop_count} ign ifc icc")
-
28
set_loopa_vector = last_vector
-
-
# count cycles in match loop block passed to help with meeting
-
# desired timeout value (have to back assign microcodes above)
-
28
prematch_cycle_count = cycle_count
-
28
match_conditions.each_with_index do |condition, i|
-
35
mask_fails(true)
-
35
condition.call # match condition
-
35
mask_fails(false)
-
35
cc ' Wait for the result to propagate through the pipeline'
-
35
cycle(microcode: 'pipe_minus 1 ign ifc icc')
-
35
inc_cycle_count(@pipeline_depth - 1) # Account for pipeline depth
-
35
cc "Branch if block condition #{i} met"
-
35
cycle(microcode: "if (pass) jump block_#{i}_matched_#{@unique_counter} icc ifc")
-
35
cycle(microcode: 'clr_flag (fail) icc')
-
end
-
28
match_conditions_cycle_count = cycle_count - prematch_cycle_count
-
28
cc "Match loop cycle count = #{match_conditions_cycle_count}"
-
-
# reduce timeout requested by match loop cycle count
-
28
timeout = (timeout.to_f / match_conditions_cycle_count).ceil
-
-
# Calculate the loop counts for the 2 loops to appropriately hit the timeout requested
-
28
loop_value = timeout.to_f.floor
-
-
28
if loop_value < (2**@loop_bits_max)
-
# small value, only need to use one loop
-
18
outer_loop_count = 1
-
18
inner_loop_count = loop_value
-
10
elsif loop_value < (2**(2 * @loop_bits_max))
-
# 2 nested loops required
-
10
inner_loop_count = 2**@loop_bits_max - 1
-
10
outer_loop_count = (loop_value.to_f / inner_loop_count).ceil
-
else
-
abort 'ERROR: timeout value too large in tester match method!'
-
end
-
-
# retroactively set loop counter values for timeout based on cycles in match loop condition
-
28
unless @inhibit_vectors
-
24
set_loopb_vector.microcode = "loopB #{outer_loop_count} ign ifc icc"
-
24
set_loopa_vector.microcode = "loopA #{inner_loop_count} ign ifc icc"
-
end
-
-
28
cc 'Loop back around if time remaining'
-
28
cycle(microcode: "end_loopA match_inner_loop_#{@unique_counter} icc")
-
28
cycle(microcode: "end_loopB match_outer_loop_#{@unique_counter} icc")
-
-
28
if options[:force_fail_on_timeout]
-
28
cc 'To get here something has gone wrong, check block again to force a pattern failure'
-
28
fail_conditions.each(&:call)
-
end
-
-
28
if options[:on_timeout_goto]
-
2
cycle(microcode: "jump #{options[:on_timeout_goto]} icc")
-
else
-
26
cycle(microcode: "jump match_loop_end_#{@unique_counter} icc")
-
# cycle(:microcode => 'halt')
-
end
-
28
match_conditions.each_with_index do |condition, i|
-
35
microcode "block_#{i}_matched_#{@unique_counter}:"
-
35
cycle(microcode: 'pop_loop icc')
-
35
cycle(microcode: 'clr_fail')
-
35
if options[:on_block_match_goto]
-
4
if options[:on_block_match_goto].is_a?(Hash)
-
4
if options[:on_block_match_goto][i]
-
2
custom_jump = options[:on_block_match_goto][i]
-
else
-
2
custom_jump = nil
-
end
-
else
-
custom_jump = options[:on_block_match_goto]
-
end
-
end
-
35
if custom_jump
-
2
cycle(microcode: "jump #{custom_jump}")
-
else
-
# Don't do a jump on the last match block as it will naturally fall through
-
# TODO: Update origen core to expose the size
-
33
unless match_conditions.instance_variable_get(:@block_args).size == i + 1
-
5
cycle(microcode: "jump match_loop_end_#{@unique_counter} icc")
-
end
-
end
-
end
-
28
microcode "match_loop_end_#{@unique_counter}:"
-
28
if options[:clr_fail_post_match]
-
20
cycle(microcode: 'clr_fail')
-
end
-
-
28
@unique_counter += 1 # Increment so a different label will be applied if another
-
# handshake is called in the same pattern
-
end
-
-
# Handshake with the tester.
-
#
-
# Will set a cpu flag (A) and wait for it to be cleared by the tester, optionally
-
# pass in a read code to pass information to the tester.
-
#
-
# ==== Examples
-
# $tester.handshake # Pass control to the tester for a measurement
-
# $tester.handshake(:readcode => 10) # Trigger a specific action by the tester
-
2
def handshake(options = {})
-
options = {
-
26
readcode: false,
-
manual_stop: false, # set a 2nd CPU flag in case 1st flag is automatically cleared
-
}.merge(options)
-
26
if options[:readcode]
-
5
set_code(options[:readcode])
-
end
-
26
if options[:manual_stop]
-
18
cycle(microcode: "#{@microcode[:enable]} (#{@flags[1]})")
-
18
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[0]} #{@flags[1]})")
-
18
cycle(microcode: "loop_here_#{@unique_counter}: if (flag) jump loop_here_#{@unique_counter}")
-
else
-
8
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[0]})")
-
8
cycle(microcode: "loop_here_#{@unique_counter}: if (#{@flags[0]}) jump loop_here_#{@unique_counter}")
-
end
-
26
@unique_counter += 1 # Increment so a different label will be applied if another
-
# handshake is called in the same pattern
-
end
-
-
2
def keep_alive(options = {})
-
2
$tester.cycle microcode: "#{@microcode[:keepalive]}"
-
end
-
end
-
end
-
2
J750 = IGXLBasedTester::J750
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750
-
2
require 'origen_testers/igxl_based_tester/base/custom_test_instance'
-
2
class CustomTestInstance < Base::CustomTestInstance
-
# Attributes for each test instance line, first few are named directly
-
TEST_INSTANCE_ATTRS = %w(
-
2
test_name proc_type proc_name proc_called_as dc_category
-
dc_selector ac_category ac_selector
-
time_sets edge_sets pin_levels overlay
-
)
-
-
# Attributes for additional test instance arguments beyond those described above
-
2
TEST_INSTANCE_EXTRA_ARGS = 80
-
-
TEST_INSTANCE_DEFAULTS = {
-
2
proc_type: 'Other',
-
proc_called_as: 'VB DLL'
-
}
-
-
TEST_INSTANCE_ALIASES = {
-
2
name: :test_name,
-
time_set: :time_sets,
-
timeset: :time_sets,
-
timesets: :time_sets
-
}
-
-
2
define
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750
-
2
require 'origen_testers/igxl_based_tester/base/flow'
-
2
class Flow < Base::Flow
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/j750/templates/flow.txt.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750
-
2
require 'origen_testers/igxl_based_tester/base/flow_line'
-
2
class FlowLine < Base::FlowLine
-
# Attributes for each flow line, these must be declared in the order they are to be output
-
2
TESTER_FLOWLINE_ATTRS = %w(label enable job part env opcode parameter tname tnum bin_pass bin_fail
-
sort_pass sort_fail result flag_pass flag_fail state
-
group_specifier group_sense group_condition group_name
-
device_sense device_condition device_name
-
debug_assume debug_sites comment
-
)
-
-
# Generate the instance method definitions based on the above
-
2
define
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750
-
# Include this module in an interface class to make it a J750 interface and to give
-
# access to the J750 program generator API
-
2
module Generator
-
2
extend ActiveSupport::Concern
-
-
2
require_all "#{Origen.root!}/lib/origen_testers/igxl_based_tester/j750"
-
2
require 'origen_testers/igxl_based_tester/base/generator'
-
-
2
included do
-
9
include Base::Generator
-
9
PLATFORM = J750
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750
-
2
require 'origen_testers/igxl_based_tester/base/patgroup'
-
2
class Patgroup < Base::Patgroup
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750
-
2
require 'origen_testers/igxl_based_tester/base/patgroups'
-
2
class Patgroups < Base::Patgroups
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/j750/templates/patgroups.txt.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750
-
2
require 'origen_testers/igxl_based_tester/base/patset'
-
2
class Patset < Base::Patset
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750
-
2
require 'origen_testers/igxl_based_tester/base/patset_pattern'
-
2
class PatsetPattern < Base::PatsetPattern
-
# Attributes for each pattern set line
-
2
PATSET_ATTRS = %w(pattern_set file_name start_label stop_label comment)
-
-
# Pattern set defaults
-
2
PATSET_DEFAULTS = {
-
}
-
-
# Generate the instance method definitions based on the above
-
2
define
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750
-
2
require 'origen_testers/igxl_based_tester/base/patsets'
-
2
class Patsets < Base::Patsets
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/j750/templates/patsets.txt.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750
-
2
require 'origen_testers/igxl_based_tester/base/patsubr'
-
2
class Patsubr < Base::Patsubr
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750
-
2
require 'origen_testers/igxl_based_tester/base/patsubr_pattern'
-
2
class PatsubrPattern < Base::PatsubrPattern
-
# Attributes for each pattern subroutine line
-
2
PATSUBR_ATTRS = %w(file_name comment)
-
-
# Pattern subroutine defaults
-
2
PATSUBR_DEFAULTS = {
-
}
-
-
# Generate the instance method definitions based on the above
-
2
define
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750
-
2
require 'origen_testers/igxl_based_tester/base/patsubrs'
-
2
class Patsubrs < Base::Patsubrs
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/j750/templates/patsubrs.txt.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750
-
2
require 'origen_testers/igxl_based_tester/base/test_instance'
-
2
class TestInstance < Base::TestInstance
-
# Attributes for each test instance line, first few are named directly
-
TEST_INSTANCE_ATTRS = %w(
-
2
test_name proc_type proc_name proc_called_as dc_category
-
dc_selector ac_category ac_selector
-
time_sets edge_sets pin_levels overlay
-
)
-
-
# Attributes for additional test instance arguments beyond those described above
-
2
TEST_INSTANCE_EXTRA_ARGS = 80
-
-
TEST_INSTANCE_ALIASES = {
-
2
name: :test_name,
-
time_set: :time_sets,
-
timeset: :time_sets,
-
timesets: :time_sets,
-
-
other: {
-
},
-
-
empty: {
-
start_func: :arg0,
-
start_of_body_f: :arg0,
-
pre_pat_func: :arg1,
-
pre_pat_f: :arg1,
-
pre_test_func: :arg2,
-
pre_test_f: :arg2,
-
post_test_func: :arg3,
-
post_test_f: :arg3,
-
post_pat_func: :arg4,
-
post_pat_f: :arg4,
-
end_func: :arg5,
-
end_of_body_f: :arg5,
-
start_func_args: :arg6,
-
start_of_body_f_args: :arg6,
-
pre_pat_func_args: :arg7,
-
pre_pat_f_args: :arg7,
-
pre_test_func_args: :arg8,
-
pre_test_f_args: :arg8,
-
post_test_func_args: :arg9,
-
post_test_f_args: :arg9,
-
post_pat_func_args: :arg10,
-
post_pat_f_args: :arg10,
-
end_func_args: :arg11,
-
end_of_body_f_args: :arg11,
-
utility_pins_1: :arg12,
-
utility_pins_0: :arg13,
-
init_lo: :arg14,
-
start_lo: :arg14,
-
init_hi: :arg15,
-
start_hi: :arg15,
-
init_hiz: :arg16,
-
start_hiz: :arg16,
-
float_pins: :arg17
-
},
-
-
# Functional test instances
-
functional: {
-
pattern: :arg0,
-
patterns: :arg0,
-
start_func: :arg1,
-
start_of_body_f: :arg1,
-
pre_pat_func: :arg2,
-
pre_pat_f: :arg2,
-
pre_test_func: :arg3,
-
pre_test_f: :arg3,
-
post_test_func: :arg4,
-
post_test_f: :arg4,
-
post_pat_func: :arg5,
-
post_pat_f: :arg5,
-
end_func: :arg6,
-
end_of_body_f: :arg6,
-
set_pass_fail: :arg7,
-
init_lo: :arg8,
-
start_lo: :arg8,
-
init_hi: :arg9,
-
start_hi: :arg9,
-
init_hiz: :arg10,
-
start_hiz: :arg10,
-
float_pins: :arg11,
-
start_func_args: :arg13,
-
start_of_body_f_args: :arg13,
-
pre_pat_func_args: :arg14,
-
pre_pat_f_args: :arg14,
-
pre_test_func_args: :arg15,
-
pre_test_f_args: :arg15,
-
post_test_func_args: :arg16,
-
post_test_f_args: :arg16,
-
post_pat_func_args: :arg17,
-
post_pat_f_args: :arg17,
-
end_func_args: :arg18,
-
end_of_body_f_args: :arg18,
-
utility_pins_1: :arg19,
-
utility_pins_0: :arg20,
-
wait_flags: :arg21,
-
wait_time: :arg22,
-
pattern_timeout: :arg22,
-
pat_flag_func: :arg23,
-
pat_flag_f: :arg23,
-
PatFlagF: :arg23,
-
pat_flag_func_args: :arg24,
-
pat_flag_f_args: :arg24,
-
relay_mode: :arg25,
-
threading: :arg26,
-
match_all_sites: :arg27,
-
capture_mode: :arg30,
-
capture_what: :arg31,
-
capture_memory: :arg32,
-
capture_size: :arg33,
-
datalog_mode: :arg34,
-
data_type: :arg35
-
},
-
-
board_pmu: {
-
hsp_start: :arg0,
-
start_func: :arg1,
-
start_of_body_f: :arg1,
-
pre_pat_func: :arg2,
-
pre_pat_f: :arg2,
-
pre_test_func: :arg3,
-
pre_test_f: :arg3,
-
post_test_func: :arg4,
-
post_test_f: :arg4,
-
post_pat_func: :arg5,
-
post_pat_f: :arg5,
-
end_func: :arg6,
-
end_of_body_f: :arg6,
-
precond_pat: :arg7,
-
hold_state_pat: :arg8,
-
holdstate_pat: :arg8,
-
pattern: :arg8,
-
pcp_stop: :arg9,
-
wait_flags: :arg10,
-
start_lo: :arg11,
-
init_lo: :arg11,
-
start_hi: :arg12,
-
init_hi: :arg12,
-
start_hiz: :arg13,
-
init_hiz: :arg13,
-
float_pins: :arg14,
-
pinlist: :arg15,
-
pin: :arg15,
-
pin_list: :arg15,
-
measure_mode: :arg16,
-
irange: :arg17,
-
clamp: :arg18,
-
vrange: :arg19,
-
sampling_time: :arg20,
-
samples: :arg21,
-
settling_time: :arg22,
-
hi_lo_lim_valid: :arg23,
-
hi_lo_limit_valid: :arg23,
-
hi_limit: :arg24,
-
lo_limit: :arg25,
-
force_cond_1: :arg26,
-
force_cond: :arg26,
-
force_condition: :arg26,
-
force_cond_2: :arg27,
-
gang_pins_tested: :arg28,
-
relay_mode: :arg29,
-
wait_time_out: :arg30,
-
start_func_args: :arg31,
-
start_of_body_f_args: :arg31,
-
pre_pat_func_args: :arg32,
-
pre_pat_f_args: :arg32,
-
pre_test_func_args: :arg33,
-
pre_test_f_args: :arg33,
-
post_test_func_args: :arg34,
-
post_test_f_args: :arg34,
-
post_pat_func_args: :arg35,
-
post_pat_f_args: :arg35,
-
end_func_args: :arg36,
-
end_of_body_f_args: :arg36,
-
pcp_start: :arg37,
-
pcp_check_pg: :arg38,
-
hsp_stop: :arg39,
-
hsp_check_pg: :arg40,
-
resume_pat: :arg41,
-
utility_pins_1: :arg42,
-
utility_pins_0: :arg43,
-
pre_charge_enable: :arg44,
-
pre_charge: :arg45,
-
threading: :arg46
-
},
-
-
pin_pmu: {
-
hsp_start: :arg0,
-
start_func: :arg1,
-
start_of_body_f: :arg1,
-
pre_pat_func: :arg2,
-
pre_pat_f: :arg2,
-
pre_test_func: :arg3,
-
pre_test_f: :arg3,
-
post_test_func: :arg4,
-
post_test_f: :arg4,
-
post_pat_func: :arg5,
-
post_pat_f: :arg5,
-
end_func: :arg6,
-
end_of_body_f: :arg6,
-
precond_pat: :arg7,
-
hold_state_pat: :arg8,
-
holdstate_pat: :arg8,
-
pattern: :arg8,
-
pcp_stop: :arg9,
-
wait_flags: :arg10,
-
start_lo: :arg11,
-
init_lo: :arg11,
-
start_hi: :arg12,
-
init_hi: :arg12,
-
start_hiz: :arg13,
-
init_hiz: :arg13,
-
float_pins: :arg14,
-
pinlist: :arg15,
-
pin: :arg15,
-
pin_list: :arg15,
-
measure_mode: :arg16,
-
irange: :arg17,
-
settling_time: :arg18,
-
hi_lo_lim_valid: :arg19,
-
hi_lo_limit_valid: :arg19,
-
hi_limit: :arg20,
-
lo_limit: :arg21,
-
force_cond_1: :arg22,
-
force_cond: :arg22,
-
force_condition: :arg22,
-
force_cond_2: :arg23,
-
fload: :arg24,
-
relay_mode: :arg25,
-
wait_time_out: :arg26,
-
start_func_args: :arg27,
-
start_of_body_f_args: :arg27,
-
pre_pat_func_args: :arg28,
-
pre_pat_f_args: :arg28,
-
pre_test_func_args: :arg29,
-
pre_test_f_args: :arg29,
-
post_test_func_args: :arg30,
-
post_test_f_args: :arg30,
-
post_pat_func_args: :arg31,
-
post_pat_f_args: :arg31,
-
end_func_args: :arg32,
-
end_of_body_f_args: :arg32,
-
pcp_start: :arg33,
-
pcp_check_pg: :arg34,
-
hsp_stop: :arg35,
-
hsp_check_pg: :arg36,
-
sampling_time: :arg37,
-
samples: :arg38,
-
resume_pat: :arg39,
-
vcl: :arg40,
-
vch: :arg41,
-
utility_pins_1: :arg42,
-
utility_pins_0: :arg43,
-
pre_charge_enable: :arg44,
-
pre_charge: :arg45,
-
threading: :arg46
-
},
-
-
apmu_powersupply: {
-
precond_pat: :arg0,
-
pre_cond_pat: :arg0,
-
start_func: :arg1,
-
start_of_body_f: :arg1,
-
pre_pat_func: :arg2,
-
pre_pat_f: :arg2,
-
pre_test_func: :arg3,
-
pre_test_f: :arg3,
-
post_test_func: :arg4,
-
post_test_f: :arg4,
-
post_pat_func: :arg5,
-
post_pat_f: :arg5,
-
end_func: :arg6,
-
end_of_body_f: :arg6,
-
pattern: :arg7,
-
hold_state_pat: :arg7,
-
holdstate_pat: :arg7,
-
wait_flags: :arg8,
-
wait_time_out: :arg9,
-
start_lo: :arg10,
-
start_init_lo: :arg10,
-
init_lo: :arg10,
-
start_hi: :arg11,
-
start_init_hi: :arg11,
-
init_hi: :arg11,
-
start_hiz: :arg12,
-
start_init_hiz: :arg12,
-
init_hiz: :arg12,
-
float_pins: :arg13,
-
irange: :arg14,
-
sampling_time: :arg15,
-
samples: :arg16,
-
settling_time: :arg17,
-
hi_lo_lim_valid: :arg18,
-
hi_lo_limit_valid: :arg18,
-
hi_limit: :arg19,
-
lo_limit: :arg20,
-
force_cond_1: :arg21,
-
force_cond: :arg21,
-
force_condition: :arg21,
-
force_condition_1: :arg21,
-
force_cond_2: :arg22,
-
force_condition_2: :arg22,
-
power_pins: :arg23,
-
pins: :arg23,
-
pin: :arg23,
-
force_source: :arg24,
-
pcp_start: :arg25,
-
pcp_stop: :arg26,
-
start_func_args: :arg27,
-
start_of_body_f_args: :arg27,
-
pre_pat_func_args: :arg28,
-
pre_pat_f_args: :arg28,
-
pre_test_func_args: :arg29,
-
pre_test_f_args: :arg29,
-
post_test_func_args: :arg30,
-
post_test_f_args: :arg30,
-
post_pat_func_args: :arg31,
-
post_pat_f_args: :arg31,
-
end_func_args: :arg32,
-
end_of_body_f_args: :arg32,
-
hsp_start: :arg33,
-
hsp_stop: :arg34,
-
pcp_check_pg: :arg35,
-
clamp: :arg36,
-
hsp_check_pg: :arg37,
-
resume_pat: :arg38,
-
relay_mode: :arg39,
-
utility_pins_1: :arg40,
-
utility_pins_0: :arg41,
-
test_control: :arg42,
-
serialize_meas: :arg43,
-
serialize_meas_func: :arg44,
-
serialize_meas_f: :arg44,
-
serialize_meas_func_args: :arg45,
-
serialize_meas_f_args: :arg45
-
},
-
-
powersupply: {
-
precond_pat: :arg0,
-
pre_cond_pat: :arg0,
-
start_func: :arg1,
-
start_of_body_f: :arg1,
-
pre_pat_func: :arg2,
-
pre_pat_f: :arg2,
-
pre_test_func: :arg3,
-
pre_test_f: :arg3,
-
post_test_func: :arg4,
-
post_test_f: :arg4,
-
post_pat_func: :arg5,
-
post_pat_f: :arg5,
-
end_func: :arg6,
-
end_of_body_f: :arg6,
-
pattern: :arg7,
-
hold_state_pat: :arg7,
-
holdstate_pat: :arg7,
-
wait_flags: :arg8,
-
wait_time_out: :arg9,
-
start_lo: :arg10,
-
start_init_lo: :arg10,
-
init_lo: :arg10,
-
start_hi: :arg11,
-
start_init_hi: :arg11,
-
init_hi: :arg11,
-
start_hiz: :arg12,
-
start_init_hiz: :arg12,
-
init_hiz: :arg12,
-
float_pins: :arg13,
-
irange: :arg14,
-
sampling_time: :arg15,
-
samples: :arg16,
-
settling_time: :arg17,
-
hi_lo_lim_valid: :arg18,
-
hi_lo_limit_valid: :arg18,
-
hi_limit: :arg19,
-
lo_limit: :arg20,
-
force_cond_1: :arg21,
-
force_cond: :arg21,
-
force_condition: :arg21,
-
force_condition_1: :arg21,
-
force_cond_2: :arg22,
-
force_condition_2: :arg22,
-
power_pins: :arg23,
-
pins: :arg23,
-
pin: :arg23,
-
force_source: :arg24,
-
pcp_start: :arg25,
-
pcp_stop: :arg26,
-
start_func_args: :arg27,
-
start_of_body_f_args: :arg27,
-
pre_pat_func_args: :arg28,
-
pre_pat_f_args: :arg28,
-
pre_test_func_args: :arg29,
-
pre_test_f_args: :arg29,
-
post_test_func_args: :arg30,
-
post_test_f_args: :arg30,
-
post_pat_func_args: :arg31,
-
post_pat_f_args: :arg31,
-
end_func_args: :arg32,
-
end_of_body_f_args: :arg32,
-
hsp_start: :arg33,
-
hsp_stop: :arg34,
-
pcp_check_pg: :arg35,
-
clamp: :arg36,
-
hsp_check_pg: :arg37,
-
resume_pat: :arg38,
-
relay_mode: :arg39,
-
utility_pins_1: :arg40,
-
utility_pins_0: :arg41,
-
test_control: :arg42,
-
serialize_meas: :arg43,
-
serialize_meas_func: :arg44,
-
serialize_meas_f: :arg44,
-
serialize_meas_func_args: :arg45,
-
serialize_meas_f_args: :arg45,
-
precond_pat_clamp: :arg46,
-
threading: :arg47
-
},
-
-
mto_memory: {
-
patterns: :arg0,
-
pattern: :arg0,
-
start_func: :arg1,
-
start_of_body_f: :arg1,
-
pre_pat_func: :arg2,
-
pre_pat_f: :arg2,
-
pre_test_func: :arg3,
-
pre_test_f: :arg3,
-
post_test_func: :arg4,
-
post_test_f: :arg4,
-
post_pat_func: :arg5,
-
post_pat_f: :arg5,
-
end_of_body_func: :arg6,
-
end_of_body_f: :arg6,
-
set_pass_fail: :arg7,
-
init_lo: :arg8,
-
start_lo: :arg8,
-
init_hi: :arg9,
-
start_hi: :arg9,
-
init_hiz: :arg10,
-
start_hiz: :arg10,
-
float_pins: :arg11,
-
start_of_body_func_args: :arg12,
-
start_of_body_f_args: :arg12,
-
pre_pat_func_args: :arg13,
-
pre_pat_f_args: :arg13,
-
pre_test_func_args: :arg14,
-
pre_test_f_args: :arg14,
-
post_test_func_args: :arg15,
-
post_test_f_args: :arg15,
-
post_pat_f_args: :arg16,
-
end_of_body_func_args: :arg17,
-
end_of_body_f_args: :arg17,
-
utility_pins_1: :arg18,
-
utility_pins_0: :arg19,
-
wait_flags: :arg20,
-
wait_time_out: :arg21,
-
PatFlagF: :arg22,
-
pat_flag_f: :arg22,
-
pat_flag_func_args: :arg23,
-
pat_flag_f_args: :arg23,
-
relay_mode: :arg24,
-
x_enable_mask: :arg29,
-
x_shift_direction: :arg30,
-
x_shift_input: :arg31,
-
y_enable_mask: :arg36,
-
y_shift_direction: :arg37,
-
y_shift_input: :arg38,
-
dga: :arg39,
-
dgb: :arg40,
-
dgc: :arg41,
-
dgd: :arg42,
-
dg_enable_mask: :arg43,
-
dg_shift_direction: :arg44,
-
dg_shift_input: :arg45,
-
x_coincidence_enable_mask: :arg46,
-
y_coincidence_enable_mask: :arg47,
-
two_bit_dg_setup: :arg48,
-
x_scramble_algorithm: :arg49,
-
y_scramble_algorithm: :arg50,
-
topo_inversion_algorithm: :arg51,
-
utility_counter_a: :arg52,
-
utility_counter_b: :arg53,
-
utility_counter_c: :arg54,
-
dut_data_source: :arg55,
-
scramble_addr: :arg56,
-
speed_mode: :arg57,
-
resource_map: :arg58,
-
receive_data: :arg59,
-
data_to_capture: :arg60,
-
capture_marker: :arg61,
-
enable_wrapping: :arg62,
-
capture_scrambled_address: :arg63,
-
mapmem_0_input_set: :arg64,
-
mapmem_1_input_set: :arg65,
-
threading: :arg69,
-
match_all_sites: :arg70
-
}
-
}
-
-
TEST_INSTANCE_DEFAULTS = {
-
2
empty: {
-
proc_type: 'IG-XL Template',
-
proc_name: 'Empty_T',
-
proc_called_as: 'Excel Macro'
-
},
-
other: {
-
proc_type: 'Other',
-
proc_called_as: 'Excel Macro'
-
},
-
functional: {
-
proc_type: 'IG-XL Template',
-
proc_name: 'Functional_T',
-
proc_called_as: 'VB DLL',
-
set_pass_fail: 1,
-
wait_flags: 'XXXX',
-
wait_time: 30,
-
relay_mode: 1,
-
threading: 0,
-
match_all_sites: 0,
-
capture_mode: 0,
-
capture_what: 0,
-
capture_memory: 0,
-
capture_size: 256,
-
datalog_mode: 0,
-
data_type: 0
-
},
-
board_pmu: {
-
proc_type: 'IG-XL Template',
-
proc_name: 'BoardPmu_T',
-
proc_called_as: 'VB DLL',
-
wait_flags: 'XXXX',
-
measure_mode: 1,
-
irange: 5,
-
vrange: 3,
-
settling_time: 0,
-
hi_lo_lim_valid: 3,
-
gang_pins_tested: 0,
-
relay_mode: 0,
-
wait_time_out: 30,
-
pcp_check_pg: 1,
-
hsp_check_pg: 1,
-
resume_pat: 0,
-
threading: 0
-
},
-
pin_pmu: {
-
proc_type: 'IG-XL Template',
-
proc_name: 'PinPmu_T',
-
proc_called_as: 'VB DLL',
-
wait_flags: 'XXXX',
-
measure_mode: 1,
-
irange: 2,
-
settling_time: 0,
-
hi_lo_lim_valid: 3,
-
fload: 0,
-
relay_mode: 0,
-
wait_time_out: 30,
-
pcp_check_pg: 1,
-
hsp_check_pg: 1,
-
resume_pat: 0,
-
threading: 0
-
},
-
apmu_powersupply: {
-
proc_type: 'IG-XL Template',
-
proc_name: 'ApmuPowerSupply_T',
-
proc_called_as: 'VB DLL',
-
wait_flags: 'XXXX',
-
irange: 1,
-
settling_time: 0,
-
hi_lo_lim_valid: 3,
-
relay_mode: 0,
-
wait_time_out: 30,
-
pcp_check_pg: 1,
-
hsp_check_pg: 1,
-
resume_pat: 0,
-
test_control: 0
-
},
-
powersupply: {
-
proc_type: 'IG-XL Template',
-
proc_name: 'PowerSupply_T',
-
proc_called_as: 'VB DLL',
-
wait_flags: 'XXXX',
-
irange: 1,
-
settling_time: 0,
-
hi_lo_lim_valid: 3,
-
relay_mode: 0,
-
wait_time_out: 30,
-
pcp_check_pg: 1,
-
hsp_check_pg: 1,
-
resume_pat: 0,
-
test_control: 0
-
},
-
mto_memory: {
-
proc_type: 'IG-XL Template',
-
proc_name: 'MtoMemory_T',
-
proc_called_as: 'VB DLL',
-
set_pass_fail: 1,
-
wait_flags: 'XXXX',
-
wait_time: 30,
-
relay_mode: 1,
-
threading: 0,
-
match_all_sites: 0,
-
dut_data_source: 0,
-
scramble_addr: 0,
-
speed_mode: 0,
-
resource_map: 'MAP_1M_2BIT',
-
receive_data: 0,
-
data_to_capture: 1,
-
capture_marker: 1,
-
enable_wrapping: 0,
-
capture_scrambled_address: 0,
-
mapmem_0_input_set: 'Map_By16',
-
mapmem_1_input_set: 'Map_By16',
-
x_scramble_algorithm: 'X_NO_SCRAMBLE',
-
y_scramble_algorithm: 'Y_NO_SCRAMBLE',
-
topo_inversion_algorithm: 'NO_TOPO',
-
x_shift_direction: 0,
-
x_shift_input: 0,
-
y_shift_direction: 0,
-
y_shift_input: 0,
-
x_coincidence_enable_mask: 0,
-
y_coincidence_enable_mask: 0,
-
dg_shift_direction: 0,
-
dg_shift_input: 0
-
}
-
}
-
-
# Generate the instance method definitions based on the above
-
2
define
-
-
# Set the cpu wait flags for the given test instance
-
# instance.set_wait_flags(:a)
-
# instance.set_wait_flags(:a, :c)
-
2
def set_wait_flags(*flags)
-
13
a = (flags.include?(:a) || flags.include?(:a)) ? '1' : 'X'
-
13
b = (flags.include?(:b) || flags.include?(:b)) ? '1' : 'X'
-
13
c = (flags.include?(:c) || flags.include?(:c)) ? '1' : 'X'
-
13
d = (flags.include?(:d) || flags.include?(:d)) ? '1' : 'X'
-
13
self.wait_flags = d + c + b + a
-
13
self
-
end
-
-
# Set and enable the pre-charge voltage of a parametric test instance.
-
2
def set_pre_charge(val)
-
if val
-
self.pre_charge_enable = 1
-
self.pre_charge = val
-
else
-
self.pre_charge_enable = 0
-
end
-
self
-
end
-
2
alias_method :set_precharge, :set_pre_charge
-
-
# Returns a hash containing key meta data about the test instance, this is
-
# intended to be used in documentation
-
2
def to_meta
-
966
return @meta if @meta
-
966
m = { 'Test' => name,
-
'Type' => type
-
}
-
966
if type == :functional
-
894
m['Pattern'] = pattern
-
72
elsif type == :board_pmu || type == :pin_pmu
-
66
m['Measure'] = fvmi? ? 'current' : 'voltage'
-
66
if hi_lo_limit_valid & 2 != 0
-
66
m['Hi'] = hi_limit
-
end
-
66
if hi_lo_limit_valid & 1 != 0
-
66
m['Lo'] = lo_limit
-
end
-
66
m['Hi'] = hi_limit
-
66
m['Lo'] = lo_limit
-
66
if force_cond
-
m['Force'] = force_cond
-
end
-
6
elsif type == :powersupply
-
3
if hi_lo_limit_valid & 2 != 0
-
3
m['Hi'] = hi_limit
-
end
-
3
if hi_lo_limit_valid & 1 != 0
-
3
m['Lo'] = lo_limit
-
end
-
3
m['Hi'] = hi_limit
-
3
m['Lo'] = lo_limit
-
3
if force_cond
-
m['Force'] = force_cond
-
end
-
end
-
966
m['DC'] = "#{dc_category} (#{dc_selector})"
-
966
m['AC'] = "#{ac_category} (#{ac_selector})"
-
966
m
-
end
-
-
# Set the meaure mode of a parametric test instance, either:
-
# * :voltage / :fimv
-
# * :current / :fvmi
-
2
def set_measure_mode(mode)
-
if mode == :current || mode == :fvmi
-
self.measure_mode = 0
-
elsif mode == :voltage || mode == :fimv
-
self.measure_mode = 1
-
else
-
fail "Unknown measure mode: #{mode}"
-
end
-
end
-
-
# Set and enable the hi limit of a parametric test instance, passing in
-
# nil or false as the lim parameter will disable the hi limit.
-
2
def set_hi_limit(lim)
-
if lim
-
if $tester.j750?
-
self.hi_lo_limit_valid = hi_lo_limit_valid | 2
-
end
-
self.hi_limit = lim
-
else
-
if $tester.j750?
-
self.hi_lo_limit_valid = hi_lo_limit_valid & 1
-
end
-
end
-
self
-
end
-
2
alias_method :hi_limit=, :set_hi_limit
-
-
# Set and enable the hi limit of a parametric test instance, passing in
-
# nil or false as the lim parameter will disable the hi limit.
-
2
def set_lo_limit(lim)
-
if lim
-
if $tester.j750?
-
self.hi_lo_limit_valid = hi_lo_limit_valid | 1
-
end
-
self.lo_limit = lim
-
else
-
if $tester.j750?
-
self.hi_lo_limit_valid = hi_lo_limit_valid & 2
-
end
-
end
-
self
-
end
-
2
alias_method :lo_limit=, :set_lo_limit
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750
-
2
require 'origen_testers/igxl_based_tester/base/test_instance_group'
-
2
class TestInstanceGroup < Base::TestInstanceGroup
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750
-
2
require 'origen_testers/igxl_based_tester/base/test_instances'
-
2
class TestInstances < Base::TestInstances
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/j750/templates/instances.txt.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
# Tester model to generate .atp patterns for the Teradyne J750 in HPT mode
-
#
-
# == Basic Usage
-
# $tester = J750_HPT.new
-
# $tester.cycle # Generate a vector
-
#
-
# Many more methods exist to generate J750 specific micro-code, see J750
-
# parent class definition for details.
-
#
-
# *Also note that this class inherits from the base Tester class and so all methods
-
# described there are also available*
-
2
class J750_HPT < J750
-
2
require 'origen_testers/igxl_based_tester/j750_hpt/generator.rb'
-
-
2
def initialize(options = {})
-
41
super(options)
-
41
@@hpt_mode = true
-
41
@drive_hi_state = '.1'
-
41
@drive_lo_state = '.0'
-
41
@expect_hi_state = '.H'
-
41
@expect_lo_state = '.L'
-
41
@dont_care_state = '.X'
-
41
@overlay_state = '.V'
-
41
@drive_very_hi_state = '.2'
-
41
@drive_mem_state = '.D'
-
41
@expect_mem_state = '.E'
-
41
@name = 'j750_hpt'
-
end
-
end
-
end
-
2
J750_HPT = IGXLBasedTester::J750_HPT
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750_HPT
-
2
require 'origen_testers/igxl_based_tester/base/custom_test_instance'
-
2
class CustomTestInstance < Base::CustomTestInstance
-
# Attributes for each test instance line, first few are named directly
-
TEST_INSTANCE_ATTRS = %w(
-
2
test_name proc_type proc_name proc_called_as dc_category
-
dc_selector ac_category ac_selector
-
time_sets edge_sets pin_levels overlay
-
)
-
-
# Attributes for additional test instance arguments beyond those described above
-
2
TEST_INSTANCE_EXTRA_ARGS = 80
-
-
TEST_INSTANCE_DEFAULTS = {
-
2
proc_type: 'Other',
-
proc_called_as: 'VB DLL'
-
}
-
-
TEST_INSTANCE_ALIASES = {
-
2
name: :test_name,
-
time_set: :time_sets,
-
timeset: :time_sets,
-
timesets: :time_sets
-
}
-
-
2
define
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750_HPT
-
2
require 'origen_testers/igxl_based_tester/j750/flow'
-
2
class Flow < J750::Flow
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750_HPT
-
2
require 'origen_testers/igxl_based_tester/j750/flow_line'
-
2
class FlowLine < J750::FlowLine
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750_HPT
-
# Include this module in an interface class to make it a J750 HPT interface and to give
-
# access to the J750 HPT program generator API
-
2
module Generator
-
2
extend ActiveSupport::Concern
-
-
2
require_all "#{Origen.root!}/lib/origen_testers/igxl_based_tester/j750_hpt"
-
2
require 'origen_testers/igxl_based_tester/base/generator'
-
-
2
included do
-
8
include Base::Generator
-
8
PLATFORM = J750_HPT
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750_HPT
-
2
require 'origen_testers/igxl_based_tester/j750/patgroup'
-
2
class Patgroup < J750::Patgroup
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750_HPT
-
2
require 'origen_testers/igxl_based_tester/j750/patgroups'
-
2
class Patgroups < J750::Patgroups
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750_HPT
-
2
require 'origen_testers/igxl_based_tester/j750/patset'
-
2
class Patset < J750::Patset
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750_HPT
-
2
require 'origen_testers/igxl_based_tester/j750/patset_pattern'
-
2
class PatsetPattern < J750::PatsetPattern
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750_HPT
-
2
require 'origen_testers/igxl_based_tester/j750/patsets'
-
2
class Patsets < J750::Patsets
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750_HPT
-
2
require 'origen_testers/igxl_based_tester/j750/patsubr'
-
2
class Patsubr < J750::Patsubr
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750_HPT
-
2
require 'origen_testers/igxl_based_tester/j750/patsubr_pattern'
-
2
class PatsubrPattern < J750::PatsubrPattern
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750_HPT
-
2
require 'origen_testers/igxl_based_tester/j750/patsubrs'
-
2
class Patsubrs < J750::Patsubrs
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750_HPT
-
2
require 'origen_testers/igxl_based_tester/base/test_instance'
-
2
class TestInstance < Base::TestInstance
-
# Attributes for each test instance line, first few are named directly
-
TEST_INSTANCE_ATTRS = %w(
-
2
test_name proc_type proc_name proc_called_as dc_category
-
dc_selector ac_category ac_selector
-
time_sets edge_sets pin_levels overlay
-
)
-
-
# Attributes for additional test instance arguments beyond those described above
-
2
TEST_INSTANCE_EXTRA_ARGS = 80
-
-
TEST_INSTANCE_ALIASES = {
-
2
name: :test_name,
-
time_set: :time_sets,
-
timeset: :time_sets,
-
timesets: :time_sets,
-
-
other: {
-
},
-
-
empty: {
-
start_func: :arg0,
-
start_of_body_f: :arg0,
-
pre_pat_func: :arg1,
-
pre_pat_f: :arg1,
-
pre_test_func: :arg2,
-
pre_test_f: :arg2,
-
post_test_func: :arg3,
-
post_test_f: :arg3,
-
post_pat_func: :arg4,
-
post_pat_f: :arg4,
-
end_func: :arg5,
-
end_of_body_f: :arg5,
-
start_func_args: :arg6,
-
start_of_body_f_args: :arg6,
-
pre_pat_func_args: :arg7,
-
pre_pat_f_args: :arg7,
-
pre_test_func_args: :arg8,
-
pre_test_f_args: :arg8,
-
post_test_func_args: :arg9,
-
post_test_f_args: :arg9,
-
post_pat_func_args: :arg10,
-
post_pat_f_args: :arg10,
-
end_func_args: :arg11,
-
end_of_body_f_args: :arg11,
-
utility_pins_1: :arg12,
-
utility_pins_0: :arg13,
-
init_lo: :arg14,
-
start_lo: :arg14,
-
init_hi: :arg15,
-
start_hi: :arg15,
-
init_hiz: :arg16,
-
start_hiz: :arg16,
-
float_pins: :arg17
-
},
-
-
# Functional test instances
-
functional: {
-
pattern: :arg0,
-
patterns: :arg0,
-
start_func: :arg1,
-
start_of_body_f: :arg1,
-
pre_pat_func: :arg2,
-
pre_pat_f: :arg2,
-
pre_test_func: :arg3,
-
pre_test_f: :arg3,
-
post_test_func: :arg4,
-
post_test_f: :arg4,
-
post_pat_func: :arg5,
-
post_pat_f: :arg5,
-
end_func: :arg6,
-
end_of_body_f: :arg6,
-
set_pass_fail: :arg7,
-
init_lo: :arg8,
-
start_lo: :arg8,
-
init_hi: :arg9,
-
start_hi: :arg9,
-
init_hiz: :arg10,
-
start_hiz: :arg10,
-
float_pins: :arg11,
-
start_func_args: :arg13,
-
start_of_body_f_args: :arg13,
-
pre_pat_func_args: :arg14,
-
pre_pat_f_args: :arg14,
-
pre_test_func_args: :arg15,
-
pre_test_f_args: :arg15,
-
post_test_func_args: :arg16,
-
post_test_f_args: :arg16,
-
post_pat_func_args: :arg17,
-
post_pat_f_args: :arg17,
-
end_func_args: :arg18,
-
end_of_body_f_args: :arg18,
-
wait_flags: :arg21,
-
wait_time: :arg22,
-
pattern_timeout: :arg22,
-
pat_flag_func: :arg23,
-
pat_flag_f: :arg23,
-
PatFlagF: :arg23,
-
pat_flag_func_args: :arg24,
-
pat_flag_f_args: :arg24,
-
relay_mode: :arg25,
-
threading: :arg26,
-
match_all_sites: :arg27,
-
capture_mode: :arg30,
-
capture_what: :arg31,
-
capture_memory: :arg32,
-
capture_size: :arg33,
-
datalog_mode: :arg34,
-
data_type: :arg35
-
},
-
-
board_pmu: {
-
hsp_start: :arg0,
-
start_func: :arg1,
-
start_of_body_f: :arg1,
-
pre_pat_func: :arg2,
-
pre_pat_f: :arg2,
-
pre_test_func: :arg3,
-
pre_test_f: :arg3,
-
post_test_func: :arg4,
-
post_test_f: :arg4,
-
post_pat_func: :arg5,
-
post_pat_f: :arg5,
-
end_func: :arg6,
-
end_of_body_f: :arg6,
-
precond_pat: :arg7,
-
hold_state_pat: :arg8,
-
holdstate_pat: :arg8,
-
pattern: :arg8,
-
pcp_stop: :arg9,
-
wait_flags: :arg10,
-
start_lo: :arg11,
-
init_lo: :arg11,
-
start_hi: :arg12,
-
init_hi: :arg12,
-
start_hiz: :arg13,
-
init_hiz: :arg13,
-
float_pins: :arg14,
-
pinlist: :arg15,
-
pin: :arg15,
-
pin_list: :arg15,
-
measure_mode: :arg16,
-
irange: :arg17,
-
clamp: :arg18,
-
vrange: :arg19,
-
sampling_time: :arg20,
-
samples: :arg21,
-
settling_time: :arg22,
-
hi_lo_lim_valid: :arg23,
-
hi_lo_limit_valid: :arg23,
-
hi_limit: :arg24,
-
lo_limit: :arg25,
-
force_cond_1: :arg26,
-
force_cond: :arg26,
-
force_condition: :arg26,
-
force_cond_2: :arg27,
-
gang_pins_tested: :arg28,
-
relay_mode: :arg29,
-
wait_time_out: :arg30,
-
start_func_args: :arg31,
-
start_of_body_f_args: :arg31,
-
pre_pat_func_args: :arg32,
-
pre_pat_f_args: :arg32,
-
pre_test_func_args: :arg33,
-
pre_test_f_args: :arg33,
-
post_test_func_args: :arg34,
-
post_test_f_args: :arg34,
-
post_pat_func_args: :arg35,
-
post_pat_f_args: :arg35,
-
end_func_args: :arg36,
-
end_of_body_f_args: :arg36,
-
pcp_start: :arg37,
-
pcp_check_pg: :arg38,
-
hsp_stop: :arg39,
-
hsp_check_pg: :arg40,
-
resume_pat: :arg41,
-
utility_pins_1: :arg42,
-
utility_pins_0: :arg43,
-
pre_charge_enable: :arg44,
-
pre_charge: :arg45,
-
threading: :arg46
-
},
-
-
pin_pmu: {
-
hsp_start: :arg0,
-
start_func: :arg1,
-
start_of_body_f: :arg1,
-
pre_pat_func: :arg2,
-
pre_pat_f: :arg2,
-
pre_test_func: :arg3,
-
pre_test_f: :arg3,
-
post_test_func: :arg4,
-
post_test_f: :arg4,
-
post_pat_func: :arg5,
-
post_pat_f: :arg5,
-
end_func: :arg6,
-
end_of_body_f: :arg6,
-
precond_pat: :arg7,
-
hold_state_pat: :arg8,
-
holdstate_pat: :arg8,
-
pattern: :arg8,
-
pcp_stop: :arg9,
-
wait_flags: :arg10,
-
start_lo: :arg11,
-
init_lo: :arg11,
-
start_hi: :arg12,
-
init_hi: :arg12,
-
start_hiz: :arg13,
-
init_hiz: :arg13,
-
float_pins: :arg14,
-
pinlist: :arg15,
-
pin: :arg15,
-
pin_list: :arg15,
-
measure_mode: :arg16,
-
irange: :arg17,
-
settling_time: :arg18,
-
hi_lo_lim_valid: :arg19,
-
hi_lo_limit_valid: :arg19,
-
hi_limit: :arg20,
-
lo_limit: :arg21,
-
force_cond_1: :arg22,
-
force_cond: :arg22,
-
force_condition: :arg22,
-
force_cond_2: :arg23,
-
fload: :arg24,
-
relay_mode: :arg25,
-
wait_time_out: :arg26,
-
start_func_args: :arg27,
-
start_of_body_f_args: :arg27,
-
pre_pat_func_args: :arg28,
-
pre_pat_f_args: :arg28,
-
pre_test_func_args: :arg29,
-
pre_test_f_args: :arg29,
-
post_test_func_args: :arg30,
-
post_test_f_args: :arg30,
-
post_pat_func_args: :arg31,
-
post_pat_f_args: :arg31,
-
end_func_args: :arg32,
-
end_of_body_f_args: :arg32,
-
pcp_start: :arg33,
-
pcp_check_pg: :arg34,
-
hsp_stop: :arg35,
-
hsp_check_pg: :arg36,
-
sampling_time: :arg37,
-
samples: :arg38,
-
resume_pat: :arg39,
-
vcl: :arg40,
-
vch: :arg41,
-
utility_pins_1: :arg42,
-
utility_pins_0: :arg43,
-
pre_charge_enable: :arg44,
-
pre_charge: :arg45,
-
threading: :arg46
-
},
-
-
apmu_powersupply: {
-
precond_pat: :arg0,
-
pre_cond_pat: :arg0,
-
start_func: :arg1,
-
start_of_body_f: :arg1,
-
pre_pat_func: :arg2,
-
pre_pat_f: :arg2,
-
pre_test_func: :arg3,
-
pre_test_f: :arg3,
-
post_test_func: :arg4,
-
post_test_f: :arg4,
-
post_pat_func: :arg5,
-
post_pat_f: :arg5,
-
end_func: :arg6,
-
end_of_body_f: :arg6,
-
pattern: :arg7,
-
hold_state_pat: :arg7,
-
holdstate_pat: :arg7,
-
wait_flags: :arg8,
-
wait_time_out: :arg9,
-
start_lo: :arg10,
-
start_init_lo: :arg10,
-
init_lo: :arg10,
-
start_hi: :arg11,
-
start_init_hi: :arg11,
-
init_hi: :arg11,
-
start_hiz: :arg12,
-
start_init_hiz: :arg12,
-
init_hiz: :arg12,
-
float_pins: :arg13,
-
irange: :arg14,
-
sampling_time: :arg15,
-
samples: :arg16,
-
settling_time: :arg17,
-
hi_lo_lim_valid: :arg18,
-
hi_lo_limit_valid: :arg18,
-
hi_limit: :arg19,
-
lo_limit: :arg20,
-
force_cond_1: :arg21,
-
force_cond: :arg21,
-
force_condition: :arg21,
-
force_condition_1: :arg21,
-
force_cond_2: :arg22,
-
force_condition_2: :arg22,
-
power_pins: :arg23,
-
pins: :arg23,
-
pin: :arg23,
-
force_source: :arg24,
-
pcp_start: :arg25,
-
pcp_stop: :arg26,
-
start_func_args: :arg27,
-
start_of_body_f_args: :arg27,
-
pre_pat_func_args: :arg28,
-
pre_pat_f_args: :arg28,
-
pre_test_func_args: :arg29,
-
pre_test_f_args: :arg29,
-
post_test_func_args: :arg30,
-
post_test_f_args: :arg30,
-
post_pat_func_args: :arg31,
-
post_pat_f_args: :arg31,
-
end_func_args: :arg32,
-
end_of_body_f_args: :arg32,
-
hsp_start: :arg33,
-
hsp_stop: :arg34,
-
pcp_check_pg: :arg35,
-
clamp: :arg36,
-
hsp_check_pg: :arg37,
-
resume_pat: :arg38,
-
relay_mode: :arg39,
-
utility_pins_1: :arg40,
-
utility_pins_0: :arg41,
-
test_control: :arg42,
-
serialize_meas: :arg43,
-
serialize_meas_func: :arg44,
-
serialize_meas_f: :arg44,
-
serialize_meas_func_args: :arg45,
-
serialize_meas_f_args: :arg45
-
},
-
-
powersupply: {
-
precond_pat: :arg0,
-
pre_cond_pat: :arg0,
-
start_func: :arg1,
-
start_of_body_f: :arg1,
-
pre_pat_func: :arg2,
-
pre_pat_f: :arg2,
-
pre_test_func: :arg3,
-
pre_test_f: :arg3,
-
post_test_func: :arg4,
-
post_test_f: :arg4,
-
post_pat_func: :arg5,
-
post_pat_f: :arg5,
-
end_func: :arg6,
-
end_of_body_f: :arg6,
-
pattern: :arg7,
-
hold_state_pat: :arg7,
-
holdstate_pat: :arg7,
-
wait_flags: :arg8,
-
wait_time_out: :arg9,
-
start_lo: :arg10,
-
start_init_lo: :arg10,
-
init_lo: :arg10,
-
start_hi: :arg11,
-
start_init_hi: :arg11,
-
init_hi: :arg11,
-
start_hiz: :arg12,
-
start_init_hiz: :arg12,
-
init_hiz: :arg12,
-
float_pins: :arg13,
-
irange: :arg14,
-
sampling_time: :arg15,
-
samples: :arg16,
-
settling_time: :arg17,
-
hi_lo_lim_valid: :arg18,
-
hi_lo_limit_valid: :arg18,
-
hi_limit: :arg19,
-
lo_limit: :arg20,
-
force_cond_1: :arg21,
-
force_cond: :arg21,
-
force_condition: :arg21,
-
force_condition_1: :arg21,
-
force_cond_2: :arg22,
-
force_condition_2: :arg22,
-
power_pins: :arg23,
-
pins: :arg23,
-
pin: :arg23,
-
force_source: :arg24,
-
pcp_start: :arg25,
-
pcp_stop: :arg26,
-
start_func_args: :arg27,
-
start_of_body_f_args: :arg27,
-
pre_pat_func_args: :arg28,
-
pre_pat_f_args: :arg28,
-
pre_test_func_args: :arg29,
-
pre_test_f_args: :arg29,
-
post_test_func_args: :arg30,
-
post_test_f_args: :arg30,
-
post_pat_func_args: :arg31,
-
post_pat_f_args: :arg31,
-
end_func_args: :arg32,
-
end_of_body_f_args: :arg32,
-
hsp_start: :arg33,
-
hsp_stop: :arg34,
-
pcp_check_pg: :arg35,
-
clamp: :arg36,
-
hsp_check_pg: :arg37,
-
resume_pat: :arg38,
-
relay_mode: :arg39,
-
utility_pins_1: :arg40,
-
utility_pins_0: :arg41,
-
test_control: :arg42,
-
serialize_meas: :arg43,
-
serialize_meas_func: :arg44,
-
serialize_meas_f: :arg44,
-
serialize_meas_func_args: :arg45,
-
serialize_meas_f_args: :arg45,
-
precond_pat_clam: :arg46,
-
threading: :arg47
-
},
-
-
mto_memory: {
-
patterns: :arg0,
-
pattern: :arg0,
-
start_func: :arg1,
-
start_of_body_f: :arg1,
-
pre_pat_func: :arg2,
-
pre_pat_f: :arg2,
-
pre_test_func: :arg3,
-
pre_test_f: :arg3,
-
post_test_func: :arg4,
-
post_test_f: :arg4,
-
post_pat_func: :arg5,
-
post_pat_f: :arg5,
-
end_of_body_func: :arg6,
-
end_of_body_f: :arg6,
-
set_pass_fail: :arg7,
-
init_lo: :arg8,
-
start_lo: :arg8,
-
init_hi: :arg9,
-
start_hi: :arg9,
-
init_hiz: :arg10,
-
start_hiz: :arg10,
-
float_pins: :arg11,
-
start_of_body_func_args: :arg12,
-
start_of_body_f_args: :arg12,
-
pre_pat_func_args: :arg13,
-
pre_pat_f_args: :arg13,
-
pre_test_func_args: :arg14,
-
pre_test_f_args: :arg14,
-
post_test_func_args: :arg15,
-
post_test_f_args: :arg15,
-
post_pat_f_args: :arg16,
-
end_of_body_func_args: :arg17,
-
end_of_body_f_args: :arg17,
-
utility_pins_1: :arg18,
-
utility_pins_0: :arg19,
-
wait_flags: :arg20,
-
wait_time_out: :arg21,
-
PatFlagF: :arg22,
-
pat_flag_f: :arg22,
-
pat_flag_func_args: :arg23,
-
pat_flag_f_args: :arg23,
-
relay_mode: :arg24,
-
x_enable_mask: :arg29,
-
x_shift_direction: :arg30,
-
x_shift_input: :arg31,
-
y_enable_mask: :arg36,
-
y_shift_direction: :arg37,
-
y_shift_input: :arg38,
-
dga: :arg39,
-
dgb: :arg40,
-
dgc: :arg41,
-
dgd: :arg42,
-
dg_enable_mask: :arg43,
-
dg_shift_direction: :arg44,
-
dg_shift_input: :arg45,
-
x_coincidence_enable_mask: :arg46,
-
y_coincidence_enable_mask: :arg47,
-
two_bit_dg_setup: :arg48,
-
x_scramble_algorithm: :arg49,
-
y_scramble_algorithm: :arg50,
-
topo_inversion_algorithm: :arg51,
-
utility_counter_a: :arg52,
-
utility_counter_b: :arg53,
-
utility_counter_c: :arg54,
-
dut_data_source: :arg55,
-
scramble_addr: :arg56,
-
speed_mode: :arg57,
-
resource_map: :arg58,
-
receive_data: :arg59,
-
data_to_capture: :arg60,
-
capture_marker: :arg61,
-
enable_wrapping: :arg62,
-
capture_scrambled_address: :arg63,
-
mapmem_0_input_set: :arg64,
-
mapmem_1_input_set: :arg65,
-
threading: :arg69,
-
match_all_sites: :arg70
-
}
-
}
-
-
TEST_INSTANCE_DEFAULTS = {
-
2
empty: {
-
proc_type: 'Template',
-
proc_name: 'HPT.xla!HPT_Empty_T',
-
proc_called_as: 'Excel Macro'
-
},
-
other: {
-
proc_type: 'Other',
-
proc_called_as: 'Excel Macro'
-
},
-
functional: {
-
proc_type: 'Template',
-
proc_name: 'HPT.xla!HPT_Functional_T',
-
proc_called_as: 'VB DLL',
-
set_pass_fail: 1,
-
wait_flags: 'XXXX',
-
wait_time: 30,
-
relay_mode: 1,
-
threading: 0,
-
match_all_sites: 0,
-
capture_mode: 0,
-
capture_what: 0,
-
capture_memory: 0,
-
capture_size: 256,
-
datalog_mode: 0,
-
data_type: 0
-
},
-
board_pmu: {
-
proc_type: 'Template',
-
proc_name: 'HPT.xla!HPT_BoardPmu_T',
-
proc_called_as: 'VB DLL',
-
wait_flags: 'XXXX',
-
measure_mode: 1,
-
irange: 5,
-
vrange: 3,
-
settling_time: 0,
-
hi_lo_lim_valid: 3,
-
gang_pins_tested: 0,
-
relay_mode: 0,
-
wait_time_out: 30,
-
pcp_check_pg: 1,
-
hsp_check_pg: 1,
-
resume_pat: 0,
-
threading: 0
-
},
-
pin_pmu: {
-
proc_type: 'Template',
-
proc_name: 'HPT.xla!HPT_PinPmu_T',
-
proc_called_as: 'VB DLL',
-
wait_flags: 'XXXX',
-
measure_mode: 1,
-
irange: 2,
-
settling_time: 0,
-
hi_lo_lim_valid: 3,
-
fload: 0,
-
relay_mode: 0,
-
wait_time_out: 30,
-
pcp_check_pg: 1,
-
hsp_check_pg: 1,
-
resume_pat: 0,
-
threading: 0
-
},
-
apmu_powersupply: {
-
proc_type: 'Template',
-
proc_name: 'HPT.xla!HPT_ApmuPowerSupply_T',
-
proc_called_as: 'VB DLL',
-
wait_flags: 'XXXX',
-
irange: 1,
-
settling_time: 0,
-
hi_lo_lim_valid: 3,
-
relay_mode: 0,
-
wait_time_out: 30,
-
pcp_check_pg: 1,
-
hsp_check_pg: 1,
-
resume_pat: 0,
-
test_control: 0
-
},
-
mto_memory: {},
-
powersupply: {}
-
}
-
-
# Generate the instance method definitions based on the above
-
2
define
-
-
# Set the cpu wait flags for the given test instance
-
# instance.set_wait_flags(:a)
-
# instance.set_wait_flags(:a, :c)
-
2
def set_wait_flags(*flags)
-
13
a = (flags.include?(:a) || flags.include?(:a)) ? '1' : 'X'
-
13
b = (flags.include?(:b) || flags.include?(:b)) ? '1' : 'X'
-
13
c = (flags.include?(:c) || flags.include?(:c)) ? '1' : 'X'
-
13
d = (flags.include?(:d) || flags.include?(:d)) ? '1' : 'X'
-
13
self.wait_flags = d + c + b + a
-
13
self
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750_HPT
-
2
require 'origen_testers/igxl_based_tester/j750/test_instance_group'
-
2
class TestInstanceGroup < J750::TestInstanceGroup
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class J750_HPT
-
2
require 'origen_testers/igxl_based_tester/j750/test_instances'
-
2
class TestInstances < J750::TestInstances
-
end
-
end
-
end
-
end
-
2
require 'origen_testers/igxl_based_tester/ultraflex/ate_hardware'
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX < Base
-
2
autoload :Generator, 'origen_testers/igxl_based_tester/ultraflex/generator.rb'
-
-
# Read or update the digital instrument
-
# Ex: tester.digital_instrument = 'hsdmq'
-
2
attr_accessor :digital_instrument
-
-
# Tester model to generate .atp patterns for the Teradyne UltraFLEX
-
#
-
# == Basic Usage
-
# $tester = Testers::UltraFLEX.new
-
# $tester.cycle # Generate a vector
-
#
-
# Many more methods exist to generate UltraFLEX specific micro-code, see below for
-
# details.
-
#
-
# Also note that this class inherits from the base IGXLBasedTester class and so all methods
-
# described there are also available.
-
-
# Returns a new UltraFLEX instance, normally there would only ever be one of these
-
# assigned to the global variable such as $tester by your target.
-
2
def initialize(options = {})
-
192
super(options)
-
192
options = { digital_instrument: 'hsdm' }.merge(options)
-
192
@pipeline_depth = 255 # for single mode
-
192
@software_version = '8.10.10'
-
192
@name = 'ultraflex'
-
192
@opcode_mode = :single # there is also :dual
-
192
@counter_lsb_bits = 16 # individual counter bit length
-
192
@counter_msb_bits = 12 # temporary register commonly used to extend all counters
-
-
192
@flags = %w(cpuA_cond cpuB_cond cpuC_cond cpuD_cond)
-
192
@microcode[:enable] = 'branch_expr ='
-
192
@microcode[:set_flag] = 'set_cpu_cond'
-
192
@microcode[:mask_vector] = 'mask'
-
-
# Min required for a VM module-- not for SRM modules
-
# this handled in pattern_header below
-
192
@min_pattern_vectors = (@opcode_mode == :single) ? 64 : 128
-
-
192
@digital_instrument = options[:digital_instrument] # 'hsdm' for HSD1000 and UP800, ok with UP1600 though
-
-
192
@capture_state = 'V' # STV requires valid 'V' expect data
-
-
192
@set_msb_issued = false # Internal flag to keep track of set_msb usage, allowing for set_lsb to be used as a readcode
-
192
@microcode[:keepalive] = 'keepalive'
-
-
192
@onemodsubs_found = false # flag to indicate whether a single-module subroutine has been implemented in this pattern
-
192
@nonmodsubs_found = false # flag to indicate whether a normal non-single-module subroutine has been implemented in this pattern
-
-
192
@dssc_send_delay = 144
-
192
@dssc_send_delay = 288 if @opcode_mode == :dual
-
192
@dssc_send_delay = 576 if @opcode_mode == :quad
-
end
-
-
# Do a frequency measure.
-
#
-
# Write the necessary micro code to do a frequency measure on the given pin,
-
# optionally supply a read code to pass information to the tester.
-
#
-
# ==== Examples
-
# $tester.freq_count($top.pin(:d_out)) # Freq measure on pin "d_out"
-
# $tester.freq_count($top.pin(:d_out):readcode => 10)
-
2
def freq_count(pin, options = {})
-
2
options = { readcode: false
-
}.merge(options)
-
-
2
set_code(options[:readcode]) if options[:readcode]
-
2
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[0]})") # set cpuA
-
2
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[0]})") # set cpuB
-
2
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[1]})") # set cpuC
-
2
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[2]})") # set cpuD
-
2
cycle(microcode: "freq_loop_1: #{@microcode[:enable]} (#{@flags[0]})")
-
2
cycle(microcode: 'if (branch_expr) jump freq_loop_1')
-
2
pin.drive_lo
-
2
delay(2000)
-
2
pin.dont_care
-
2
cycle(microcode: "freq_loop_2: #{@microcode[:enable]} (#{@flags[1]})")
-
2
cycle(microcode: 'if (branch_expr) jump freq_loop_2')
-
2
cycle(microcode: "#{@microcode[:enable]} (#{@flags[2]})")
-
2
cycle(microcode: 'if (branch_expr) jump freq_loop_1')
-
end
-
-
2
def memory_test(options = {})
-
options = {
-
6
gen_vector: true, # Default generate vector not just MTO opcode
-
init_counter_x: false, # initialize counter X
-
inc_counter_x: false, # increment counter X
-
init_counter_y: false, # initialize counter X
-
inc_counter_y: false, # increment counter X
-
capture_vector: false, # capture vector to memory using all mem types
-
capture_vector_mem0: false, # capture vector to memory type 0, here for J750 will be stv_m0
-
capture_vector_mem1: false, # capture vector to memory type 1, here for J750 will be stv_m1
-
capture_vector_mem2: false, # capture vector to memory type 2, here for J750 will be stv_c
-
pin: false, # pin on which to drive or expect data, pass pin object here!
-
pin_data: false, # pin data (:none, :drive, :expect)
-
use_dgen_group: false,
-
set_msb: false
-
}.merge(options)
-
-
6
mto_opcode = ''
-
-
6
if options[:init_counter_x]
-
1
mto_opcode += ' xenable_load jam_reg xa jam_reg'
-
end
-
-
6
if options[:init_counter_y]
-
1
mto_opcode += ' yenable_load jam_reg ya jam_reg'
-
end
-
-
6
if options[:inc_counter_x]
-
2
mto_opcode += ' xa inc'
-
end
-
-
6
if options[:inc_counter_y]
-
2
mto_opcode += ' ya inc'
-
end
-
-
6
if options[:use_dgen_group]
-
mto_opcode += ' dgroup 0'
-
end
-
-
6
if options[:set_msb]
-
microcode 'set_msb 1'
-
end
-
-
6
unless mto_opcode.eql?('')
-
5
mto_opcode = '(mto =' + mto_opcode + ')'
-
end
-
-
6
if options[:pin_data] == :expect
-
1
mto_opcode = 'stv'
-
end
-
-
6
if options[:gen_vector]
-
6
if options[:pin]
-
1
case options[:pin_data]
-
when :drive
-
# store current pin state
-
cur_pin_state = options[:pin].state.to_sym
-
options[:pin].drive_mem
-
when :expect
-
# store current pin state
-
1
cur_pin_state = options[:pin].state.to_sym
-
1
options[:pin].expect_mem
-
end
-
end
-
6
cycle(microcode: "#{mto_opcode}", dont_compress: false)
-
6
if options[:pin]
-
# restore previous pin state
-
1
case options[:pin_data]
-
when :drive
-
options[:pin].state = cur_pin_state
-
when :expect
-
1
options[:pin].state = cur_pin_state
-
end
-
end
-
else
-
microcode "#{mto_opcode}"
-
end
-
end
-
-
2
def call_match
-
# fail 'Method call_match not yet supported for UltraFLEX!'
-
2
@match_counter = @match_counter || 0
-
2
call_subroutine("match_done_#{@match_counter}")
-
2
@match_counter += 1 unless @match_counter == (@match_entries || 1) - 1
-
end
-
-
# Ultraflex implementation of J750-style 'set_code'
-
#
-
# Set a readcode, using one of the Ultraflex general-purpose counters.
-
# Counter C15 is used by default, this can be changed by the caller if necessary.
-
#
-
# Use to set an explicit readcode for communicating with the tester. This method
-
# will generate an additional vector (or 2, depending if set_msb is needed).
-
#
-
# NOTE: Some caveats when using this method:
-
# - When setting a counter from the pattern microcode, the actual Patgen counter value is set to n-1.
-
# This method adjusts by using a value of n+1, so the value read by the tester is the original intended value.
-
#
-
# - When setting a counter from pattern microcode, the upper bits must be loaded separately using 'set_msb'.
-
# This method calls the set_msb opcode if needed - note the tester must mask the upper 16 bits to get the desired value.
-
# The set_msb opcode will also generate a second vector the first time the set_code method is called.
-
#
-
# ==== Examples
-
# $tester.set_code(55)
-
#
-
2
def set_code(*code)
-
25
options = code.last.is_a?(Hash) ? code.pop : {}
-
25
options = { counter: 'c15'
-
}.merge(options)
-
25
cc " Using counter #{options[:counter]} as set_code replacement - value set to #{code[0]} + 1"
-
25
unless @set_msb_issued
-
25
set_msb(1)
-
25
cycle # set_msb doesn't issue a cycle
-
end
-
25
cycle(microcode: "set #{options[:counter]} #{code[0].next}") #+1 here to align with VBT
-
end
-
-
2
def set_code_no_msb(*code)
-
options = code.last.is_a?(Hash) ? code.pop : {}
-
options = { counter: 'c15'
-
}.merge(options)
-
unless @set_msb_issued
-
cycle # set_msb doesn't issue a cycle
-
end
-
cycle(microcode: "set #{options[:counter]} #{code[0].next}") #+1 here to align with VBT
-
end
-
-
2
def loop_vectors(name, number_of_loops, global = false, label_first = false)
-
3
if number_of_loops > 1
-
2
@loop_counters ||= {}
-
2
if @loop_counters[name]
-
1
@loop_counters[name] += 1
-
else
-
1
@loop_counters[name] = 0
-
end
-
2
loop_name = @loop_counters[name] == 0 ? name : "#{name}_#{@loop_counters[name]}"
-
2
if label_first
-
1
global_opt = (global) ? 'global ' : ''
-
1
microcode "#{global_opt}#{loop_name}: "
-
end
-
-
2
if "#{loop_name}" == 'row_loop'
-
cycle(microcode: 'loop c0')
-
2
elsif "#{loop_name}" == 'quad_loop'
-
cycle(microcode: 'loop c1')
-
2
elsif "#{loop_name}" == 'page_loop_red'
-
cycle(microcode: 'loop c2')
-
2
elsif "#{loop_name}" == 'page_loop_ecc'
-
cycle(microcode: 'loop c3')
-
2
elsif "#{loop_name}" == 'page_loop_data'
-
cycle(microcode: 'loop c4')
-
end
-
-
2
unless label_first
-
1
global_opt = (global) ? 'global ' : ''
-
1
cycle(microcode: "#{global_opt}#{loop_name}: ")
-
end
-
2
yield
-
2
cycle(microcode: "end_loop #{loop_name}")
-
else
-
1
yield
-
end
-
end
-
-
2
alias_method :loop_vector, :loop_vectors
-
-
2
def pattern_header(options = {})
-
options = {
-
20
instruments: {}
-
}.merge(options)
-
-
20
case $tester.vector_group_size
-
when 1
-
16
@opcode_mode = :single
-
when 2
-
2
@opcode_mode = :dual
-
when 4
-
2
@opcode_mode = :quad
-
end
-
-
20
options[:memory_test] = memory_test_en
-
20
options[:dc_pins] = get_dc_instr_pins
-
20
options[:digsrc_pins] = get_digsrc_pins
-
20
options[:digcap_pins] = get_digcap_pins
-
20
if options[:dc_pins]
-
16
options[:dc_pins].each do |pin|
-
32
options[:instruments].merge!(pin => 'DCVS')
-
end
-
end
-
-
# Syntax for Digital Source
-
# instruments = {
-
# pin-item:digsrc instrument-width: bit-order: instrument-mode:
-
# site-uniqueness: format: auto_cond;
-
# }
-
-
20
if options[:digsrc_pins]
-
16
@digsrc_settings.each do |setting_name, setting|
-
112
options.merge!(setting_name => setting) if options[setting_name].nil?
-
end
-
16
options[:digsrc_pins].each do |pin|
-
32
options[:instruments].merge!(pin => 'digsrc')
-
end
-
end
-
-
# Syntax for Digital Capture
-
# instruments = {
-
# pin-item:digcap instrument-width: bit-order: instrument-mode:
-
# format: data-type: auto_cond: auto_trig_enable: store_stv: receive_data;
-
# }
-
-
20
if options[:digcap_pins]
-
16
@digcap_settings.each do |setting_name, setting|
-
160
options.merge!(setting_name => setting) if options[setting_name].nil?
-
end
-
16
options[:digcap_pins].each do |pin|
-
16
options[:instruments].merge!(pin => 'digcap')
-
end
-
end
-
-
# If memory test, then add to instruments hash
-
20
if options[:memory_test]
-
16
options[:instruments].merge!('nil' => 'mto')
-
end
-
-
# If tester.overlay was used to implement digsrc, update the header instruments
-
20
auto_instr = {}
-
20
@overlay_history.each_pair do |pin_name, value|
-
6
if value[:is_digsrc]
-
4
microcode "// DigSrc SEND count for #{pin_name}: #{value[:count]}"
-
4
new_instr = 'DigSrc '
-
-
# override default settings
-
4
digsrc_overrides = source_memory(:digsrc).accumulate_attributes(pin_name)
-
-
# append instrument width
-
4
digsrc_instr_width = (dut.pin(pin_name)).size
-
# override default width if requested
-
4
digsrc_instr_width = digsrc_overrides[:size] unless digsrc_overrides[:size].nil?
-
4
new_instr += digsrc_instr_width.to_s
-
-
# append any other instrument override settings
-
4
if digsrc_instr_width > 1 && (dut.pin(pin_name)).size == 1
-
2
new_instr += ':serial'
-
2
if (digsrc_overrides[:bit_order] != :msb0) && (digsrc_overrides[:bit_order] != :msb)
-
2
new_instr += ':lsb'
-
else
-
new_instr += ':msb'
-
end
-
end
-
4
new_instr += ":format=#{digsrc_overrides[:format]}" unless digsrc_overrides[:format].nil?
-
4
new_instr += ":data_type=#{digsrc_overrides[:data_type]}" unless digsrc_overrides[:data_type].nil?
-
4
auto_instr["(#{pin_name})"] = new_instr
-
end
-
end
-
# If tester.store was used to implement digcap, update the header instruments
-
# TODO: a lot of duplication of digsrc logic here. This can be smart-ified.
-
20
@capture_history.each_pair do |pin_name, value|
-
2
if value[:is_digcap]
-
2
microcode "// DigCap Store count for #{pin_name}: #{value[:count]}"
-
2
new_instr = 'DigCap '
-
-
# override default settings
-
2
digcap_overrides = capture_memory(:digcap).accumulate_attributes(pin_name)
-
-
# append instrument width
-
2
digcap_instr_width = (dut.pin(pin_name)).size
-
2
digcap_instr_width = digcap_overrides[:size] unless digcap_overrides[:size].nil?
-
2
new_instr += digcap_instr_width.to_s
-
2
if digcap_instr_width > 1 && (dut.pin(pin_name)).size == 1
-
1
new_instr += ':serial'
-
1
if (digcap_overrides[:bit_order] != :msb0) && (digcap_overrides[:bit_order] != :msb)
-
1
new_instr += ':lsb'
-
else
-
new_instr += ':msb'
-
end
-
end
-
2
new_instr += ":format=#{digcap_overrides[:format]}" unless digcap_overrides[:format].nil?
-
2
new_instr += ":data_type=#{digcap_overrides[:data_type]}" unless digcap_overrides[:data_type].nil?
-
2
new_instr += ':auto_trig_enable' # always enable auto-trigger for digcap, trigger microcode isn't applied
-
2
auto_instr["(#{pin_name})"] = new_instr
-
end
-
end
-
20
options[:instruments] = options[:instruments].merge(auto_instr)
-
-
20
super(options.merge(digital_inst: @digital_instrument,
-
memory_test: false,
-
high_voltage: false,
-
svm_only: false
-
)) do |pin_list|
-
# if subroutine pattern has only single-module subroutines then skip module start
-
# (will be taken care of elsewhere)
-
20
unless options[:subroutine_pat] && @onemodsubs_found && !@nonmodsubs_found
-
19
microcode "#{options[:subroutine_pat] ? 'srm_vector' : 'vm_vector'}"
-
19
microcode "#{options[:pattern]} ($tset, #{pin_list})"
-
19
microcode '{'
-
end
-
# override min vector limit if subroutine pattern
-
20
@min_pattern_vectors = 0 if options[:subroutine_pat]
-
20
unless options[:subroutine_pat]
-
18
microcode "start_label #{options[:pattern]}_st:"
-
end
-
end
-
end
-
-
2
def pattern_footer(options = {})
-
# if subroutine pattern has any single-module subroutines then skip module end
-
# (will be taken care of elsewhere)
-
21
unless options[:subroutine_pat] && @onemodsubs_found
-
19
super(options.merge(end_module: false))
-
end
-
end
-
-
# allow for option of separate modules for each subroutine
-
# requirement is that any subroutines in their own module (options[:onemodsub] = true)
-
# MUST be implemented AFTER any subroutines in the common pattern module!
-
2
def start_subroutine(name, options = {})
-
23
if options[:onemodsub]
-
8
if @nonmodsubs_found && !@onemodsubs_found
-
# this means we need to do end module for non-single-module subroutines
-
# do only once!
-
1
pattern_footer(options.merge(subroutine_pat: true, end_module: false))
-
end
-
8
@onemodsubs_found = true # importnat put this after the call to pattern_footer above
-
8
pin_list = ordered_pins.map(&:name).join(', ')
-
8
microcode 'srm_vector'
-
8
microcode "#{name}_module ($tset, #{pin_list})"
-
8
microcode '{'
-
else
-
# normal subroutine to use common
-
15
if @onemodsubs_found
-
# give error -- requirement is that any normal subroutines using common pattern module
-
# must be done BEFORE any subroutines that need their own module definition!
-
fail "ERROR: Cannot implement any common module subroutines (#{name}) after implementing any single-module subroutines in the same pattern!"
-
end
-
15
@nonmodsubs_found = true
-
end
-
23
super(name, options)
-
end
-
-
2
def end_subroutine(cond = false, options = {})
-
23
(cond, options) = false, cond if cond.is_a?(Hash)
-
23
super(cond, options)
-
23
if options[:onemodsub]
-
8
microcode '}'
-
end
-
end
-
-
# Generates a match loop based on vector condition passed in via block
-
#
-
# This method is not really intended to be called directly, rather you should call
-
# via Tester#wait:
-
# e.g. $tester.wait(:match => true) do
-
# reg(:status_reg).bit(:done).read(1)! # vector condition that you want to match
-
# end
-
#
-
# The timeout should be provided in cycles, however when called via the wait method the
-
# time-based helpers (time_in_us, etc) will be converted to cycles for you.
-
#
-
# The following options are available to tailor the match loop behavior, defaults in
-
# parenthesis:
-
# * :force_fail_on_timeout (true) - Force a vector mis-compare if the match loop times out
-
# * :on_timeout_goto ("") - Optionally supply a label to branch to on timeout, by default will continue from the end of the match loop
-
# * :on_block_match_goto ("") - Optionally supply a label to branch to when block condition is met, by default will continue from the end of the match loop
-
# * :multiple_entries (false) - Supply an integer to generate multiple entries into the match (each with a unique readcode), this can be useful when debugging patterns with multiple matches
-
# * :force_fail_on_timeout (true) - force pattern to fail if timeout occurs
-
# * :global_loops (false) - whether match loop loops should use global labels
-
# * :manual_stop (false) - whether to use extra cpuB flag to resolve IG-XL v.3.50.xx bug where VBT clears cpuA immediately
-
# at start of PatFlagFunc instead of at end. Use will have to manually clear cpuB to resume this pattern.
-
# ==== Examples
-
# $tester.wait(:match => true, :time_in_us => 5000, :pin => $top.pin(:done), :state => :high) do
-
# <vectors>
-
# end
-
2
def match_block(timeout, options = {}, &block)
-
options = {
-
13
check_for_fails: false,
-
on_timeout_goto: false,
-
on_block_match_goto: false,
-
multiple_entries: false,
-
force_fail_on_timeout: true,
-
global_loops: false,
-
manual_stop: false,
-
clr_fail_post_match: false
-
}.merge(options)
-
-
13
unless block_given?
-
fail 'ERROR: block not passed to match_block!'
-
end
-
-
# if options[:check_for_fails]
-
# cc 'NOTE: check for fails prior to match loop not necessary on UltraFlex'
-
# end
-
-
# ss 'WARNING: MATCH LOOP FOR ULTRAFLEX STILL UNDER DEVELOPMENT'
-
-
# Create BlockArgs objects in order to receive multiple blocks
-
13
match_conditions = Origen::Utility::BlockArgs.new
-
13
fail_conditions = Origen::Utility::BlockArgs.new
-
-
# yield object to calling routine to get populated with blocks
-
13
if block.arity > 0
-
8
yield match_conditions, fail_conditions
-
else
-
# for backwards compatibility with Origen core call to match_block
-
5
match_conditions.add(&block)
-
5
fail_conditions.add(&block)
-
end
-
-
13
if options[:check_for_fails]
-
9
if options[:multiple_entries]
-
1
@match_entries.times do |i|
-
10
microcode "global subr match_done_#{i}:"
-
10
set_code(i + 100)
-
10
cycle(microcode: 'jump call_tester') unless i == @match_entries - 1
-
end
-
1
microcode 'call_tester:'
-
else
-
8
set_code(100)
-
end
-
9
cc 'Wait for any prior failures to propagate through the pipeline'
-
9
cycle(microcode: 'pipe_minus 1')
-
9
cc 'Now handshake with the tester to bin out and parts that have failed before they got here'
-
9
handshake(manual_stop: options[:manual_stop])
-
end
-
-
# Now do the main match loop
-
13
cc 'Start the match loop'
-
-
13
cycle # (:microcode => "set_msb #{counter_msb}") # set_msb microcode will be set below after counting match loop cycles
-
13
set_msb_vector = last_vector # remember the vector with set_msb opcode
-
-
13
cycle(microcode: 'branch_expr = (fail)')
-
-
13
global_opt = (options[:global_loops]) ? 'global ' : ''
-
13
microcode "#{global_opt}match_loop_#{@unique_counter}:"
-
-
13
cycle # (:microcode => "set c0 #{counter_lsb}")
-
13
set_c0_vector = last_vector # remember the vector with set_c0 opcode
-
-
13
microcode "match_result_loop_#{@unique_counter}:"
-
13
cycle(microcode: 'loop c0')
-
-
# count cycles in match loop block passed to help with meeting
-
# desired timeout value (have to back assign microcodes above)
-
13
prematch_cycle_count = cycle_count
-
13
match_conditions.each_with_index do |condition, i|
-
16
mask_fails(true)
-
16
condition.call # match condition
-
16
mask_fails(false)
-
-
16
cc ' Wait for the result to propagate through the pipeline'
-
16
cycle(microcode: 'pipe_minus 1')
-
16
inc_cycle_count(@pipeline_depth - 1) # Account for pipeline depth
-
16
cc "Branch if block condition #{i} not yet met"
-
16
cycle(microcode: "if (branch_expr) jump block_#{i}_notyet_matched_#{@unique_counter}")
-
16
cc 'Match found'
-
16
cycle(microcode: 'pop_loop')
-
16
if options[:on_block_match_goto]
-
2
if options[:on_block_match_goto].is_a?(Hash)
-
2
if options[:on_block_match_goto][i]
-
1
custom_jump = options[:on_block_match_goto][i]
-
else
-
1
custom_jump = nil
-
end
-
else
-
custom_jump = options[:on_block_match_goto]
-
end
-
end
-
16
if custom_jump
-
1
cycle(microcode: "jump #{custom_jump}")
-
else
-
15
cycle(microcode: "jump match_loop_end_#{@unique_counter}")
-
end
-
16
cc 'Match not yet found'
-
16
cycle(microcode: "block_#{i}_notyet_matched_#{@unique_counter}:")
-
end
-
-
13
match_conditions_cycle_count = cycle_count - prematch_cycle_count
-
13
cc "Match loop cycle count = #{match_conditions_cycle_count}"
-
-
# reduce timeout requested by match loop cycle count
-
13
timeout = (timeout.to_f / match_conditions_cycle_count).ceil
-
-
# Calculate the counter values appropriately hit the timeout requested
-
13
match_delay_cycles = false
-
-
# Determine full value of counter0
-
13
counter_value = timeout.to_f.floor
-
-
13
if counter_value < (2**@counter_lsb_bits)
-
# small value, don't need msb temp register
-
8
counter_msb = 1
-
8
counter_lsb = counter_value
-
5
elsif counter_value < (2**(@counter_lsb_bits + @counter_msb_bits))
-
# larger value, but smaller than counter maximum
-
4
counter_msb = counter_value # set MSB (lowest LSB bits get ignored)
-
4
counter_lsb = counter_value & (2**@counter_lsb_bits - 1) # set LSB
-
1
elsif counter_value < (2**(@counter_lsb_bits + @counter_msb_bits)) * @max_repeat_loop
-
# larger value, greater than counter, so add time delay per instance of loop to avoid using second counter
-
1
match_delay_cycles = (counter_value.to_f / (2**(@counter_lsb_bits + @counter_msb_bits))).ceil
-
1
counter_msb = (counter_value / match_delay_cycles).floor # set MSB (lowest LSB bits get ignored)
-
1
counter_lsb = counter_msb & (2**@counter_lsb_bits - 1) # set LSB
-
else
-
abort 'ERROR: timeout value too large in tester match method!'
-
end
-
-
# retroactively modify the counters based on cycles in match loop conditions
-
13
unless @inhibit_vectors
-
9
set_msb_vector.microcode = "set_msb #{counter_msb}"
-
9
set_c0_vector.microcode = "set c0 #{counter_lsb}"
-
end
-
-
13
if match_delay_cycles
-
1
cc 'Delay to meet timeout value'
-
1
cycle(repeat: match_delay_cycles) if match_delay_cycles
-
end
-
-
13
cycle(microcode: "end_loop match_result_loop_#{@unique_counter}")
-
-
13
if options[:force_fail_on_timeout]
-
13
cc 'To get here something has gone wrong, check blocks again to force a pattern failure'
-
13
fail_conditions.each do |condition|
-
13
cycle(microcode: 'pipe_minus 1')
-
13
condition.call
-
end
-
end
-
13
if options[:on_timeout_goto]
-
1
cycle(microcode: "jump #{options[:on_timeout_goto]}")
-
else
-
12
cycle(microcode: "jump match_loop_end_#{@unique_counter}")
-
end
-
13
cycle(microcode: "match_loop_end_#{@unique_counter}:")
-
-
13
@unique_counter += 1 # Increment so a different label will be applied if another
-
# handshake is called in the same pattern
-
end
-
-
# Handshake with the tester.
-
#
-
# Will set a cpu flag (A) and wait for it to be cleared by the tester, optionally
-
# pass in a read code to pass information to the tester.
-
#
-
# ==== Examples
-
# $tester.handshake # Pass control to the tester for a measurement
-
# $tester.handshake(:readcode => 10) # Trigger a specific action by the tester
-
2
def handshake(options = {})
-
options = {
-
12
readcode: false,
-
manual_stop: false, # set a 2nd CPU flag in case 1st flag is automatically cleared
-
}.merge(options)
-
12
if options[:readcode]
-
2
set_code(options[:readcode])
-
end
-
12
if options[:manual_stop]
-
9
cycle(microcode: "#{@microcode[:enable]} (#{@flags[1]})")
-
9
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[0]} #{@flags[1]})")
-
else
-
3
cycle(microcode: "#{@microcode[:enable]} (#{@flags[0]})")
-
3
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[0]})")
-
end
-
12
cycle(microcode: "loop_here_#{@unique_counter}: if (branch_expr) jump loop_here_#{@unique_counter}")
-
-
12
@unique_counter += 1 # Increment so a different label will be applied if another
-
# handshake is called in the same pattern
-
end
-
-
2
def keep_alive(options = {})
-
2
if options[:subroutine_pat]
-
1
cycle(microcode: 'clr_subr')
-
1
cycle(microcode: "#{@microcode[:enable]} (#{@flags[3]})")
-
1
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[3]})")
-
1
cycle(microcode: "loop_here_#{@unique_counter}: if (branch_expr) jump loop_here_#{@unique_counter}")
-
1
cycle
-
1
@unique_counter += 1 # Increment so a different label will be applied if another
-
else
-
1
$tester.cycle
-
1
call_subroutine('keep_alive')
-
end
-
end
-
-
# Capture a vector to the tester HRAM.
-
#
-
# This method applys a store vector (stv) opcode to the previous vector, note that is does
-
# not actually generate a new vector.
-
#
-
# Sometimes when generating vectors within a loop you may want to apply a stv opcode
-
# retrospectively to a previous vector, passing in an offset option will allow you
-
# to do this.
-
#
-
# On J750 the pins argument is ignored since the tester only supports whole vector capture.
-
#
-
# @example
-
# $tester.cycle # This is the vector you want to capture
-
# $tester.store # This applys the STV opcode
-
#
-
# $tester.cycle # This one gets stored
-
# $tester.cycle
-
# $tester.cycle
-
# $tester.store(:offset => -2) # Just realized I need to capture that earlier vector
-
2
def store(*pins)
-
15
return if @inhibit_vectors
-
13
options = pins.last.is_a?(Hash) ? pins.pop : {}
-
13
options = { offset: 0,
-
opcode: 'stv'
-
}.merge(options)
-
13
pins = pins.flatten.compact
-
13
if pins.empty?
-
fail 'For the UltraFLEX you must supply the pins to store/capture'
-
end
-
-
13
capt_style = options[:capture_style].nil? ? @capture_style : options[:capture_style]
-
13
if capt_style == :digcap
-
1
capt_microcode = dssc_store(pins, options)
-
else
-
12
capt_microcode = options[:opcode]
-
end
-
-
13
pins.each do |pin|
-
13
pin.restore_state do
-
13
pin.capture
-
13
update_vector_pin_val pin, offset: options[:offset]
-
13
last_vector(options[:offset]).dont_compress = true
-
end
-
end
-
13
update_vector microcode: capt_microcode, offset: options[:offset]
-
end
-
2
alias_method :to_hram, :store
-
2
alias_method :capture, :store
-
-
# use digcap to store, called by tester.store()
-
2
def dssc_store(pins, options)
-
1
repeat_count = last_vector(options[:offset]).repeat
-
1
capt_microcode = []
-
1
pins.each do |pin|
-
1
if @capture_history[pin.name].nil?
-
1
@capture_history[pin.name] = { is_digcap: true, count: repeat_count }
-
else
-
@capture_history[pin.name][:count] += repeat_count
-
end
-
1
capt_microcode << "((#{pin.name}):DigCap = Store)"
-
end
-
1
capt_microcode << 'stv'
-
1
capt_microcode.join(',')
-
end
-
-
2
def reload_counters(name)
-
microcode "reload #{name}"
-
end
-
-
2
def set_msb(integer)
-
25
microcode "set_msb #{integer}"
-
end
-
-
# Capture the next vector generated to HRAM
-
#
-
# This method applies a store vector (stv) opcode to the next vector to be generated,
-
# note that is does not actually generate a new vector.
-
#
-
# pin argument must be provided so that 'V' (valid) state can be applied to the pin
-
# if not already.
-
#
-
# @example
-
# $tester.store_next_cycle
-
# $tester.cycle # This is the vector that will be captured
-
2
def store_next_cycle(*pins)
-
3
return if @inhibit_vectors
-
2
options = pins.last.is_a?(Hash) ? pins.pop : {}
-
options = {
-
2
opcode: 'stv'
-
}.merge(options)
-
2
pins = pins.flatten.compact
-
2
if pins.empty?
-
fail 'For the UltraFLEX you must supply the pins to store/capture'
-
end
-
-
2
capt_style = options[:capture_style].nil? ? @capture_style : options[:capture_style]
-
2
if capt_style == :digcap
-
2
capt_microcode = []
-
2
repeat_count = options[:repeat].nil? ? 1 : options[:repeat]
-
2
pins.each do |pin|
-
2
if @capture_history[pin.name].nil?
-
1
@capture_history[pin.name] = { is_digcap: true, count: repeat_count }
-
else
-
1
@capture_history[pin.name][:count] += repeat_count
-
end
-
2
capt_microcode << "((#{pin.name}):DigCap = Store)"
-
end
-
2
capt_microcode << 'stv'
-
2
capt_microcode = capt_microcode.join(',')
-
else
-
capt_microcode = options[:opcode]
-
end
-
-
4
pins.each { |pin| pin.save; pin.capture }
-
# Register this clean up function to be run after the next vector
-
# is generated (SMcG: cool or what! DH: Yes, very cool!)
-
2
preset_next_vector(microcode: capt_microcode) do
-
2
pins.each(&:restore)
-
end
-
end
-
2
alias_method :store!, :store_next_cycle
-
-
# ate_hardware stores "key" UltraFLEX hardware information needed for test program generation
-
# Instrument types available for ppmu: "HSD-M", "HSD-U", "HSD-4G", and "HSS-6G".
-
# Sample usage: $tester.ate_hardware("HSD-U").ppmu
-
# Instrument types available for supply: "VSM", "VSMx2", "VSMx4", "HexVS", "HexVSx2", "HexVSx4",
-
# "HexVSx6", "HexVS+x2", "HexVS+x4", "HexVS+x6", "HDVS1", "HDVS1x2", "HDVS1x4", "VHDVS",
-
# "VHDVS_HC", "VHDVSx2", "VHDVS_HCx2", "VHDVS_HCx4", "VHDVS_HCx8", "VHDVS+", "VHDVS_HC+",
-
# "VHDVS+x2", "VHDVS_HC+x2", "VHDVS_HC+x4", and "VHDVS_HC+x8".
-
# HDVS1 is also known as HDVS. VHDVS is also known as UVS256.
-
# x2 is Merged2, x4 is Merged4, x6 is Merged6. _HC is High-Current.
-
# + is High-Accuracy.
-
# Sample usage: $tester.ate_hardware("VSM").supply
-
# Sample usage: $tester.ate_hardware("HSD-M").ppmu
-
2
def ate_hardware(instrumentname = '')
-
32
@ate_hardware = ATEHardware.new(instrumentname)
-
end
-
end
-
end
-
2
UltraFLEX = IGXLBasedTester::UltraFLEX
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/ac_specsets'
-
2
class ACSpecsets < Base::ACSpecsets
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/ultraflex/templates/ac_specsets.txt.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX < Base
-
2
class ATEHardware
-
2
attr_accessor :instrument
-
-
2
def initialize(instrumentname)
-
32
@name = 'ultraflex'
-
32
@instrument ||= instrumentname
-
end
-
-
2
def ppmu
-
5
ppmu = Struct.new(:forcei, :forcev, :measi, :measv, :vclamp)
-
-
5
if @instrument == 'HSD-M' # also known as HSD1000
-
1
forcei = [20.uA, 200.uA, 2.mA, 50.mA]
-
1
forcev = { forcei_50mA__gt_20mA: (-0.1.V..4.5.V),
-
1
forcei_50mA__lte_20mA: (-1.V..6.V),
-
1
forcei_Non50mA__half_scale: (-1..6.V),
-
1
forcei_Non50mA__full_scale: (-1.V..5.5.V) }
-
1
measi = [2.uA, 20.uA, 200.uA, 2.mA, 50.mA]
-
1
measv = { measi_50mA__gt_20mA: (-0.1.V..4.5.V),
-
1
measi_50mA__lte_20mA: (-1.V..6.V),
-
1
measi_20mA__0p5mA_to_20mA: (-1.V..5.5.V),
-
1
measi_20mA__0p05mA_to_1mA: (-1.V..6.V),
-
1
measi_20mA__n0p5mA_to_0p5mA: (-1.85.V..6.V),
-
1
measi_20mA__n1mA_to_n0p5mA: (-1.V..6.V),
-
1
measi_20mA__n2mA_to_n1mA: (-1.V..5.5.V),
-
1
measi_200uA__half_scale: (-1.V..6.V),
-
1
measi_200uA__full_scale: (-1.V..5.V),
-
1
measi_20uA__half_scale: (-1.V..6.V),
-
1
measi_20uA__full_scale: (-1.V..5.5.V) }
-
1
vclamp = (-2.V..6.5.V)
-
1
ppmu.new(forcei, forcev, measi, measv, vclamp)
-
4
elsif @instrument == 'HSD-U' # also known as Ultrapin1600 or Utah
-
2
forcei = [20.uA, 200.uA, 2.mA, 50.mA]
-
2
forcev = { forcei_50mA__20mA_to_50mA: (-0.1.V..4.5.V),
-
2
forcei_50mA__0mA_to_20mA: (-1.V..6.V),
-
2
forcei_50mA__n20mA_to_0mA: (-0.1.V..6.V),
-
2
forcei_50mA__n35mA_to_n20mA: (0.5.V..5.1.V),
-
2
forcei_50mA__n50mA_to_n35mA: (1.1.V..4.5.V),
-
2
forcei_Non50mA: (-1.V..6.V) }
-
2
measi = [2.uA, 20.uA, 200.uA, 2.mA, 50.mA]
-
2
measv = { measi_50mA: (-1.V..6.V),
-
2
measi_200uA: (-1.V..6.V),
-
2
measi_20uA: (-1.V..6.V),
-
2
measi_2mA__1mA_to_2mA: (-1.V..6.V),
-
2
measi_2mA__n1mA_to_1mA: (-1.5.V..6.V),
-
2
measi_2mA__n2mA_to_n1mA: (-1.V..6.V) }
-
2
vclamp = (-1.5.V..6.5.V)
-
2
ppmu.new(forcei, forcev, measi, measv, vclamp)
-
2
elsif @instrument == 'HSD-4G'
-
1
forcei = [200.uA, 2.mA, 30.mA]
-
1
forcev = { measi_30mA: [min: '1.5V, 1.5V - 50mV/mA * Idut', max: '0V, -50mV/mA * Idut'],
-
1
measi_2mA: (-1.V..1.5.V),
-
1
measi_200uA: (-1.V..1.5.V) }
-
1
measi = [200.uA, 2.mA, 30.mA]
-
1
measv = (-1.V..1.5.V)
-
1
vclamp = 'n/a'
-
1
ppmu.new(forcei, forcev, measi, measv, vclamp)
-
1
elsif @instrument == 'HSS-6G' # also known as SB6G
-
1
forcei = [200.uA, 2.mA, 50.mA]
-
1
forcev = { forcei_50mA__gt_20mA: (-0.1.V..3.6.V),
-
1
forcei_50mA__lte_20mA: (-1.V..3.6.V),
-
1
forcei_2mA: (-1.V..3.6.V),
-
1
forcei_200uA: (-1.V..3.6.V) }
-
1
measi = [200.uA, 2.mA, 50.mA]
-
1
measv = { measi_50mA__gt_20mA: (-0.1.V..3.6.V),
-
1
measi_50mA__lte_20mA: (-1.V..3.6.V),
-
1
measi_200uA: (-1.V..3.6.V),
-
1
measi_2mA: (-1.V..3.6.V) }
-
1
vclamp = (-1.3.V..3.9.V)
-
1
ppmu.new(forcei, forcev, measi, measv, vclamp)
-
else
-
puts "please enter an instrument type: e.g. $tester.ate_hardware(\"HSD-M\").ppmu"
-
puts "Instrument type available: \"HSD-M\", \"HSD-U\", \"HSD-4G\", and \"HSS-6G\" "
-
puts 'HSD-U is also known as Ultrapin1600. HSS-6G is also known as SB6G.'
-
end
-
end
-
-
2
def supply
-
27
supply = Struct.new(:forcev, :irange, :source_overload_i, :source_overload_t, :source_fold_i,
-
:source_fold_t, :sink_overload_i, :sink_overload_t, :sink_fold_i,
-
:sink_fold_t, :meter_irange, :meter_vrange, :tdelay, :accuracy,
-
:filter, :bandwidth)
-
27
if @instrument == 'VSM'
-
1
forcev = (0.V..4.V)
-
1
irange = [1.A, 11.A, 21.A, 51.A, 81.A]
-
1
source_overload_i = { irange_1A: (100.mA..1.08.A),
-
1
irange_11A: (1.1.A..11.88.A),
-
1
irange_21A: (2.1.A..22.68.A),
-
1
irange_51A: (5.1.A..55.08.A),
-
1
irange_81A: (8.1.A..87.48.A) }
-
1
source_overload_t = (10.uS..8.S)
-
1
source_fold_i = { irange_1A: (50.mA..1.03.A),
-
1
irange_11A: (550.mA..11.33.A),
-
1
irange_21A: (1.05.A..21.63.A),
-
1
irange_51A: (2.55.A..52.53.A),
-
1
irange_81A: (4.05.A..83.43.A) }
-
1
source_fold_t = (10.uS..8.S)
-
1
sink_overload_i = { irange_1A: [max: 78.mA], # ????? Not programmable?
-
irange_11A: [max: 858.mA], # ????? Not programmable?
-
irange_21A: [max: 1.64.A], # ????? Not programmable?
-
irange_51A: [max: 3.98.A], # ????? Not programmable?
-
irange_81A: [max: 6.32.A] } # ????? Not programmable?
-
1
sink_overload_t = 0 # ????? Not programmable?
-
1
sink_fold_i = { irange_1A: [max: 78.mA], # ????? Not programmable?
-
irange_11A: [max: 858.mA], # ????? Not programmable?
-
irange_21A: [max: 1.64.A], # ????? Not programmable?
-
irange_51A: [max: 3.98.A], # ????? Not programmable?
-
irange_81A: [max: 6.32.A] } # ????? Not programmable?
-
1
sink_fold_t = (10.uS..8.S)
-
1
meter_irange = { irange_1A: [1.25.A, 2.5.A],
-
irange_11A: [13.75.A, 27.5.A],
-
irange_21A: [26.25.A, 52.5.A],
-
irange_51A: [63.75.A, 127.5.A],
-
irange_81A: [101.25.A, 202.5.A] }
-
1
meter_vrange = [3.V, 6.V]
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: -2.mV, pos: 2.mV }
-
1
filter = [635, 2539, 40_625]
-
1
bandwidth = [0, 1, 2, 3, 4]
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
26
elsif @instrument == 'VSMx2' # Also known as VSM, Merged2
-
1
forcev = (0.V..4.V)
-
1
irange = [1.A, 2.A, 11.A, 21.A, 51.A, 81.A, 102.A, 162.A]
-
1
source_overload_i = { irange_1A: (100.mA..1.08.A),
-
1
irange_2A: (200.mA..2.16.A),
-
1
irange_11A: (1.1.A..11.88.A),
-
1
irange_21A: (2.1.A..22.68.A),
-
1
irange_51A: (5.1.A..55.08.A),
-
1
irange_81A: (8.1.A..87.48.A),
-
1
irange_102A: (10.2.A..110.16.A),
-
1
irange_162A: (16.2.A..174.96.A) }
-
1
source_overload_t = (10.uS..8.S)
-
1
source_fold_i = { irange_1A: (50.mA..1.03.A),
-
1
irange_2A: (100.mA..2.06.A),
-
1
irange_11A: (550.mA..11.33.A),
-
1
irange_21A: (1.05.A..21.63.A),
-
1
irange_51A: (2.55.A..52.53.A),
-
1
irange_81A: (4.05.A..83.43.A),
-
1
irange_102A: (5.1.A..105.06.A),
-
1
irange_162A: (8.1.A..166.86.A) }
-
1
source_fold_t = (10.uS..8.S)
-
1
sink_overload_i = { irange_1A: [max: 78.mA], # ????? Not programmable?
-
irange_2A: [max: 156.mA], # ????? Not programmable?
-
irange_11A: [max: 858.mA], # ????? Not programmable?
-
irange_21A: [max: 1.64.A], # ????? Not programmable?
-
irange_51A: [max: 3.98.A], # ????? Not programmable?
-
irange_81A: [max: 6.32.A], # ????? Not programmable?
-
irange_102A: [max: 7.96.A], # ????? Not programmable?
-
irange_162A: [max: 12.64.A] } # ????? Not programmable?
-
1
sink_overload_t = 0 # ????? Not programmable?
-
1
sink_fold_i = { irange_1A: [max: 78.mA], # ????? Not programmable?
-
irange_2A: [max: 156.mA], # ????? Not programmable?
-
irange_11A: [max: 858.mA], # ????? Not programmable?
-
irange_21A: [max: 1.64.A], # ????? Not programmable?
-
irange_51A: [max: 3.98.A], # ????? Not programmable?
-
irange_81A: [max: 6.32.A], # ????? Not programmable?
-
irange_102A: [max: 7.96.A], # ????? Not programmable?
-
irange_162A: [max: 12.64.A] } # ????? Not programmable?
-
1
meter_irange = { irange_1A: [1.25.A, 2.5.A],
-
irange_2A: [2.5.A, 5.A],
-
irange_11A: [13.75.A, 27.5.A],
-
irange_21A: [26.25.A, 52.5.A],
-
irange_51A: [63.75.A, 127.5.A],
-
irange_81A: [101.25.A, 202.5.A],
-
irange_102A: [127.5.A, 255.A],
-
irange_162A: [202.5.A, 405.A] }
-
1
sink_fold_t = (10.uS..8.S)
-
1
meter_vrange = [3.V, 6.V]
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: -2.mV, pos: 2.mV }
-
1
filter = [635, 2539, 40_625]
-
1
bandwidth = [0, 1, 2, 3, 4]
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
25
elsif @instrument == 'HexVS'
-
1
forcev = (0.V..5.5.V)
-
1
irange = 15.A
-
1
source_overload_i = (1.05.A..16.5.A)
-
1
source_overload_t = (102.4.uS..300.mS)
-
1
source_fold_i = (50.mA..15.5.A)
-
1
source_fold_t = (102.4.uS..5.S)
-
1
sink_overload_i = (2.A..3.A)
-
1
sink_overload_t = (102.4.uS..300.mS)
-
1
sink_fold_i = (1.A..2.A)
-
1
sink_fold_t = (102.4.uS..5.S)
-
1
meter_irange = [10.mA, 100.mA, 1.A, 15.A]
-
1
meter_vrange = [4.V, 8.V]
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: -7.mV, pos: 7.mV }
-
1
filter = 10_000
-
1
bandwidth = [0, 1, 2, 3, 4, 5, 6, 7]
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
24
elsif @instrument == 'HexVSx2' # Also known as HexVS, Merged2
-
1
forcev = (0.V..5.5.V)
-
1
irange = [15.A, 30.A]
-
1
source_overload_i = { irange_15A: (1.05.A..16.5.A),
-
1
irange_30A: (2.1.A..33.A) }
-
1
source_overload_t = (102.4.uS..300.mS)
-
1
source_fold_i = { irange_15A: (50.mA..15.5.A),
-
1
irange_30A: (100.mA..31.A) }
-
1
source_fold_t = (102.4.uS..5.S)
-
1
sink_overload_i = { irange_15A: (2.A..3.A),
-
1
irange_30A: (4.A..6.A) }
-
1
sink_overload_t = (102.4.uS..300.mS)
-
1
sink_fold_i = { irange_15A: (1.A..2.A),
-
1
irange_30A: (2.A..4.A) }
-
1
sink_fold_t = (102.4.uS..5.S)
-
1
meter_irange = { irange_15A: [10.mA, 100.mA, 1.A, 15.A],
-
irange_30A: [30.A] } # This is verified to be correct on tester.
-
1
meter_vrange = [4.V, 8.V]
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: -7.mV, pos: 7.mV }
-
1
filter = 10_000
-
1
bandwidth = [0, 1, 2, 3, 4, 5, 6, 7]
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
23
elsif @instrument == 'HexVSx4' # Also known as HexVS, Merged4
-
1
forcev = (0.V..5.5.V)
-
1
irange = [15.A, 60.A]
-
1
source_overload_i = { irange_15A: (1.05.A..16.5.A),
-
1
irange_60A: (4.2.A..66.A) }
-
1
source_overload_t = (102.4.uS..300.mS)
-
1
source_fold_i = { irange_15A: (50.mA..15.5.A),
-
1
irange_60A: (200.mA..62.A) }
-
1
source_fold_t = (102.4.uS..5.S)
-
1
sink_overload_i = { irange_15A: (2.A..3.A),
-
1
irange_60A: (8.A..12.A) }
-
1
sink_overload_t = (102.4.uS..300.mS)
-
1
sink_fold_i = { irange_15A: (1.A..2.A),
-
1
irange_60A: (4.A..8.A) }
-
1
sink_fold_t = (102.4.uS..5.S)
-
1
meter_irange = { irange_15A: [10.mA, 100.mA, 1.A, 15.A],
-
irange_60A: [60.A] } # This is verified to be correct on tester.
-
1
meter_vrange = [4.V, 8.V]
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: -7.mV, pos: 7.mV }
-
1
filter = 10_000
-
1
bandwidth = [0, 1, 2, 3, 4, 5, 6, 7]
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
22
elsif @instrument == 'HexVSx6' # Also known as HexVS, Merged6
-
1
forcev = (0.V..5.5.V)
-
1
irange = [15.A, 90.A]
-
1
source_overload_i = { irange_15A: (1.05.A..16.5.A),
-
1
irange_90A: (6.3.A..99.A) }
-
1
source_overload_t = (102.4.uS..300.mS)
-
1
source_fold_i = { irange_15A: (50.mA..15.5.A),
-
1
irange_90A: (300.mA..93.A) }
-
1
source_fold_t = (102.4.uS..5.S)
-
1
sink_overload_i = { irange_15A: (2.A..3.A),
-
1
irange_90A: (12.A..18.A) }
-
1
sink_overload_t = (102.4.uS..300.mS)
-
1
sink_fold_i = { irange_15A: (1.A..2.A),
-
1
irange_90A: (6.A..12.A) }
-
1
sink_fold_t = (102.4.uS..5.S)
-
1
meter_irange = { irange_15A: [10.mA, 100.mA, 1.A, 15.A],
-
irange_90A: [90.A] } # This is verified to be correct on tester.
-
1
meter_vrange = [4.V, 8.V]
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: -7.mV, pos: 7.mV }
-
1
filter = 10_000
-
1
bandwidth = [0, 1, 2, 3, 4, 5, 6, 7]
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
21
elsif @instrument == 'HexVS+'
-
1
forcev = (0.V..5.5.V)
-
1
irange = 15.A
-
1
source_overload_i = (1.05.A..16.5.A)
-
1
source_overload_t = (102.4.uS..300.mS)
-
1
source_fold_i = (50.mA..15.5.A)
-
1
source_fold_t = (102.4.uS..5.S)
-
1
sink_overload_i = (2.A..3.A)
-
1
sink_overload_t = (102.4.uS..300.mS)
-
1
sink_fold_i = (1.A..2.A)
-
1
sink_fold_t = (102.4.uS..5.S)
-
1
meter_irange = [10.mA, 100.mA, 1.A, 15.A]
-
1
meter_vrange = [4.V, 8.V]
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: -2.mV, pos: 2.mV }
-
1
filter = 10_000
-
1
bandwidth = [0, 1, 2, 3, 4, 5, 6, 7]
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
20
elsif @instrument == 'HexVS+x2' # Also known as HexVS+, Merged2
-
1
forcev = (0.V..5.5.V)
-
1
irange = [15.A, 30.A]
-
1
source_overload_i = { irange_15A: (1.05.A..16.5.A),
-
1
irange_30A: (2.1.A..33.A) }
-
1
source_overload_t = (102.4.uS..300.mS)
-
1
source_fold_i = { irange_15A: (50.mA..15.5.A),
-
1
irange_30A: (100.mA..31.A) }
-
1
source_fold_t = (102.4.uS..5.S)
-
1
sink_overload_i = { irange_15A: (2.A..3.A),
-
1
irange_30A: (4.A..6.A) }
-
1
sink_overload_t = (102.4.uS..300.mS)
-
1
sink_fold_i = { irange_15A: (1.A..2.A),
-
1
irange_30A: (2.A..4.A) }
-
1
sink_fold_t = (102.4.uS..5.S)
-
1
meter_irange = { irange_15A: [10.mA, 100.mA, 1.A, 15.A],
-
irange_30A: [30.A] } # This is verified to be correct on tester.
-
1
meter_vrange = [4.V, 8.V]
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: -2.mV, pos: 2.mV }
-
1
filter = 10_000
-
1
bandwidth = [0, 1, 2, 3, 4, 5, 6, 7]
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
19
elsif @instrument == 'HexVS+x4' # Also known as HexVS+, Merged4
-
1
forcev = (0.V..5.5.V)
-
1
irange = [15.A, 60.A]
-
1
source_overload_i = { irange_15A: (1.05.A..16.5.A),
-
1
irange_60A: (4.2.A..66.A) }
-
1
source_overload_t = (102.4.uS..300.mS)
-
1
source_fold_i = { irange_15A: (50.mA..15.5.A),
-
1
irange_60A: (200.mA..62.A) }
-
1
source_fold_t = (102.4.uS..5.S)
-
1
sink_overload_i = { irange_15A: (2.A..3.A),
-
1
irange_60A: (8.A..12.A) }
-
1
sink_overload_t = (102.4.uS..300.mS)
-
1
sink_fold_i = { irange_15A: (1.A..2.A),
-
1
irange_60A: (4.A..8.A) }
-
1
sink_fold_t = (102.4.uS..5.S)
-
1
meter_irange = { irange_15A: [10.mA, 100.mA, 1.A, 15.A],
-
irange_60A: [60.A] } # This is verified to be correct on tester.
-
1
meter_vrange = [4.V, 8.V]
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: -2.mV, pos: 2.mV }
-
1
filter = 10_000
-
1
bandwidth = [0, 1, 2, 3, 4, 5, 6, 7]
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
18
elsif @instrument == 'HexVS+x6' # Also known as HexVS+, Merged6
-
1
forcev = (0.V..5.5.V)
-
1
irange = [15.A, 90.A]
-
1
source_overload_i = { irange_15A: (1.05.A..16.5.A),
-
1
irange_90A: (6.3.A..99.A) }
-
1
source_overload_t = (102.4.uS..300.mS)
-
1
source_fold_i = { irange_15A: (50.mA..15.5.A),
-
1
irange_90A: (300.mA..93.A) }
-
1
source_fold_t = (102.4.uS..5.S)
-
1
sink_overload_i = { irange_15A: (2.A..3.A),
-
1
irange_90A: (12.A..18.A) }
-
1
sink_overload_t = (102.4.uS..300.mS)
-
1
sink_fold_i = { irange_15A: (1.A..2.A),
-
1
irange_90A: (6.A..12.A) }
-
1
sink_fold_t = (102.4.uS..5.S)
-
1
meter_irange = { irange_15A: [10.mA, 100.mA, 1.A, 15.A],
-
irange_90A: [90.A] } # This is verified to be correct on tester.
-
1
meter_vrange = [4.V, 8.V]
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: -2.mV, pos: 2.mV }
-
1
filter = 10_000
-
1
bandwidth = [0, 1, 2, 3, 4, 5, 6, 7]
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
17
elsif @instrument == 'HDVS1' # also known as HDVS
-
1
forcev = (0.V..7.V)
-
1
irange = 1.A
-
1
source_overload_i = 'n/a'
-
1
source_overload_t = 'n/a'
-
1
source_fold_i = (5.mA..1.A)
-
1
source_fold_t = (0.S..167.77.mS)
-
1
sink_overload_i = 'n/a'
-
1
sink_overload_t = 'n/a'
-
1
sink_fold_i = (5.mA..200.mA)
-
1
sink_fold_t = (0.S..167.77.mS)
-
1
meter_irange = [10.uA, 100.uA, 1.mA, 10.mA, 100.mA, 1.A]
-
1
meter_vrange = 7.V
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: '-0.001xSUPPLY-10.mV', pos: '0.001xSUPPLY+10.mV' }
-
1
filter = [1356, 2712, 5425, 10_850, 21_701, 43_402, 86_805, 173_611, 347_222,
-
694_444, 1_388_888, 2_777_777, 5_555_555]
-
1
bandwidth = [0, 1, 2, 3, 4, 10, 11, 12, 13, 14, 20, 21, 22, 23, 24,
-
100, 101, 102, 103, 104, 220, 221, 222, 223, 224, 470,
-
471, 472, 473, 474]
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
16
elsif @instrument == 'HDVS1x2' # also known as HDVS, Merged2
-
1
forcev = (0.V..7.V)
-
1
irange = 2.A
-
1
source_overload_i = 'n/a'
-
1
source_overload_t = 'n/a'
-
1
source_fold_i = (10.mA..2.A)
-
1
source_fold_t = (0.S..167.77.mS)
-
1
sink_overload_i = 'n/a'
-
1
sink_overload_t = 'n/a'
-
1
sink_fold_i = (10.mA..400.mA)
-
1
sink_fold_t = (0.S..167.77.mS)
-
1
meter_irange = [20.uA, 200.uA, 2.mA, 20.mA, 200.mA, 2.A]
-
1
meter_vrange = 7.V
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: '-0.001xSUPPLY-10.mV', pos: '0.001xSUPPLY+10.mV' }
-
1
filter = [1356, 2712, 5425, 10_850, 21_701, 43_402, 86_805, 173_611, 347_222,
-
694_444, 1_388_888, 2_777_777, 5_555_555]
-
1
bandwidth = [0, 1, 2, 3, 4, 10, 11, 12, 13, 14, 20, 21, 22, 23, 24,
-
100, 101, 102, 103, 104, 220, 221, 222, 223, 224, 470,
-
471, 472, 473, 474]
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
15
elsif @instrument == 'HDVS1x4' # also known as HDVS, Merged4
-
1
forcev = (0.V..7.V)
-
1
irange = [4.A]
-
1
source_overload_i = 'n/a'
-
1
source_overload_t = 'n/a'
-
1
source_fold_i = (20.mA..4.A)
-
1
source_fold_t = (0.S..167.77.mS)
-
1
sink_overload_i = 'n/a'
-
1
sink_overload_t = 'n/a'
-
1
sink_fold_i = (20.mA..800.mA)
-
1
sink_fold_t = (0.S..167.77.mS)
-
1
meter_irange = [40.uA, 400.uA, 4.mA, 40.mA, 400.mA, 4.A]
-
1
meter_vrange = 7.V
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: '-0.001xSUPPLY-10.mV', pos: '0.001xSUPPLY+10.mV' }
-
1
filter = [1356, 2712, 5425, 10_850, 21_701, 43_402, 86_805, 173_611, 347_222,
-
694_444, 1_388_888, 2_777_777, 5_555_555]
-
1
bandwidth = [0, 1, 2, 3, 4, 10, 11, 12, 13, 14, 20, 21, 22, 23, 24,
-
100, 101, 102, 103, 104, 220, 221, 222, 223, 224, 470,
-
471, 472, 473, 474]
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
14
elsif @instrument == 'VHDVS' # also known as UVS256
-
1
forcev = (-2.V..18.V)
-
1
irange = [4.uA, 20.uA, 200.uA, 2.mA, 20.mA, 200.mA]
-
1
source_overload_i = 'n/a'
-
1
source_overload_t = 'n/a'
-
1
source_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_200mA: (25.mA..200.mA) }
-
1
source_fold_t = (300.uS..2.S)
-
1
sink_overload_i = 'n/a'
-
1
sink_overload_t = 'n/a'
-
1
sink_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_200mA: (25.mA..75.mA) }
-
1
sink_fold_t = (300.uS..2.S)
-
1
meter_irange = { irange_4uA: 4.uA,
-
irange_20uA: 20.uA,
-
irange_200uA: 200.uA,
-
irange_2mA: 2.mA,
-
irange_20mA: 20.mA,
-
irange_200mA: 200.mA }
-
1
meter_vrange = 18.V
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: '-0.001xSUPPLY-10.mV', pos: '0.001xSUPPLY+10.mV' }
-
1
filter = [49, 98, 195, 391, 781, 1563, 3125, 6250, 12_500, 25_000, 50_000, 100_000, 200_000]
-
1
bandwidth = (0..255) # Integers
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
13
elsif @instrument == 'VHDVS_HC' # also known as UVS256, High-Current
-
1
forcev = (-2.V..18.V)
-
1
irange = [4.uA, 20.uA, 200.uA, 2.mA, 20.mA, 200.mA, 700.mA, 800.mA]
-
1
source_overload_i = 'n/a'
-
1
source_overload_t = 'n/a'
-
1
source_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_200mA: (25.mA..200.mA),
-
1
irange_700mA: (100.mA..700.mA),
-
1
irange_800mA: (100.mA..800.mA) }
-
1
source_fold_t = (300.uS..2.S)
-
1
sink_overload_i = 'n/a'
-
1
sink_overload_t = 'n/a'
-
1
sink_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_200mA: (25.mA..75.mA),
-
1
irange_700mA: (90.mA..110.mA), # This is verified on tester
-
1
irange_800mA: (90.mA..110.mA) } # This is verified on tester
-
1
sink_fold_t = (300.uS..2.S)
-
1
meter_irange = { irange_4uA: 4.uA,
-
irange_20uA: 20.uA,
-
irange_200uA: 200.uA,
-
irange_2mA: 2.mA,
-
irange_20mA: 20.mA,
-
irange_200mA: 200.mA,
-
irange_700mA: 700.mA,
-
irange_800mA: 800.mA }
-
1
meter_vrange = 18.V
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: '-0.001xSUPPLY-10.mV', pos: '0.001xSUPPLY+10.mV' }
-
1
filter = [49, 98, 195, 391, 781, 1563, 3125, 6250, 12_500, 25_000, 50_000, 100_000, 200_000]
-
1
bandwidth = (0..255) # Integers
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
12
elsif @instrument == 'VHDVSx2' # also known as UVS256, Merged2
-
1
forcev = (-2.V..18.V)
-
1
irange = [4.uA, 20.uA, 200.uA, 2.mA, 20.mA, 40.mA, 200.mA, 400.mA]
-
1
source_overload_i = 'n/a'
-
1
source_overload_t = 'n/a'
-
1
source_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_40mA: (5.mA..40.mA),
-
1
irange_200mA: (25.mA..200.mA),
-
1
irange_400mA: (50.mA..400.mA) }
-
1
source_fold_t = (300.uS..2.S)
-
1
sink_overload_i = 'n/a'
-
1
sink_overload_t = 'n/a'
-
1
sink_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_40mA: (5.mA..40.mA),
-
1
irange_200mA: (25.mA..75.mA),
-
1
irange_400mA: (50.mA..150.mA) }
-
1
sink_fold_t = (300.uS..2.S)
-
1
meter_irange = { irange_4uA: 4.uA,
-
irange_20uA: 20.uA,
-
irange_200uA: 200.uA,
-
irange_2mA: 2.mA,
-
irange_20mA: 20.mA,
-
irange_40mA: 40.mA,
-
irange_200mA: 200.mA,
-
irange_400mA: 400.mA }
-
1
meter_vrange = 18.V
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: '-0.001xSUPPLY-10.mV', pos: '0.001xSUPPLY+10.mV' }
-
1
filter = [49, 98, 195, 391, 781, 1563, 3125, 6250, 12_500, 25_000, 50_000, 100_000, 200_000]
-
1
bandwidth = (0..255) # Integers
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
11
elsif @instrument == 'VHDVS_HCx2' # also known as UVS256, High-Current, Merged2
-
1
forcev = (-2.V..18.V)
-
1
irange = [4.uA, 20.uA, 200.uA, 2.mA, 20.mA, 40.mA, 200.mA, 400.mA, 700.mA, 1.4.A]
-
1
source_overload_i = 'n/a'
-
1
source_overload_t = 'n/a'
-
1
source_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_40mA: (5.mA..40.mA),
-
1
irange_200mA: (25.mA..200.mA),
-
1
irange_400mA: (50.mA..400.mA),
-
1
irange_700mA: (100.mA..700.mA),
-
1
irange_1p4A: (200.mA..1.4.A) }
-
1
source_fold_t = (300.uS..2.S)
-
1
sink_overload_i = 'n/a'
-
1
sink_overload_t = 'n/a'
-
1
sink_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_40mA: (5.mA..40.mA),
-
1
irange_200mA: (25.mA..75.mA),
-
1
irange_400mA: (50.mA..150.mA),
-
1
irange_700mA: (90.mA..110.mA), # This is verified on tester
-
1
irange_1p4A: (190.mA..210.mA) } # This is verified on tester
-
1
sink_fold_t = (300.uS..2.S)
-
1
meter_irange = { irange_4uA: 4.uA,
-
irange_20uA: 20.uA,
-
irange_200uA: 200.uA,
-
irange_2mA: 2.mA,
-
irange_20mA: 20.mA,
-
irange_40mA: 40.mA,
-
irange_200mA: 200.mA,
-
irange_400mA: 400.mA,
-
irange_700mA: 700.mA,
-
irange_1p4A: 1.4.A }
-
1
meter_vrange = 18.V
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: '-0.001xSUPPLY-10.mV', pos: '0.001xSUPPLY+10.mV' }
-
1
filter = [49, 98, 195, 391, 781, 1563, 3125, 6250, 12_500, 25_000, 50_000, 100_000, 200_000]
-
1
bandwidth = (0..255) # Integers
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
10
elsif @instrument == 'VHDVS_HCx4' # also known as UVS256, High-Current, Merged4
-
1
forcev = (-2.V..18.V)
-
1
irange = [4.uA, 20.uA, 200.uA, 2.mA, 20.mA, 200.mA, 700.mA, 2.8.A]
-
1
source_overload_i = 'n/a'
-
1
source_overload_t = 'n/a'
-
1
source_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_200mA: (25.mA..200.mA),
-
1
irange_700mA: (100.mA..700.mA),
-
1
irange_2p8A: (400.mA..2.8.A) }
-
1
source_fold_t = (300.uS..2.S)
-
1
sink_overload_i = 'n/a'
-
1
sink_overload_t = 'n/a'
-
1
sink_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_200mA: (25.mA..75.mA),
-
1
irange_700mA: (90.mA..110.mA), # This is verified on tester
-
1
irange_2p8A: (390.mA..410.mA) } # This is verified on tester
-
1
sink_fold_t = (300.uS..2.S)
-
1
meter_irange = { irange_4uA: 4.uA,
-
irange_20uA: 20.uA,
-
irange_200uA: 200.uA,
-
irange_2mA: 2.mA,
-
irange_20mA: 20.mA,
-
irange_200mA: 200.mA,
-
irange_700mA: 700.mA,
-
irange_2p8A: 2.8.A }
-
1
meter_vrange = 18.V
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: '-0.001xSUPPLY-10.mV', pos: '0.001xSUPPLY+10.mV' }
-
1
filter = [49, 98, 195, 391, 781, 1563, 3125, 6250, 12_500, 25_000, 50_000, 100_000, 200_000]
-
1
bandwidth = (0..255) # Integers
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
9
elsif @instrument == 'VHDVS_HCx8' # also known as UVS256, High-Current, Merged8
-
1
forcev = (-2.V..18.V)
-
1
irange = [4.uA, 20.uA, 200.uA, 2.mA, 20.mA, 200.mA, 700.mA, 5.6.A]
-
1
source_overload_i = 'n/a'
-
1
source_overload_t = 'n/a'
-
1
source_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_200mA: (25.mA..200.mA),
-
1
irange_700mA: (100.mA..700.mA),
-
1
irange_5p6A: (800.mA..5.6.A) }
-
1
source_fold_t = (300.uS..2.S)
-
1
sink_overload_i = 'n/a'
-
1
sink_overload_t = 'n/a'
-
1
sink_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_200mA: (25.mA..75.mA),
-
1
irange_700mA: (90.mA..110.mA), # This is verified on tester
-
1
irange_5p6A: (790.mA..810.mA) } # This is verified on tester
-
1
sink_fold_t = (300.uS..2.S)
-
1
meter_irange = { irange_4uA: 4.uA,
-
irange_20uA: 20.uA,
-
irange_200uA: 200.uA,
-
irange_2mA: 2.mA,
-
irange_20mA: 20.mA,
-
irange_200mA: 200.mA,
-
irange_700mA: 700.mA,
-
irange_5p6A: 5.6.A }
-
1
meter_vrange = 18.V
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: '-0.001xSUPPLY-10.mV', pos: '0.001xSUPPLY+10.mV' }
-
1
filter = [49, 98, 195, 391, 781, 1563, 3125, 6250, 12_500, 25_000, 50_000, 100_000, 200_000]
-
1
bandwidth = (0..255) # Integers
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
8
elsif @instrument == 'VHDVS+' # also known as UVS256, High-Accuracy
-
1
forcev = (-2.V..18.V)
-
1
irange = [4.uA, 20.uA, 200.uA, 2.mA, 20.mA, 200.mA]
-
1
source_overload_i = 'n/a'
-
1
source_overload_t = 'n/a'
-
1
source_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_200mA: (25.mA..200.mA) }
-
1
source_fold_t = (300.uS..2.S)
-
1
sink_overload_i = 'n/a'
-
1
sink_overload_t = 'n/a'
-
1
sink_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_200mA: (25.mA..75.mA) }
-
1
sink_fold_t = (300.uS..2.S)
-
1
meter_irange = { irange_4uA: 4.uA,
-
irange_20uA: 20.uA,
-
irange_200uA: 200.uA,
-
irange_2mA: 2.mA,
-
irange_20mA: 20.mA,
-
irange_200mA: 200.mA }
-
1
meter_vrange = 18.V
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: '-0.001xSUPPLY-5.mV', pos: '0.001xSUPPLY+5.mV' }
-
1
filter = [49, 98, 195, 391, 781, 1563, 3125, 6250, 12_500, 25_000, 50_000, 100_000, 200_000]
-
1
bandwidth = (0..255) # Integers
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
7
elsif @instrument == 'VHDVS_HC+' # also known as UVS256, High-Current, High-Accuracy
-
1
forcev = (-2.V..18.V)
-
1
irange = [4.uA, 20.uA, 200.uA, 2.mA, 20.mA, 200.mA, 700.mA, 800.mA]
-
1
source_overload_i = 'n/a'
-
1
source_overload_t = 'n/a'
-
1
source_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_200mA: (25.mA..200.mA),
-
1
irange_700mA: (100.mA..700.mA),
-
1
irange_800mA: (100.mA..800.mA) }
-
1
source_fold_t = (300.uS..2.S)
-
1
sink_overload_i = 'n/a'
-
1
sink_overload_t = 'n/a'
-
1
sink_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_200mA: (25.mA..75.mA),
-
1
irange_700mA: (90.mA..110.mA), # This is verified on tester
-
1
irange_800mA: (90.mA..110.mA) } # This is verified on tester
-
1
sink_fold_t = (300.uS..2.S)
-
1
meter_irange = { irange_4uA: 4.uA,
-
irange_20uA: 20.uA,
-
irange_200uA: 200.uA,
-
irange_2mA: 2.mA,
-
irange_20mA: 20.mA,
-
irange_200mA: 200.mA,
-
irange_700mA: 700.mA,
-
irange_800mA: 800.mA }
-
1
meter_vrange = 18.V
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: '-0.001xSUPPLY-5.mV', pos: '0.001xSUPPLY+5.mV' }
-
1
filter = [49, 98, 195, 391, 781, 1563, 3125, 6250, 12_500, 25_000, 50_000, 100_000, 200_000]
-
1
bandwidth = (0..255) # Integers
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
6
elsif @instrument == 'VHDVS+x2' # also known as UVS256, High-Accuracy, Merged2
-
1
forcev = (-2.V..18.V)
-
1
irange = [4.uA, 20.uA, 200.uA, 2.mA, 20.mA, 40.mA, 200.mA, 400.mA]
-
1
source_overload_i = 'n/a'
-
1
source_overload_t = 'n/a'
-
1
source_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_40mA: (5.mA..40.mA),
-
1
irange_200mA: (25.mA..200.mA),
-
1
irange_400mA: (50.mA..400.mA) }
-
1
source_fold_t = (300.uS..2.S)
-
1
sink_overload_i = 'n/a'
-
1
sink_overload_t = 'n/a'
-
1
sink_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_40mA: (5.mA..40.mA),
-
1
irange_200mA: (25.mA..75.mA),
-
1
irange_400mA: (50.mA..150.mA) }
-
1
sink_fold_t = (300.uS..2.S)
-
1
meter_irange = { irange_4uA: 4.uA,
-
irange_20uA: 20.uA,
-
irange_200uA: 200.uA,
-
irange_2mA: 2.mA,
-
irange_20mA: 20.mA,
-
irange_40mA: 40.mA,
-
irange_200mA: 200.mA,
-
irange_400mA: 400.mA }
-
1
meter_vrange = 18.V
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: '-0.001xSUPPLY-5.mV', pos: '0.001xSUPPLY+5.mV' }
-
1
filter = [49, 98, 195, 391, 781, 1563, 3125, 6250, 12_500, 25_000, 50_000, 100_000, 200_000]
-
1
bandwidth = (0..255) # Integers
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
5
elsif @instrument == 'VHDVS_HC+x2' # also known as UVS256, High-Current, High-Accuracy, Merged2
-
3
forcev = (-2.V..18.V)
-
3
irange = [4.uA, 20.uA, 200.uA, 2.mA, 20.mA, 40.mA, 200.mA, 400.mA, 700.mA, 1.4.A]
-
3
source_overload_i = 'n/a'
-
3
source_overload_t = 'n/a'
-
3
source_fold_i = { irange_4uA: (500.nA..4.uA),
-
3
irange_20uA: (2.5.uA..20.uA),
-
3
irange_200uA: (25.uA..200.uA),
-
3
irange_2mA: (250.uA..2.mA),
-
3
irange_20mA: (2.5.mA..20.mA),
-
3
irange_40mA: (5.mA..40.mA),
-
3
irange_200mA: (25.mA..200.mA),
-
3
irange_400mA: (50.mA..400.mA),
-
3
irange_700mA: (100.mA..700.mA),
-
3
irange_1p4A: (200.mA..1.4.A) }
-
3
source_fold_t = (300.uS..2.S)
-
3
sink_overload_i = 'n/a'
-
3
sink_overload_t = 'n/a'
-
3
sink_fold_i = { irange_4uA: (500.nA..4.uA),
-
3
irange_20uA: (2.5.uA..20.uA),
-
3
irange_200uA: (25.uA..200.uA),
-
3
irange_2mA: (250.uA..2.mA),
-
3
irange_20mA: (2.5.mA..20.mA),
-
3
irange_40mA: (5.mA..40.mA),
-
3
irange_200mA: (25.mA..75.mA),
-
3
irange_400mA: (50.mA..150.mA),
-
3
irange_700mA: (90.mA..110.mA), # This is verified on tester
-
3
irange_1p4A: (190.mA..210.mA) } # This is verified on tester
-
3
sink_fold_t = (300.uS..2.S)
-
3
meter_irange = { irange_4uA: 4.uA,
-
irange_20uA: 20.uA,
-
irange_200uA: 200.uA,
-
irange_2mA: 2.mA,
-
irange_20mA: 20.mA,
-
irange_40mA: 40.mA,
-
irange_200mA: 200.mA,
-
irange_400mA: 400.mA,
-
irange_700mA: 700.mA,
-
irange_1p4A: 1.4.A }
-
3
meter_vrange = 18.V
-
3
tdelay = 0 # default tdelay
-
3
accuracy = { neg: '-0.001xSUPPLY-5.mV', pos: '0.001xSUPPLY+5.mV' }
-
3
filter = [49, 98, 195, 391, 781, 1563, 3125, 6250, 12_500, 25_000, 50_000, 100_000, 200_000]
-
3
bandwidth = (0..255) # Integers
-
3
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
2
elsif @instrument == 'VHDVS_HC+x4' # also known as UVS256, High-Current, High-Accuracy, Merged4
-
1
forcev = (-2.V..18.V)
-
1
irange = [4.uA, 20.uA, 200.uA, 2.mA, 20.mA, 200.mA, 700.mA, 2.8.A]
-
1
source_overload_i = 'n/a'
-
1
source_overload_t = 'n/a'
-
1
source_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_200mA: (25.mA..200.mA),
-
1
irange_700mA: (100.mA..700.mA),
-
1
irange_2p8A: (400.mA..2.8.A) }
-
1
source_fold_t = (300.uS..2.S)
-
1
sink_overload_i = 'n/a'
-
1
sink_overload_t = 'n/a'
-
1
sink_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_200mA: (25.mA..75.mA),
-
1
irange_700mA: (90.mA..110.mA), # This is verified on tester
-
1
irange_2p8A: (390.mA..410.mA) } # This is verified on tester
-
1
sink_fold_t = (300.uS..2.S)
-
1
meter_irange = { irange_4uA: 4.uA,
-
irange_20uA: 20.uA,
-
irange_200uA: 200.uA,
-
irange_2mA: 2.mA,
-
irange_20mA: 20.mA,
-
irange_200mA: 200.mA,
-
irange_700mA: 700.mA,
-
irange_2p8A: 2.8.A }
-
1
meter_vrange = 18.V
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: '-0.001xSUPPLY-5.mV', pos: '0.001xSUPPLY+5.mV' }
-
1
filter = [49, 98, 195, 391, 781, 1563, 3125, 6250, 12_500, 25_000, 50_000, 100_000, 200_000]
-
1
bandwidth = (0..255) # Integers
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
1
elsif @instrument == 'VHDVS_HC+x8' # also known as UVS256, High-Current, High-Accuracy, Merged8
-
1
forcev = (-2.V..18.V)
-
1
irange = [4.uA, 20.uA, 200.uA, 2.mA, 20.mA, 200.mA, 700.mA, 5.6.A]
-
1
source_overload_i = 'n/a'
-
1
source_overload_t = 'n/a'
-
1
source_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_200mA: (25.mA..200.mA),
-
1
irange_700mA: (100.mA..700.mA),
-
1
irange_5p6A: (800.mA..5.6.A) }
-
1
source_fold_t = (300.uS..2.S)
-
1
sink_overload_i = 'n/a'
-
1
sink_overload_t = 'n/a'
-
1
sink_fold_i = { irange_4uA: (500.nA..4.uA),
-
1
irange_20uA: (2.5.uA..20.uA),
-
1
irange_200uA: (25.uA..200.uA),
-
1
irange_2mA: (250.uA..2.mA),
-
1
irange_20mA: (2.5.mA..20.mA),
-
1
irange_200mA: (25.mA..75.mA),
-
1
irange_700mA: (90.mA..110.mA), # This is verified on tester
-
1
irange_5p6A: (790.mA..810.mA) } # This is verified on tester
-
1
sink_fold_t = (300.uS..2.S)
-
1
meter_irange = { irange_4uA: 4.uA,
-
irange_20uA: 20.uA,
-
irange_200uA: 200.uA,
-
irange_2mA: 2.mA,
-
irange_20mA: 20.mA,
-
irange_200mA: 200.mA,
-
irange_700mA: 700.mA,
-
irange_5p6A: 5.6.A }
-
1
meter_vrange = 18.V
-
1
tdelay = 0 # default tdelay
-
1
accuracy = { neg: '-0.001xSUPPLY-5.mV', pos: '0.001xSUPPLY+5.mV' }
-
1
filter = [49, 98, 195, 391, 781, 1563, 3125, 6250, 12_500, 25_000, 50_000, 100_000, 200_000]
-
1
bandwidth = (0..255) # Integers
-
1
supply.new(forcev, irange, source_overload_i, source_overload_t, source_fold_i,
-
source_fold_t, sink_overload_i, sink_overload_t, sink_fold_i,
-
sink_fold_t, meter_irange, meter_vrange, tdelay, accuracy, filter, bandwidth)
-
else
-
puts "please enter an instrument type: e.g. $tester.ate_hardware(\"VSM\").supply"
-
puts "Instrument type available: \"VSM\", \"VSMx2\", \"VSMx4\","
-
puts "\"HexVS\", \"HexVSx2\", \"HexVSx4\", \"HexVSx6\","
-
puts "\"HexVS+\", \"HexVS+x2\", \"HexVS+x4\", \"HexVS+x6\", \"HDVS1\","
-
puts "\"HDVS1x2\", \"HDVS1x4\", \"VHDVS\", \"VHDVS_HC\", \"VHDVSx2\","
-
puts "\"VHDVS_HCx2\", \"VHDVS_HCx4\", and \"VHDVS_HCx8\"."
-
puts "\"VHDVS+\", \"VHDVS_HC+\", \"VHDVS+x2\","
-
puts "\"VHDVS_HC+x2\", \"VHDVS_HC+x4\", and \"VHDVS_HC+x8\"."
-
puts 'HDVS1 is also known as HDVS. VHDVS is also known as UVS256.'
-
puts 'x2 is Merged2, x4 is Merged4, x6 is Merged6. _HC is High-Current.'
-
puts '+ is High-Accuracy.'
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/custom_test_instance'
-
2
class CustomTestInstance < Base::CustomTestInstance
-
# Give all UltraFLEX test instances the ability to contain limits, these will
-
# be rendered to Use-limit lines in the flow
-
2
attr_accessor :lo_limit, :hi_limit, :scale, :units, :defer_limits, :lo, :hi
-
-
# Attributes for each test instance line, first few are named directly
-
TEST_INSTANCE_ATTRS = %w(
-
2
test_name proc_type proc_name proc_called_as dc_category
-
dc_selector ac_category ac_selector
-
time_sets edge_sets pin_levels mixedsignal_timing overlay
-
)
-
-
# Attributes for additional test instance arguments beyond those described above
-
2
TEST_INSTANCE_EXTRA_ARGS = 130
-
-
TEST_INSTANCE_DEFAULTS = {
-
2
proc_type: 'Other',
-
proc_called_as: 'VB DLL'
-
}
-
-
TEST_INSTANCE_ALIASES = {
-
2
name: :test_name,
-
time_set: :time_sets,
-
timeset: :time_sets,
-
timesets: :time_sets
-
}
-
-
2
define
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/dc_specsets'
-
2
class DCSpecsets < Base::DCSpecsets
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/ultraflex/templates/dc_specsets.txt.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/edge'
-
2
class Edge < Base::Edge
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/edges'
-
2
class Edges < Base::Edges
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/edgeset'
-
2
class Edgeset < Base::Edgeset
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/edgesets'
-
2
class Edgesets < Base::Edgesets
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/ultraflex/templates/edgesets.txt.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/flow'
-
2
class Flow < Base::Flow
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/ultraflex/templates/flow.txt.erb"
-
-
2
SCALES = [:p, :n, :u, :m, :none, :k, :M]
-
-
2
def on_test(node)
-
370
super
-
370
ins = node.find(:object).value
-
-
# allow defer limits when limits are only given in sub tests
-
370
if ins.respond_to?(:defer_limits)
-
315
if ins.defer_limits
-
4
completed_lines.last.opcode = 'Test-defer-limits'
-
end
-
end
-
-
370
if ins.respond_to?(:lo_limit) && (ins.lo_limit || ins.hi_limit) || ins.respond_to?(:lo) && (ins.lo || ins.hi)
-
22
limit = completed_lines.last.dup
-
22
limit.type = :use_limit
-
22
limit.opcode = 'Use-Limit'
-
22
limit.parameter = nil
-
22
limit.tnum = nil # Don't duplate test numbers, allow auto-increment by leaving blank
-
22
if ins.respond_to?(:lo_limit)
-
22
lo = ins.lo_limit
-
22
hi = ins.hi_limit
-
22
if lo.nil?
-
6
lo = ins.lo
-
end
-
22
if hi.nil?
-
2
hi = ins.hi
-
end
-
elsif ins.respond_to?(:lo)
-
lo = ins.lo
-
hi = ins.hi
-
end
-
-
22
size = 1
-
22
if lo.is_a?(Array)
-
2
size = lo.size if lo.size > size
-
end
-
22
if hi.is_a?(Array)
-
4
size = hi.size if hi.size > size
-
end
-
-
22
size.times do |i|
-
28
line = limit.dup
-
-
28
if lo.is_a?(Array)
-
6
l = lo[i]
-
else
-
22
l = lo
-
end
-
-
28
if hi.is_a?(Array)
-
10
h = hi[i]
-
else
-
18
h = hi
-
end
-
-
28
if ins.scale
-
if ins.scale.is_a?(Array)
-
s = ins.scale[i]
-
else
-
s = ins.scale
-
end
-
else
-
28
unless $tester.ultraflex?
-
s = lowest_scale(scale_of(l), scale_of(h))
-
l = scaled(l, s)
-
h = scaled(h, s)
-
end
-
end
-
28
line.lolim = l
-
28
line.hilim = h
-
28
line.scale = s unless s == :none
-
28
if ins.units
-
6
if ins.units.is_a?(Array)
-
line.units = ins.units[i]
-
else
-
6
line.units = ins.units
-
end
-
end
-
28
completed_lines << line
-
end
-
end
-
# finish off any limit lines from sub tests
-
370
unless @limit_lines.nil?
-
5
tl = completed_lines.last
-
5
tnum = tl.tnum
-
5
@limit_lines.each do |line|
-
10
line.parameter = tl.parameter
-
10
line.sbin = tl.sbin
-
10
line.bin = tl.bin
-
10
line.tnum = tnum += 1 if tnum.is_a?(Numeric) && !line.tnum
-
10
completed_lines << line
-
end
-
5
@limit_lines = nil
-
end
-
end
-
-
2
def on_sub_test(node)
-
# for now assuming sub tests will be limits
-
10
tname = node.find(:object).value
-
# for some reason new_line :use_limit does not provide hbin, sbin etc accessors, duplicating behavior in on_test above
-
10
line = open_lines.last.dup
-
10
line.type = :use_limit
-
10
line.opcode = 'Use-Limit'
-
10
line.tname = tname
-
10
line.tnum = nil
-
10
open_lines << line
-
10
process_all(node.children)
-
10
@limit_lines = [] if @limit_lines.nil?
-
10
@limit_lines << open_lines.pop
-
end
-
-
2
def on_limit(node)
-
20
value, rule, unit, selector = *node
-
20
case rule
-
when 'gte'
-
10
current_line.lolim = value
-
when 'lte'
-
10
current_line.hilim = value
-
end
-
end
-
-
# Returns the scale that should be best used to represent the given number, returns
-
# nil in the case where the given number is nil
-
2
def scale_of(number)
-
if number && number.is_a?(Numeric)
-
number = number.abs
-
if number >= 1_000_000
-
:M
-
elsif number >= 1_000
-
:k
-
elsif number >= 0.1
-
:none
-
elsif number >= 0.000_1
-
:m
-
elsif number >= 0.000_000_1
-
:u
-
elsif number >= 0.000_000_000_1
-
:n
-
else
-
:p
-
end
-
end
-
end
-
-
# Returns the lowest of the two scales
-
2
def lowest_scale(a, b)
-
if a == b
-
a
-
elsif !a
-
b
-
elsif !b
-
a
-
else
-
if SCALES.index(a) < SCALES.index(b)
-
a
-
else
-
b
-
end
-
end
-
end
-
-
2
def scaled(number, scale)
-
if number
-
if number.is_a?(Numeric)
-
number = number.to_f
-
if scale
-
case scale
-
when :M
-
number = number / 1_000_000
-
when :k
-
number = number / 1_000
-
when :m
-
number = number * 1_000
-
when :u
-
number = number * 1_000_000
-
when :n
-
number = number * 1_000_000_000
-
when :p
-
number = number * 1_000_000_000_000
-
end
-
end
-
if number.round(2) == number.to_i.to_f.round(2)
-
number.to_i
-
else
-
number.round(2)
-
end
-
else
-
number
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/flow_line'
-
2
class FlowLine < Base::FlowLine
-
# Attributes for each flow line, these must be declared in the order they are to be output
-
2
TESTER_FLOWLINE_ATTRS = %w(label enable job part env opcode parameter tname tnum lolim hilim scale units format
-
bin_pass bin_fail sort_pass sort_fail result flag_pass flag_fail state
-
group_specifier group_sense group_condition group_name
-
device_sense device_condition device_name
-
debug_assume debug_sites comment
-
)
-
-
# Generate the instance method definitions based on the above
-
2
define
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
# Include this module in an interface class to make it an UltraFLEX interface and to give
-
# access to the UltraFLEX program generator API
-
2
module Generator
-
2
extend ActiveSupport::Concern
-
-
2
require_all "#{Origen.root!}/lib/origen_testers/igxl_based_tester/ultraflex"
-
2
require 'origen_testers/igxl_based_tester/base/generator'
-
-
2
included do
-
85
include Base::Generator
-
85
PLATFORM = UltraFLEX
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/global_specs'
-
2
class GlobalSpecs < Base::GlobalSpecs
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/ultraflex/templates/global_specs.txt.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/job'
-
2
class Job < Base::Job
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/jobs'
-
2
class Jobs < Base::Jobs
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/ultraflex/templates/jobs.txt.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/level_io_se'
-
2
class PinLevelSingle < Base::PinLevelSingle
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/level_supply'
-
2
class SupplyLevel < Base::SupplyLevel
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/levels'
-
2
class Levels < Base::Levels
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/levelset'
-
2
class Levelset < Base::Levelset
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/ultraflex/templates/levelset.txt.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/patgroup'
-
2
class Patgroup < Base::Patgroup
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/patgroups'
-
2
class Patgroups < Base::Patgroups
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/ultraflex/templates/patgroups.txt.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/patset'
-
2
class Patset < Base::Patset
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/patset_pattern'
-
2
class PatsetPattern < Base::PatsetPattern
-
# Attributes for each pattern set line
-
2
PATSET_ATTRS = %w(pattern_set td_group time_domain file_name burst start_label stop_label comment)
-
-
PATSET_DEFAULTS = {
-
2
burst: 'Yes'
-
}
-
-
# Generate the instance method definitions based on the above
-
2
define
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/patsets'
-
2
class Patsets < Base::Patsets
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/ultraflex/templates/patsets.txt.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/patsubr'
-
2
class Patsubr < Base::Patsubr
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/patsubr_pattern'
-
2
class PatsubrPattern < Base::PatsubrPattern
-
# Attributes for each pattern subroutine line
-
2
PATSUBR_ATTRS = %w(file_name comment)
-
-
# Pattern subroutine defaults
-
2
PATSUBR_DEFAULTS = {
-
}
-
-
# Generate the instance method definitions based on the above
-
2
define
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/patsubrs'
-
2
class Patsubrs < Base::Patsubrs
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/ultraflex/templates/patsubrs.txt.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/pinmap'
-
2
class Pinmap < Base::Pinmap
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/ultraflex/templates/pinmap.txt.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/references'
-
2
class References < Base::References
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/ultraflex/templates/references.txt.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/test_instance'
-
2
class TestInstance < Base::TestInstance
-
# Attributes for each test instance line, first few are named directly
-
TEST_INSTANCE_ATTRS = %w(
-
2
test_name proc_type proc_name proc_called_as dc_category
-
dc_selector ac_category ac_selector
-
time_sets edge_sets pin_levels mixedsignal_timing overlay
-
)
-
-
# Give all UltraFLEX test instances the ability to contain limits, these will
-
# be rendered to Use-limit lines in the flow
-
2
attr_accessor :lo_limit, :hi_limit, :scale, :units, :defer_limits, :lo, :hi
-
-
# Attributes for additional test instance arguments beyond those described above
-
2
TEST_INSTANCE_EXTRA_ARGS = 130
-
-
TEST_INSTANCE_ALIASES = {
-
2
name: :test_name,
-
time_set: :time_sets,
-
timeset: :time_sets,
-
timesets: :time_sets,
-
-
other: {
-
},
-
-
empty: {
-
arg_list: :arg0,
-
start_func: :arg1,
-
start_of_body_f: :arg1,
-
pre_pat_func: :arg2,
-
pre_pat_f: :arg2,
-
pre_test_func: :arg3,
-
pre_test_f: :arg3,
-
post_test_func: :arg4,
-
post_test_f: :arg4,
-
post_pat_func: :arg5,
-
post_pat_f: :arg5,
-
end_func: :arg6,
-
end_of_body_f: :arg6,
-
start_func_args: :arg7,
-
start_of_body_f_args: :arg7,
-
pre_pat_func_args: :arg8,
-
pre_pat_f_args: :arg8,
-
pre_test_func_args: :arg9,
-
pre_test_f_args: :arg9,
-
post_test_func_args: :arg10,
-
post_test_f_args: :arg10,
-
post_pat_func_args: :arg11,
-
post_pat_f_args: :arg11,
-
end_func_args: :arg12,
-
end_of_body_f_args: :arg12,
-
utility_pins_1: :arg13,
-
utility_pins_0: :arg14,
-
init_lo: :arg15,
-
start_lo: :arg15,
-
init_hi: :arg16,
-
start_hi: :arg16,
-
init_hiz: :arg17,
-
start_hiz: :arg17,
-
float_pins: :arg18,
-
disable_pins: :arg19
-
},
-
-
# Functional test instances
-
functional: {
-
arg_list: :arg0,
-
pattern: :arg1,
-
patterns: :arg1,
-
start_func: :arg2,
-
start_of_body_f: :arg2,
-
pre_pat_func: :arg3,
-
pre_pat_f: :arg3,
-
pre_test_func: :arg4,
-
pre_test_f: :arg4,
-
post_test_func: :arg5,
-
post_test_f: :arg5,
-
post_pat_func: :arg6,
-
post_pat_f: :arg6,
-
end_func: :arg7,
-
end_of_body_f: :arg7,
-
set_pass_fail: :arg8,
-
report_result: :arg8,
-
result_mode: :arg9,
-
init_lo: :arg10,
-
start_lo: :arg10,
-
init_hi: :arg11,
-
start_hi: :arg11,
-
init_hiz: :arg12,
-
start_hiz: :arg12,
-
disable_pins: :arg13,
-
float_pins: :arg14,
-
start_func_args: :arg15,
-
start_of_body_f_args: :arg15,
-
pre_pat_func_args: :arg16,
-
pre_pat_f_args: :arg16,
-
pre_test_func_args: :arg17,
-
pre_test_f_args: :arg17,
-
post_test_func_args: :arg18,
-
post_test_f_args: :arg18,
-
post_pat_func_args: :arg19,
-
post_pat_f_args: :arg19,
-
end_func_args: :arg20,
-
end_of_body_f_args: :arg20,
-
utility_pins_1: :arg21,
-
utility_pins_0: :arg22,
-
pat_flag_func: :arg23,
-
pat_flag_f: :arg23,
-
PatFlagF: :arg23,
-
pat_flag_func_args: :arg24,
-
pat_flag_f_args: :arg24,
-
relay_mode: :arg25,
-
threading: :arg26,
-
match_all_sites: :arg27,
-
wait_flag1: :arg28,
-
wait_flag2: :arg29,
-
wait_flag3: :arg30,
-
wait_flag4: :arg31,
-
validating: :arg32,
-
wait_time: :arg33,
-
pattern_timeout: :arg33,
-
wait_time_domain: :arg34,
-
concurrent_mode: :arg35
-
},
-
-
pin_pmu: {
-
arg_list: :arg0,
-
hsp_start: :arg1,
-
start_func: :arg2,
-
start_of_body_f: :arg2,
-
pre_pat_func: :arg3,
-
pre_pat_f: :arg3,
-
pre_test_func: :arg4,
-
pre_test_f: :arg4,
-
post_test_func: :arg5,
-
post_test_f: :arg5,
-
post_pat_func: :arg6,
-
post_pat_f: :arg6,
-
end_func: :arg7,
-
end_of_body_f: :arg7,
-
precond_pat: :arg8,
-
hold_state_pat: :arg9,
-
holdstate_pat: :arg9,
-
pattern: :arg9,
-
pcp_stop: :arg10,
-
start_lo: :arg11,
-
init_lo: :arg11,
-
start_hi: :arg12,
-
init_hi: :arg12,
-
start_hiz: :arg13,
-
init_hiz: :arg13,
-
disable_pins: :arg14,
-
float_pins: :arg15,
-
pinlist: :arg16,
-
pin: :arg16,
-
pin_list: :arg16,
-
measure_mode: :arg17,
-
settling_time: :arg18,
-
force_cond_1: :arg19,
-
force_cond: :arg19,
-
force_condition: :arg19,
-
force_cond_2: :arg20,
-
relay_mode: :arg21,
-
start_func_args: :arg22,
-
start_of_body_f_args: :arg22,
-
pre_pat_func_args: :arg23,
-
pre_pat_f_args: :arg23,
-
pre_test_func_args: :arg24,
-
pre_test_f_args: :arg24,
-
post_test_func_args: :arg25,
-
post_test_f_args: :arg25,
-
post_pat_func_args: :arg26,
-
post_pat_f_args: :arg26,
-
end_func_args: :arg27,
-
end_of_body_f_args: :arg27,
-
pcp_start: :arg28,
-
pcp_check_pg: :arg29,
-
hsp_stop: :arg30,
-
hsp_check_pg: :arg31,
-
sampling_time: :arg32,
-
samples: :arg33,
-
resume_pat: :arg34,
-
vcl: :arg35,
-
vch: :arg36,
-
utility_pins_1: :arg37,
-
utility_pins_0: :arg38,
-
wait_flag1: :arg39,
-
wait_flag2: :arg40,
-
wait_flag3: :arg41,
-
wait_flag4: :arg42,
-
validating: :arg43,
-
force_irange: :arg44,
-
meas_irange: :arg45,
-
wait_time_out: :arg46,
-
pcp_disable_alarm_check: :arg47,
-
hsp_disable_alarm_check: :arg48,
-
testing_in_series: :arg49,
-
background_meas_mode: :arg50,
-
background_force_irange: :arg51,
-
background_meas_irange: :arg52,
-
background_force_cond: :arg53,
-
pins_alt: :arg54,
-
measure_mode_alt: :arg55,
-
force_cond_alt: :arg56,
-
force_irange_alt: :arg57,
-
meas_irange_alt: :arg58
-
},
-
-
dcvi_powersupply: {
-
arg_list: :arg0,
-
precond_pat: :arg1,
-
start_func: :arg2,
-
pre_pat_func: :arg3,
-
pre_test_func: :arg4,
-
post_test_func: :arg5,
-
post_pat_func: :arg6,
-
end_of_body_f: :arg7,
-
hold_state_pat: :arg8,
-
pattern: :arg8,
-
drive_lo_pins: :arg9,
-
drive_hi_pins: :arg10,
-
drive_z_pins: :arg11,
-
float_pins: :arg12,
-
sampling_time: :arg13,
-
sample: :arg14,
-
sample_size: :arg14,
-
settling_time: :arg15,
-
main_voltage: :arg16,
-
alt_voltage: :arg17,
-
power_pins: :arg18,
-
disable_pins: :arg19,
-
voltage_output: :arg20,
-
pcp_start_label: :arg21,
-
pcp_start: :arg21,
-
pcp_stop_label: :arg22,
-
pcp_stop: :arg22,
-
start_func_args: :arg23,
-
start_of_body_f_args: :arg23,
-
pre_pat_func_args: :arg24,
-
pre_pat_f_args: :arg24,
-
pre_test_func_args: :arg25,
-
pre_test_f_args: :arg25,
-
post_test_func_args: :arg26,
-
post_test_f_args: :arg26,
-
post_pat_func_args: :arg27,
-
post_pat_f_args: :arg27,
-
end_func_args: :arg28,
-
end_of_body_f_args: :arg28,
-
hsp_start_label: :arg29,
-
hsp_start: :arg29,
-
hsp_stop_label: :arg30,
-
hsp_stop: :arg30,
-
pcp_check_patGen: :arg31,
-
current_clamp: :arg32,
-
hsp_checkpat_gen: :arg33,
-
hsp_resume_pat: :arg34,
-
relay_mode: :arg35,
-
utility_pins_1: :arg36,
-
utility_pins_0: :arg37,
-
test_control: :arg38,
-
serialize_meas: :arg39,
-
meas_f: :arg40,
-
meas_f_args: :arg41,
-
wait_flag1: :arg42,
-
wait_flag2: :arg43,
-
wait_flag3: :arg44,
-
wait_flag4: :arg45,
-
validating: :arg46,
-
i_range: :arg47,
-
pattern_timeout: :arg48,
-
pcp_disable_alarm: :arg49,
-
hcp_disable_alarm: :arg50
-
}
-
-
}
-
-
TEST_INSTANCE_DEFAULTS = {
-
2
empty: {
-
arg_list: 'StartOfBodyF,PrePatF,PreTestF,PostTestF,PostPatF,EndOfBodyF,StartOfBodyFArgs,PrePatFArgs,PreTestFArgs,PostTestFArgs,PostPatFArgs,EndOfBodyFArgs,Util1Pins,Util0Pins,DriveLoPins,DriveHiPins,DriveZPins,FloatPins,DisablePins',
-
proc_type: 'VBT',
-
proc_name: 'Empty_T',
-
proc_called_as: 'Excel Macro'
-
},
-
other: {
-
proc_type: 'Other',
-
proc_called_as: 'Excel Macro'
-
},
-
functional: {
-
arg_list: 'Patterns,StartOfBodyF,PrePatF,PreTestF,PostTestF,PostPatF,EndOfBodyF,ReportResult,ResultMode,DriveLoPins,DriveHiPins,DriveZPins,DisablePins,FloatPins,StartOfBodyFArgs,PrePatFArgs,PreTestFArgs,PostTestFArgs,PostPatFArgs,EndOfBodyFArgs,Util1Pins,Util0Pins,PatFlagF,PatFlagFArgs,RelayMode,PatThreading,MatchAllSites,WaitFlagA,WaitFlagB,WaitFlagC,WaitFlagD,Validating_,PatternTimeout,WaitTimeDomain,ConcurrentMode',
-
proc_type: 'VBT',
-
proc_name: 'Functional_T',
-
proc_called_as: 'Excel Macro',
-
set_pass_fail: 1,
-
relay_mode: 1,
-
threading: 0,
-
match_all_sites: 0,
-
wait_flag1: -2, # waitoff
-
wait_flag2: -2, # waitoff
-
wait_flag3: -2, # waitoff
-
wait_flag4: -2, # waitoff
-
wait_time: 30
-
},
-
pin_pmu: {
-
arg_list: 'HspStartLabel,StartOfBodyF,PrePatF,PreTestF,PostTestF,PostPatF,EndOfBodyF,PreconditionPat,HoldStatePat,PcpStopLabel,DriveLoPins,DriveHiPins,DriveZPins,DisablePins,FloatPins,Pins,MeasureMode,SettlingTime,ForceCond1,ForceCond2,RelayMode,StartOfBodyFArgs,PrePatFArgs,PreTestFArgs,PostTestFArgs,PostPatFArgs,EndOfBodyFArgs,PcpStartLabel,PcpCheckPatGen,HspStopLabel,HspCheckPatGen,SamplingTime,SampleCount,HspResumePat,VClampLo,VClampHi,Util1Pins,Util0Pins,WaitFlagA,WaitFlagB,WaitFlagC,WaitFlagD,Validating_,ForceIRange,MeasIRange,PatternTimeout,PcpDisableAlarmCheck,HspDisableAlarmCheck,TestingInSeries,BackgroundMeasureMode,BackgroundForceIRange,BackgroundMeasIRange,BackgroundForceCond,PinsAlt,MeasureModeAlt,ForceCondAlt,ForceIRangeAlt,MeasIRangeAlt',
-
proc_type: 'VBT',
-
proc_name: 'PinPmu_T',
-
proc_called_as: 'Excel Macro',
-
wait_flag1: -2, # waitoff
-
wait_flag2: -2, # waitoff
-
wait_flag3: -2, # waitoff
-
wait_flag4: -2, # waitoff
-
},
-
dcvi_powersupply: {
-
arg_list: 'PreconditionPat,StartOfBodyF,PrePatF,PreTestF,PostTestF,PostPatF,EndOfBodyF,HoldStatePat,DriveLoPins,DriveHiPins,DriveZPins,FloatPins,SamplingTime,SampleSize,SettlingTime,MainVoltage,AltVoltage,PowerPins,DisablePins,VoltageOutput,PcpStartLabel,PcpStopLabel,StartOfBodyFArgs,PrePatFArgs,PreTestFArgs,PostTestFArgs,PostPatFArgs,EndOfBodyFArgs,HspStartLabel,HspStopLabel,PcpCheckPatGen,CurrentClamp,HspCheckPatGen,HspResumePat,RelayMode,Util1Pins,Util0Pins,TestControl,SerializeMeas,MeasF,MeasFArgs,WaitFlagA,WaitFlagB,WaitFlagC,WaitFlagD,Validating_,Irange,PatternTimeout,PcpDisableAlarm,HspDisableAlarm',
-
proc_type: 'VBT',
-
proc_name: 'DCVIPowerSupply_T',
-
proc_called_as: 'Excel Macro',
-
wait_flag1: -2, # waitoff
-
wait_flag2: -2, # waitoff
-
wait_flag3: -2, # waitoff
-
wait_flag4: -2, # waitoff
-
}
-
-
}
-
-
# Generate the instance method definitions based on the above
-
2
define
-
-
# Set the cpu wait flags for the given test instance
-
# instance.set_wait_flags(:a)
-
# instance.set_wait_flags(:a, :c)
-
# assumes set flag means to set it high (waithi = -1 )
-
# assumes clr flag means to set it off (waitoff = -2)
-
# does not yet support waitlo = 0
-
2
def set_wait_flags(*flags)
-
14
a = (flags.include?(:a) || flags.include?(:a)) ? '-1' : '-2'
-
14
b = (flags.include?(:b) || flags.include?(:b)) ? '-1' : '-2'
-
14
c = (flags.include?(:c) || flags.include?(:c)) ? '-1' : '-2'
-
14
d = (flags.include?(:d) || flags.include?(:d)) ? '-1' : '-2'
-
14
self.wait_flag1 = a
-
14
self.wait_flag2 = b
-
14
self.wait_flag3 = c
-
14
self.wait_flag4 = d
-
14
self
-
end
-
-
# Set and enable the pre-charge voltage of a parametric test instance.
-
2
def set_pre_charge(val)
-
self
-
end
-
2
alias_method :set_precharge, :set_pre_charge
-
-
# Returns a hash containing key meta data about the test instance, this is
-
# intended to be used in documentation
-
2
def to_meta
-
960
return @meta if @meta
-
960
m = { 'Test' => name,
-
'Type' => type
-
}
-
960
if type == :functional
-
957
m['Pattern'] = pattern
-
3
elsif type == :board_pmu || type == :pin_pmu
-
m['Measure'] = fvmi? ? 'current' : 'voltage'
-
m['Hi'] = hi_limit
-
m['Lo'] = lo_limit
-
if force_cond
-
m['Force'] = force_cond
-
end
-
end
-
960
m['DC'] = "#{dc_category} (#{dc_selector})"
-
960
m['AC'] = "#{ac_category} (#{ac_selector})"
-
960
m
-
end
-
-
# Set the meaure mode of a parametric test instance, either:
-
# * :voltage / :fimv
-
# * :current / :fvmi
-
2
def set_measure_mode(mode)
-
if mode == :current || mode == :fvmi
-
self.measure_mode = 2
-
elsif mode == :voltage || mode == :fimv
-
self.measure_mode = 1
-
else
-
fail "Unknown measure mode: #{mode}"
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/test_instance_group'
-
2
class TestInstanceGroup < Base::TestInstanceGroup
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/test_instances'
-
2
class TestInstances < Base::TestInstances
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/ultraflex/templates/instances.txt.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/timeset'
-
2
class Timeset < Base::Timeset
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/timesets'
-
2
class Timesets < Base::Timesets
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/ultraflex/templates/timesets.txt.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module IGXLBasedTester
-
2
class UltraFLEX
-
2
require 'origen_testers/igxl_based_tester/base/timesets_basic'
-
2
class TimesetsBasic < Base::TimesetsBasic
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/igxl_based_tester/ultraflex/templates/timesets_basic.txt.erb"
-
end
-
end
-
end
-
end
-
2
require 'active_support/concern'
-
-
2
module OrigenTesters
-
# Include this module in any class you define as a test interface
-
2
module Interface
-
2
extend ActiveSupport::Concern
-
2
include ATP::FlowAPI
-
-
2
included do
-
12
Origen.add_interface(self)
-
end
-
-
2
class PatternArray < ::Array
-
2
def <<(pat)
-
1932
push(pat)
-
end
-
-
# Override the array push method to capture the pattern under the new API, but
-
# maintain the old one where a pattern reference was just pushed to the
-
# referenced_patterns array
-
2
def push(pat)
-
1932
Origen.interface.record_pattern_reference(pat)
-
end
-
end
-
-
2
def self.with_resources_mode
-
38
orig = @resources_mode
-
38
@resources_mode = true
-
38
yield
-
38
@resources_mode = orig
-
end
-
-
2
def self.resources_mode?
-
4995
!!@resources_mode
-
end
-
-
2
def self.write=(val)
-
13
@write = val
-
end
-
-
2
def self.write?
-
207
!!@write
-
end
-
-
2
def test(name, options = {})
-
348
flow.test(name, options)
-
end
-
-
2
def generating_sub_program?
-
84
(defined? @@generating_sub_program) ? @@generating_sub_program : false
-
end
-
-
# Returns the abstract test program model for the current flow
-
2
def atp
-
745
flow.model
-
end
-
-
2
def write?
-
207
OrigenTesters::Interface.write?
-
end
-
-
# Returns true if the test flow context (as supplied in the given options)
-
# has changed vs. that applied to the previous test.
-
# Flow context means enabled words, job, if_failed/passed, etc.
-
2
def context_changed?(options = {})
-
10
flow.context_changed?(options)
-
end
-
-
# Returns true if the value of the given parameter within the given options is
-
# different vs. the last test
-
# if parameter_changed?(:vdd, :vddc, options)
-
# # execute code if the vdd level has changed
-
# end
-
2
def parameter_changed?(*params)
-
8
options = params.last.is_a?(Hash) ? params.pop : {}
-
8
last = flow.instance_variable_get(:@_last_parameters_)
-
8
if last
-
14
params.any? { |p| options[p] != last[p] }
-
else
-
1
false
-
end
-
end
-
-
# Convenience method, equivalent of calling (context_changed? || parameter_changed?)
-
2
def context_or_parameter_changed?(*params)
-
4
options = params.last.is_a?(Hash) ? params.pop : {}
-
4
context_changed?(options) || parameter_changed?(*params, options)
-
end
-
-
# Returns the value defined on if/how to make test names unique within a flow
-
2
def unique_test_names
-
4805
@unique_test_names
-
end
-
-
# Set the value of unique_test_names
-
2
def unique_test_names=(val)
-
116
@unique_test_names = val
-
end
-
-
# Returns whether the tester has been configured to wrap top-level flow modules with an
-
# enable or not.
-
#
-
# Returns nil if not.
-
#
-
# Returns :enabled if the enable is configured to be on by default, or :disabled if it is
-
# configured to be off by default.
-
2
def add_flow_enable
-
@add_flow_enable
-
end
-
-
# Set to :enabled to have the current flow wrapped by an enable flow variable
-
# that is enabled by default (top-level flow has to disable modules it doesn't want).
-
#
-
# Set to :disabled to have the opposite, where the top-level flow has to enable all
-
# modules.
-
#
-
# Set to nil to have no wrapping. While this is the default, setting this to nil will
-
# override any setting of the attribute of the same name that has been set at
-
# tester-level by the target.
-
2
def add_flow_enable=(value)
-
9
return unless flow.respond_to?(:add_flow_enable=)
-
6
if value
-
6
if value == :enable || value == :enabled
-
6
flow.add_flow_enable = :enabled
-
elsif value == :disable || value == :disabled
-
flow.add_flow_enable = :disabled
-
else
-
fail "Unknown add_flow_enable value, #{value}, must be :enabled or :disabled"
-
end
-
else
-
flow.add_flow_enable = nil
-
end
-
end
-
-
# This identifier will be used to make labels and other references unique to the
-
# current application. This will help to avoid name duplication if a program is
-
# comprised of many modules generated by Origen.
-
#
-
# Override in the application interface to customize, by default the identifier
-
# will be Origen.config.initials
-
2
def app_identifier
-
Origen.config.initials || 'Anon App'
-
end
-
-
2
def close(options = {})
-
326
sheet_generators.each do |generator|
-
2776
generator.close(options)
-
end
-
end
-
-
# Compile a template file
-
2
def compile(file, options = {})
-
2
return unless write?
-
# Any options passed in from an interface will be passed to the compiler and to
-
# the templates being compiled
-
2
options[:initial_options] = options
-
2
Origen.file_handler.preserve_state do
-
begin
-
2
file = Origen.file_handler.clean_path_to_template(file)
-
2
Origen.generator.compile_file_or_directory(file, options)
-
rescue
-
file = Origen.file_handler.clean_path_to(file)
-
Origen.generator.compile_file_or_directory(file, options)
-
end
-
end
-
end
-
-
2
def import(file, options = {})
-
# Attach the import request to the first generator, when it imports
-
# it any generated resources will automatically find their way to the
-
# correct generator/collection
-
133
generator = flow || sheet_generators.first
-
133
generator.import(file, options)
-
end
-
-
2
def render(file, options = {})
-
12
flow.render(file, options)
-
end
-
-
2
def add_meta!(options)
-
745
flow.send(:add_meta!, options)
-
end
-
-
2
def add_description!(options)
-
745
flow.send(:add_description!, options)
-
end
-
-
2
def write_files(options = {})
-
13
sheet_generators.each do |generator|
-
188
generator.finalize(options)
-
end
-
13
sheet_generators.each do |generator|
-
198
generator.write_to_file(options) if generator.to_be_written?
-
end
-
13
clean_referenced_patterns
-
13
flow.save_program
-
end
-
-
2
def on_program_completion(options = {})
-
13
reset_globals
-
13
@@pattern_references = {}
-
13
@@referenced_patterns = nil
-
end
-
-
# A secondary pattern is one where the pattern has been created by Origen as an output from
-
# generating another pattern (a primary pattern). For example, on V93K anytime a tester
-
# handshake is done, the pattern will be split into separate components, such as
-
# meas_bgap.avc (the primary pattern) and meas_bgap_part1.avc (a secondary pattern).
-
#
-
# Any such secondary pattern references should be pushed to this array, rather than the
-
# referenced_patterns array.
-
# By using the dedicated secondary array, the pattern will not appear in the referenced.list
-
# file so that Origen is not asked to generate it (since it will be created naturally from
-
# the primary pattern reference).
-
# However if the ATE requires a reference to the pattern (e.g. the V93K pattern master file),
-
# then it will be included in the relevant ATE files.
-
2
def record_pattern_reference(name, options = {})
-
3406
if name.is_a?(String) || name.is_a?(Symbol)
-
3406
name = name.to_s
-
else
-
fail "Pattern name must be a string or a symbol, not a #{name.class}"
-
end
-
# Help out the user and force any multi-part patterns to :ate type
-
3406
unless options[:type]
-
3406
if name.sub(/\..*/, '') =~ /part\d+$/
-
options[:type] = :ate
-
end
-
end
-
3406
unless options[:type] == :origen
-
# Inform the current generator that it has a new pattern reference to handle
-
3406
if respond_to?(:pattern_reference_recorded)
-
1474
pattern_reference_recorded(name, options)
-
end
-
end
-
3406
base = options[:subroutine] ? pattern_references[:subroutine] : pattern_references[:main]
-
3406
case options[:type]
-
when :origen
-
base[:origen] << name
-
when :ate
-
base[:ate] << name
-
when nil
-
3406
base[:all] << name
-
else
-
fail "Unknown pattern reference type, #{options[:type]}, valid values are :origen or :ate"
-
end
-
nil
-
end
-
-
# @api private
-
2
def clear_pattern_references
-
@@pattern_references = nil
-
end
-
-
# @api private
-
2
def merge_pattern_references(references)
-
references.each do |name, values|
-
pattern_references(name)[:main][:all].push(*values[:main][:all])
-
end
-
end
-
-
2
def pattern_references(name = pattern_references_name)
-
3524
@@pattern_references ||= {}
-
3524
@@pattern_references[name] ||= {
-
main: {
-
all: [],
-
origen: [],
-
ate: []
-
},
-
subroutine: {
-
all: [],
-
origen: [],
-
ate: []
-
}
-
}
-
end
-
-
2
def all_pattern_references
-
118
pattern_references
-
118
@@pattern_references
-
end
-
-
2
def pattern_references_name=(name)
-
85
@pattern_references_name = name
-
end
-
-
2
def pattern_references_name
-
3524
@pattern_references_name || 'global'
-
end
-
-
# @deprecated Use record_pattern_reference instead
-
#
-
# All generators should push to this array whenever they reference a pattern
-
# so that it is captured in the pattern list, e.g.
-
# Origen.interface.referenced_patterns << pattern
-
#
-
# If the ATE platform also has a pattern list, e.g. the pattern master file on V93K,
-
# then this will also be updated.
-
# Duplicates will be automatically eliminated, so no duplicate checking should be
-
# performed on the application side.
-
2
def referenced_patterns
-
1945
@@referenced_patterns ||= PatternArray.new
-
end
-
-
# Remove duplicates and file extensions from the referenced pattern lists
-
2
def clean_referenced_patterns
-
13
refs = [:referenced_patterns]
-
# refs << :referenced_subroutine_patterns if Origen.tester.v93k?
-
13
refs.each do |ref|
-
13
var = send(ref)
-
13
var = var.uniq.map do |pat|
-
pat = pat.sub(/\..*/, '')
-
pat unless pat =~ /_part\d+$/
-
end.uniq.compact
-
13
singleton_class.class_variable_set("@@#{ref}", var)
-
end
-
end
-
-
# Add a comment line into the buffer
-
2
def comment(text)
-
comments << text
-
end
-
-
2
def comments
-
1133
@@comments ||= []
-
end
-
-
2
def discard_comments
-
1133
@@comments = nil
-
end
-
-
# Returns the buffered description comments and clears the buffer
-
2
def consume_comments
-
1133
c = comments
-
1133
discard_comments
-
1133
c
-
end
-
-
2
def top_level_flow
-
204
@@top_level_flow ||= nil
-
end
-
2
alias_method :top_level_flow_filename, :top_level_flow
-
-
2
def discard_top_level_flow
-
@@top_level_flow = nil
-
end
-
-
2
def flow_generator
-
310
flow
-
end
-
-
2
def set_top_level_flow
-
155
@@top_level_flow = flow_generator.output_file
-
end
-
-
2
def clear_top_level_flow
-
59
@@top_level_flow = nil
-
end
-
-
# A storage Hash that all generators can push comment descriptions
-
# into when generating.
-
# At the end of a generation run this will contain all descriptions
-
# for all flows that were just created.
-
#
-
# Access via Origen.interface.descriptions
-
2
def descriptions
-
1133
@@descriptions ||= Parser::DescriptionLookup.new
-
end
-
-
# Any tests generated within the given block will be generated in resources mode.
-
# Generally this means that all resources for a given test will be generated but
-
# flow entries will be inhibited.
-
2
def resources_mode
-
19
OrigenTesters::Interface.with_resources_mode do
-
19
yield
-
end
-
end
-
2
alias_method :with_resources_mode, :resources_mode
-
-
2
def resources_mode?
-
4995
OrigenTesters::Interface.resources_mode?
-
end
-
-
2
def identity_map # :nodoc:
-
1921
@@identity_map ||= ::OrigenTesters::Generator::IdentityMap.new
-
end
-
-
2
def platform
-
# This branch to support the ProgramGenerators module where the generator
-
# is included into an interface instance and not the class
-
9471
if singleton_class.const_defined? :PLATFORM
-
9471
singleton_class::PLATFORM
-
else
-
self.class::PLATFORM
-
end
-
end
-
-
2
module ClassMethods
-
# Returns true if the interface class supports the
-
# given tester instance
-
2
def supports?(tester_instance)
-
tester_instance.class == self::PLATFORM
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module LabVIEWBasedTester
-
2
autoload :Pxie6570, 'origen_testers/labview_based_tester/pxie6570.rb'
-
end
-
# Shorter name without LabVIEWBasedTester namespace
-
2
autoload :Pxie6570, 'origen_testers/labview_based_tester/pxie6570.rb'
-
end
-
1
module OrigenTesters
-
1
module LabVIEWBasedTester
-
1
class Pxie6570
-
1
include OrigenTesters::VectorBasedTester
-
-
1
attr_accessor :default_source_wave_name, :default_capture_wave_name
-
-
1
def initialize
-
4
@name = 'pxie'
-
4
@pat_extension = 'digipatsrc'
-
4
@capture_history = {}
-
4
@source_history = {}
-
4
@global_label_export = []
-
4
@called_subroutines = []
-
4
@default_capture_wave_name = 'default_capture_waveform'
-
4
@default_source_wave_name = 'default_source_waveform'
-
end
-
-
# Internal method called by Origen
-
1
def pattern_header(options = {})
-
4
microcode "// source count: #{@source_history[:count]}" if @source_history[:started]
-
4
microcode "// capture count: #{@capture_history[:count]}" if @capture_history[:started]
-
4
microcode 'file_format_version 1.0;'
-
4
start_label = "#{options[:pattern]}_st"
-
4
microcode "export #{start_label};"
-
4
@global_label_export.each { |label| microcode "export #{label};" }
-
10
@called_subroutines.each { |sub| microcode "import #{sub};" }
-
4
called_timesets.each do |timeset|
-
4
microcode "timeset #{timeset.name};"
-
end
-
4
pin_list = ordered_pins.map(&:name).join(',')
-
4
microcode "pattern #{options[:pattern]} (#{pin_list})"
-
4
microcode '{'
-
4
microcode "#{start_label}:"
-
# Remove any leading comments before first vector data
-
4
unless options[:subroutine_pat]
-
4
stage.with_bank(:body) do
-
# find the first vector
-
4
stage.bank.delete_at(0) until stage.bank[0].is_a?(OrigenTesters::Vector) || stage.bank.empty?
-
end
-
end
-
end
-
-
# Internal method called by Origen
-
1
def pattern_footer(options = {})
-
# add capture/source stop to the end of the pattern
-
4
cycle microcode: 'capture_stop' if @capture_history[:started]
-
4
cycle microcode: 'halt'
-
4
microcode '}'
-
end
-
-
# Internal method called by Origen
-
1
def format_vector(vec)
-
269
timeset = vec.timeset ? " #{vec.timeset.name}" : ''
-
269
pin_vals = vec.pin_vals ? "#{vec.pin_vals} ;" : ''
-
269
microcode = vec.microcode ? vec.microcode : ''
-
269
if vec.repeat > 1
-
125
microcode = "repeat (#{vec.repeat})"
-
else
-
144
microcode = vec.microcode ? vec.microcode : ''
-
end
-
269
if vec.pin_vals && ($_testers_enable_vector_comments || vector_comments)
-
comment = " // #{vec.number}:#{vec.cycle} #{vec.inline_comment}"
-
else
-
269
comment = vec.inline_comment.empty? ? '' : " // #{vec.inline_comment}"
-
end
-
-
269
"#{microcode.ljust(65)}#{timeset.ljust(31)}#{pin_vals}#{comment}"
-
end
-
-
# insert a subroutine call
-
# provide optional argument to implement as jump instead of call:
-
#
-
# @example
-
# tester.call_subroutine 'my_sub', jump: true
-
1
def call_subroutine(name, options = {})
-
6
options = { jump: false }.merge(options)
-
6
@called_subroutines << name.to_s.chomp unless @called_subroutines.include?(name.to_s.chomp)
-
6
local_microcode = ''
-
6
if options[:jump]
-
local_microcode = "jump #{name}"
-
else
-
6
local_microcode = "call #{name}"
-
end
-
6
update_vector microcode: local_microcode, offset: options[:offset]
-
end
-
-
1
def start_subroutine(name, options = {})
-
options = { global: false }.merge(options)
-
label name, options[:global]
-
end
-
-
1
def end_subroutine
-
update_vector microcode: 'return'
-
end
-
-
# store/capture the state of the provided pins
-
1
def store(*pins)
-
options = pins.last.is_a?(Hash) ? pins.pop : {}
-
options = { offset: 0 }.merge(options)
-
pins = pins.flatten.compact
-
-
fail 'For the PXIE6570 you must supply the pins to store/capture' if pins.empty?
-
add_capture_start pins, options
-
-
pins.each do |pin|
-
pin.restore_state do
-
pin.capture
-
update_vector_pin_val pin, offset: options[:offset]
-
last_vector(options[:offset]).dont_compress = true
-
end
-
end
-
-
update_vector microcode: 'capture', offset: options[:offset]
-
end
-
1
alias_method :to_hram, :store
-
1
alias_method :capture, :store
-
-
1
def add_microcode_to_first_vec(statement)
-
# find the first vector
-
2
i = 0
-
2
i += 1 until stage.bank[i].is_a?(OrigenTesters::Vector)
-
2
first_vector = stage.bank[i]
-
-
2
if first_vector.has_microcode? || first_vector.repeat > 1
-
1
v = OrigenTesters::Vector.new
-
1
v.pin_vals = first_vector.pin_vals
-
1
v.timeset = first_vector.timeset
-
1
v.inline_comment = 'added line for opcode insert'
-
1
v.dont_compress = true
-
1
v.microcode = statement
-
1
stage.insert_from_start v, i
-
-
# decrement repeat count of previous first vector if > 1
-
1
first_vector.repeat -= 1 if first_vector.repeat > 1
-
else
-
1
first_vector.microcode = statement
-
end
-
end
-
-
1
def cycle(options = {})
-
# handle overlay if requested
-
987
overlay_options = options.key?(:overlay) ? options.delete(:overlay) : {}
-
987
cur_pin_state = nil
-
987
if overlay_options.key?(:pins)
-
2
overlay_options = { change_data: true }.merge(overlay_options)
-
2
unless @source_history[:started]
-
1
add_microcode_to_first_vec "source_start(#{@default_source_wave_name})"
-
1
@source_history[:started] = true
-
1
@source_history[:count] = 0
-
end
-
-
# ensure no unwanted repeats on the source line
-
2
options[:dont_compress] = true
-
-
2
if overlay_options[:change_data]
-
1
@source_history[:count] += 1
-
1
if options[:microcode].nil?
-
1
options[:microcode] = 'source'
-
else
-
options[:microcode] = options[:microcode] + ', source'
-
end
-
1
options[:microcode] = options[:microcode] + ", repeat (#{options[:repeat]})" unless options[:repeat].nil?
-
1
options.delete(:repeat)
-
end
-
-
# set pins to drive data
-
2
cur_pin_state = overlay_options[:pins].state.to_sym
-
2
overlay_options[:pins].drive_mem
-
end
-
987
super(options)
-
987
overlay_options[:pins].state = cur_pin_state if overlay_options.key?(:pins)
-
end
-
-
# internal method to avoid needless code duplication
-
1
def add_capture_start(pins, options = {})
-
1
unless @capture_history[:started]
-
# add the capture start opcode to the top of the pattern
-
1
add_microcode_to_first_vec "capture_start(#{@default_capture_wave_name})"
-
1
@capture_history[:started] = true
-
1
@capture_history[:count] = 0
-
end
-
end
-
-
# store/capture the provided pins on the next cycle
-
1
def store_next_cycle(*pins)
-
1
options = pins.last.is_a?(Hash) ? pins.pop : {}
-
1
options = { offset: 0 }.merge(options)
-
1
pins = pins.flatten.compact
-
-
1
repeat_count = options[:repeat].nil? ? 1 : options[:repeat]
-
-
1
fail 'For the PXIE6570 you must supply the pins to store/capture' if pins.empty?
-
1
add_capture_start pins, options
-
1
@capture_history[:count] += repeat_count
-
-
2
pins.each { |pin| pin.save; pin.capture }
-
1
preset_next_vector(microcode: 'capture') do
-
1
pins.each(&:restore)
-
end
-
end
-
1
alias_method :store!, :store_next_cycle
-
-
# add a label to the output pattern
-
1
def label(name, global = false)
-
microcode name + ':'
-
@global_label_export << name if global
-
end
-
-
# change the capture state character
-
1
def format_pin_state(pin)
-
3538
response = super(pin)
-
3538
response.sub('C', 'V')
-
end
-
-
# warn but don't fail if an api for another platform is not yet implemented
-
1
def method_missing(m, *args, &block)
-
Origen.log.warn "#{m} is not yet implemented for LabVIEWBasedTester::Pxie6570"
-
end
-
end
-
end
-
1
Pxie6570 = LabVIEWBasedTester::Pxie6570
-
end
-
2
module OrigenTesters
-
2
class MemoryStyle
-
2
attr_reader :pin_id, :size, :bit_order, :format, :trigger, :mode, :data_type
-
-
2
def initialize
-
20
@pin_id = []
-
20
@size = []
-
20
@bit_order = []
-
20
@format = []
-
20
@trigger = []
-
20
@mode = []
-
20
@data_type = []
-
end
-
-
# Set memory style attributes for the given pin
-
#
-
# @example
-
# mem.pin :tdi, size: 8, trigger: :auto
-
2
def pin(*pin_ids)
-
25
options = pin_ids.last.is_a?(Hash) ? pin_ids.pop : {}
-
25
pin_ids.each_index do |i|
-
26
if pin_ids[i].is_a?(Symbol)
-
26
pin_ids[i] = dut.pin(pin_ids[i]).name
-
else
-
pin_ids[i] = pin_ids[i].name
-
end
-
end
-
25
@pin_id << pin_ids
-
25
@size << options[:size]
-
25
@bit_order << options[:bit_order]
-
25
@format << options[:format]
-
25
@trigger << options[:trigger]
-
25
@mode << options[:mode]
-
25
@data_type << options[:data_type]
-
end
-
-
# Get the chronologically last setting for the given pin's attributes
-
#
-
# @example
-
# mem.pin :tdi, size: 1
-
# mem.pin :tdi, size: 2
-
#
-
# my_local_attribute_hash = mem.accumulate_attributes(:tdi)
-
# # my_local_attribute_hash now is
-
# # {pin_id: :tdi, size: 2, bit_order: nil, format: nil, trigger: nil}
-
2
def accumulate_attributes(pin_id)
-
13
a = { pin_id: pin_id }
-
13
@pin_id.each_index do |i|
-
20
if @pin_id[i].include?(pin_id)
-
12
a[:size] = @size[i]
-
12
a[:bit_order] = @bit_order[i]
-
12
a[:format] = @format[i]
-
12
a[:trigger] = @trigger[i]
-
12
a[:mode] = @mode[i]
-
12
a[:data_type] = @data_type[i]
-
end
-
end
-
13
a
-
end
-
-
# Check to see if a given pin exists in this style container
-
2
def contains_pin?(pin_id)
-
3
contained_pins.include?(pin_id)
-
end
-
-
# Get an array of pins contained in this style container
-
2
def contained_pins
-
4
pins = []
-
4
@pin_id.each do |a|
-
8
a.each do |p|
-
8
pins << p
-
end
-
end
-
4
pins.uniq
-
end
-
end
-
end
-
# This shim is temporary to help NXP transition to Origen from
-
# our original internal version (RGen)
-
2
if defined? RGen::ORIGENTRANSITION
-
require 'rgen/application/runner'
-
else
-
2
require 'origen/application/runner'
-
end
-
2
module Origen
-
2
class Application
-
2
class Runner
-
2
alias_method :orig_launch, :launch
-
# Patch this to allow write: false to be given as an option when
-
# generating a test program. When supplied and set to false, the program
-
# output files will not be written and only a flow model will be generated.
-
2
def launch(options = {})
-
13
if options.key?(:write)
-
OrigenTesters::Interface.write = options[:write]
-
else
-
13
OrigenTesters::Interface.write = true
-
end
-
13
orig_launch(options)
-
end
-
end
-
end
-
end
-
# This shim is temporary to help NXP transition to Origen from
-
# our original internal version (RGen)
-
2
if defined? RGen::ORIGENTRANSITION
-
require 'rgen/generator'
-
else
-
2
require 'origen/generator'
-
end
-
2
module Origen
-
2
class Generator
-
2
include Comparator
-
-
# @api private
-
2
def generate_program(file, options)
-
13
Origen.file_handler.resolve_files(file, ignore_with_prefix: '_', default_dir: "#{Origen.root}/program") do |path|
-
60
Origen.file_handler.current_file = path
-
60
j = Job.new(path, options)
-
60
j.pattern = path
-
60
j.run
-
end
-
13
yield if block_given?
-
13
Origen.interface.write_files(options)
-
13
unless options[:quiet] || !Origen.interface.write? || options[:skip_referenced_pattern_write]
-
13
if options[:referenced_pattern_list]
-
file = "#{Origen.root}/list/#{options[:referenced_pattern_list]}"
-
else
-
13
file = Origen.config.referenced_pattern_list
-
end
-
13
Origen.log.info "Referenced pattern list written to: #{Pathname.new(file).relative_path_from(Pathname.pwd)}"
-
13
dir = Pathname.new(file).dirname
-
13
FileUtils.mkdir_p(dir) unless dir.exist?
-
13
File.open(file, 'w') do |f|
-
13
pats = Origen.interface.all_pattern_references.map do |name, refs|
-
33
refs[:main][:all] + refs[:main][:origen]
-
end.flatten.uniq.sort
-
13
unless pats.empty?
-
13
f.puts '# Main patterns'
-
746
pats.each { |p| f.puts p }
-
13
f.puts
-
end
-
-
13
pats = Origen.interface.all_pattern_references.map do |name, refs|
-
33
refs[:subroutine][:all] + refs[:subroutine][:origen]
-
end.flatten.uniq.sort
-
13
unless pats.empty?
-
f.puts '# Subroutine patterns'
-
pats.each { |p| f.puts p }
-
end
-
end
-
13
ref_file = File.join(Origen.file_handler.reference_directory, Pathname.new(file).basename)
-
13
check_for_changes(file, ref_file)
-
end
-
13
Origen.interface.on_program_completion(options) unless options[:skip_on_program_completion]
-
end
-
end
-
end
-
# This shim is temporary to help NXP transition to Origen from
-
# our original internal version (RGen)
-
2
if defined? RGen::ORIGENTRANSITION
-
require 'rgen/generator/flow'
-
else
-
2
require 'origen/generator/flow'
-
end
-
2
module Origen
-
2
class Generator
-
2
class Flow
-
# Create a call stack of flows so that we can work out where the nodes
-
# of the ATP AST originated from
-
2
def create(options = {}, &block)
-
options = {
-
279
reload_target: true,
-
name: OrigenTesters::Flow.name_stack.pop
-
}.merge(options)
-
# Patch for Windows operation since the path can start with something like "C:/"
-
279
if caller[0] =~ /(:(\/|\\))/
-
orig_separator = Regexp.last_match(1)
-
file, line = *caller[0].sub(/:(\/|\\)/, '_ORIG_SEPARATOR_').split(':')
-
file = file.sub('_ORIG_SEPARATOR_', orig_separator)
-
else
-
279
file, line = *caller[0].split(':')
-
end
-
279
OrigenTesters::Flow.callstack << file
-
279
flow_comments, comments = *_extract_comments(OrigenTesters::Flow.callstack.last, line.to_i)
-
279
OrigenTesters::Flow.comment_stack << comments
-
279
OrigenTesters::Flow.ht_comments = {}
-
279
comments.each do |src_line, com_array|
-
1011
flow_src_line = src_line + com_array.size
-
1011
OrigenTesters::Flow.ht_comments[flow_src_line] = com_array
-
end
-
279
if OrigenTesters::Flow.flow_comments
-
122
top = false
-
122
name = options[:name] || Pathname.new(file).basename('.rb').to_s.sub(/^_/, '')
-
# Generate imports as separate sub-flow files on this platform
-
122
if tester.v93k? && tester.smt8?
-
26
parent, sub_flow = *_sub_flow(name, options, &block)
-
26
path = sub_flow.output_file.relative_path_from(Origen.file_handler.output_directory)
-
26
parent.atp.sub_flow(sub_flow.atp.raw, path: path.to_s)
-
else
-
96
Origen.interface.flow.group(name, description: flow_comments) do
-
96
_create(options, &block)
-
end
-
end
-
else
-
157
@top_level_flow = nil
-
157
OrigenTesters::Flow.flow_comments = flow_comments
-
157
if options.key?(:unique_ids)
-
OrigenTesters::Flow.unique_ids = options.delete(:unique_ids)
-
else
-
157
OrigenTesters::Flow.unique_ids = true
-
end
-
157
top = true
-
157
_create(options, &block)
-
end
-
279
OrigenTesters::Flow.callstack.pop
-
279
OrigenTesters::Flow.comment_stack.pop
-
279
OrigenTesters::Flow.flow_comments = nil if top
-
end
-
-
# @api private
-
2
def _sub_flow(name, options, &block)
-
54
@top_level_flow ||= Origen.interface.flow
-
54
parent = Origen.interface.flow
-
# If the parent flow already has a child flow of this name then we need to generate a
-
# new unique name/id
-
# Also generate a new name when the child flow name matches the parent flow name, SMT8.2
-
# onwards does not allow this
-
54
if parent.children[name] || parent.name.to_s == name.to_s
-
12
i = 0
-
12
tempname = name
-
12
while parent.children[tempname] || parent.name.to_s == tempname.to_s
-
18
i += 1
-
18
tempname = "#{name}_#{i}"
-
end
-
12
name = tempname
-
end
-
54
if parent
-
54
id = parent.path + ".#{name}"
-
else
-
id = name
-
end
-
54
sub_flow = Origen.interface.with_flow(id) do
-
54
Origen.interface.flow.instance_variable_set(:@top_level, @top_level_flow)
-
54
Origen.interface.flow.instance_variable_set(:@parent, parent)
-
54
_create(options, &block)
-
end
-
54
parent.children[name] = sub_flow
-
54
[parent, sub_flow]
-
end
-
-
# @api private
-
2
def _create(options = {}, &block)
-
options = {
-
307
reload_target: true
-
}.merge(options)
-
# Make the top level flow globally available, this helps to assign test descriptions
-
# to the correct flow whenever tests are instantiated from sub-flows
-
307
if Origen.interface_loaded? && Origen.interface.top_level_flow
-
152
sub_flow = true
-
152
if Origen.tester.doc?
-
Origen.interface.flow.start_section
-
end
-
else
-
155
sub_flow = false
-
end
-
307
job.output_file_body = options.delete(:name).to_s if options[:name]
-
307
if sub_flow
-
152
interface = Origen.interface
-
152
if reload_target?(interface, options)
-
151
Origen.app.reload_target!
-
151
Origen.tester.generating = :program
-
end
-
152
opts = Origen.generator.option_pipeline.pop || {}
-
152
Origen.interface.startup(options) if Origen.interface.respond_to?(:startup)
-
152
interface.instance_exec(opts, &block)
-
152
Origen.interface.shutdown(options) if Origen.interface.respond_to?(:shutdown)
-
152
if Origen.tester.doc?
-
Origen.interface.flow.stop_section
-
end
-
152
interface.close(flow: true, sub_flow: true)
-
else
-
155
Origen.log.info "Generating... #{Origen.file_handler.current_file.basename}"
-
155
interface = Origen.reset_interface(options)
-
155
if reload_target?(interface, options)
-
154
Origen.app.reload_target!
-
154
Origen.tester.generating = :program
-
end
-
155
Origen.interface.set_top_level_flow
-
155
Origen.interface.flow_generator.set_flow_description(Origen.interface.consume_comments)
-
155
options[:top_level] = true
-
155
Origen.interface.flow.instance_variable_set('@top_level', Origen.interface.flow)
-
155
Origen.interface.flow.on_top_level_set if Origen.interface.flow.respond_to?(:on_top_level_set)
-
155
Origen.app.listeners_for(:on_flow_start).each do |listener|
-
155
listener.on_flow_start(options)
-
end
-
155
Origen.interface.startup(options) if Origen.interface.respond_to?(:startup)
-
155
interface.instance_eval(&block)
-
155
Origen.interface.generate_eof_charz_tests if Origen.interface.respond_to?(:generate_eof_charz_tests)
-
155
Origen.interface.shutdown(options) if Origen.interface.respond_to?(:shutdown)
-
155
interface.at_flow_end if interface.respond_to?(:at_flow_end)
-
155
Origen.app.listeners_for(:on_flow_end).each do |listener|
-
listener.on_flow_end(options)
-
end
-
155
interface.close(flow: true)
-
end
-
end
-
-
2
def reset
-
60
Origen.interface.clear_top_level_flow if Origen.interface_loaded?
-
end
-
-
2
def job
-
6
Origen.app.current_job
-
end
-
-
2
def _extract_comments(file, flow_line)
-
279
flow_comments = []
-
279
comments = {}
-
279
comment = nil
-
279
File.readlines(file).each_with_index do |line, i|
-
86811
if comment
-
2284
if line =~ /^\s*#-(.*)/
-
# Nothing, just ignore but keep the comment open
-
2284
elsif line =~ /^\s*#(.*)/
-
1042
comment << Regexp.last_match(1).strip
-
else
-
1242
comment = nil
-
end
-
else
-
84527
if line =~ /^\s*#[^-](.*)/
-
1242
if i < flow_line
-
231
comment = flow_comments
-
else
-
1011
comment = []
-
1011
comments[i + 1] = comment
-
end
-
1242
comment << Regexp.last_match(1).strip
-
end
-
end
-
end
-
279
[flow_comments, comments]
-
end
-
-
2
private
-
-
2
def reload_target?(interface, options)
-
307
if interface.respond_to?(:reload_target)
-
# If the test interface cares about reloading the target,
-
# it can veto the default behavior of reloading the target
-
2
if interface.reload_target && options[:reload_target]
-
true
-
else
-
2
false
-
end
-
305
elsif options[:reload_target]
-
305
true
-
else
-
false
-
end
-
end
-
end
-
end
-
-
# Provides a hook to enable an internal startup callback to
-
2
class OrigenTestersPersistentFlowCallbackHandler
-
2
include Origen::PersistentCallbacks
-
-
2
def on_flow_start(options)
-
155
if Origen.interface.respond_to?(:_internal_startup)
-
59
Origen.interface._internal_startup(options)
-
end
-
end
-
end
-
# Instantiate an instance of this class immediately when this file is loaded, this object will
-
# then listen for the remainder of the Origen thread
-
2
OrigenTestersPersistentFlowCallbackHandler.new
-
end
-
# This responsibility should be with OrigenTesters, starting to override the methods here
-
# within OrigenTesters over time and it will be removed from Origen in future once fully
-
# transferred
-
2
require 'origen/generator/pattern'
-
2
module Origen
-
2
class Generator
-
2
class Pattern
-
# @api private
-
2
def self.convert(file)
-
@converting = file
-
yield
-
@converting = nil
-
end
-
-
# @api private
-
2
def self.converting
-
284
@converting
-
end
-
-
2
private
-
-
2
def converting
-
284
self.class.converting
-
end
-
-
2
def header
-
142
Origen.tester.pre_header if Origen.tester.doc?
-
142
inject_separator
-
142
if $desc
-
c2 'DESCRIPTION:'
-
$desc.split(/\n/).each { |line| cc line }
-
inject_separator
-
end
-
142
c2 'GENERATED:'
-
142
c2 " Time: #{Origen.launch_time}"
-
142
c2 " By: #{Origen.current_user.name}"
-
142
c2 " Mode: #{Origen.mode}"
-
142
if converting
-
c2 " Source: #{converting}"
-
-
else
-
142
l = " Command: origen g #{job.requested_pattern} -t #{Origen.target.file.basename}"
-
142
if Origen.environment && Origen.environment.file
-
142
l += " -e #{Origen.environment.file.basename}"
-
end
-
142
c2(l)
-
end
-
142
inject_separator
-
142
c2 'ENVIRONMENT:'
-
142
unless converting
-
142
c2 ' Application'
-
142
if Origen.app.rc
-
142
if Origen.app.rc.git?
-
142
c2 " Source: #{Origen.config.rc_url}"
-
else
-
c2 " Vault: #{Origen.config.vault}"
-
end
-
end
-
142
c2 " Version: #{Origen.app.version}"
-
142
unless Origen.app.config.release_externally
-
c2 " Workspace: #{Origen.root}"
-
end
-
142
if Origen.app.rc && Origen.app.rc.git?
-
begin
-
142
@branch ||= Origen.app.rc.current_branch
-
142
@commit ||= Origen.app.rc.current_commit
-
142
status = "#{@branch}(#{@commit})"
-
142
@pattern_local_mods = !Origen.app.rc.local_modifications.empty? unless @pattern_local_mods_fetched
-
142
@pattern_local_mods_fetched = true
-
142
status += ' (+local edits)' if @pattern_local_mods
-
142
c2 " Branch: #{status}"
-
rescue
-
# No problem, we did our best
-
end
-
end
-
end
-
142
c2 ' Origen'
-
142
c2 ' Source: https://github.com/Origen-SDK/origen'
-
142
c2 " Version: #{Origen.version}"
-
142
unless Origen.app.plugins.empty?
-
142
c2 ' Plugins'
-
852
Origen.app.plugins.sort_by { |p| p.name.to_s }.each do |plugin|
-
710
c2 " #{plugin.name}:".ljust(30) + plugin.version
-
end
-
end
-
142
inject_separator
-
-
142
unless Origen.app.plugins.empty?
-
# Plugins can use config.shared_pattern_header to inject plugin-specific comments into the patterns header
-
142
header_printed = false
-
852
Origen.app.plugins.sort_by { |p| p.name.to_s }.each do |plugin|
-
710
unless plugin.config.shared_pattern_header.nil?
-
unless header_printed
-
c2 'Header Comments From Shared Plugins:'
-
header_printed = true
-
end
-
inject_pattern_header(
-
config_loc: plugin,
-
scope: :shared_pattern_header,
-
message: "Header Comments From Shared Plugin: #{plugin.name}:",
-
message_spacing: 2,
-
line_spacing: 4,
-
no_separator: true
-
)
-
end
-
end
-
142
inject_separator if header_printed
-
end
-
-
142
if Origen.app.plugins.current && !Origen.app.plugins.current.config.send(:current_plugin_pattern_header).nil?
-
# The top level plugin (if one is set) can further inject plugin-specific comment into the header.
-
# These will only appear if the plugin is the top-level plugin though.
-
inject_pattern_header(
-
config_loc: Origen.app.plugins.current,
-
scope: :current_plugin_pattern_header,
-
message: "Header Comments From The Current Plugin: #{Origen.app.plugins.current.name}:"
-
)
-
end
-
-
142
unless Origen.app.config.send(:application_pattern_header).nil?
-
inject_pattern_header(
-
config_loc: Origen.app,
-
scope: :application_pattern_header,
-
message: "Header Comments From Application: #{Origen.app.name}:"
-
)
-
end
-
-
142
if Origen.config.pattern_header
-
Origen.log.deprecated 'Origen.config.pattern_header is deprecated.'
-
Origen.log.deprecated 'Please use config.shared_pattern_header, config.application_pattern_header, or config.current_plugin_pattern_header instead.'
-
inject_separator
-
end
-
142
Origen.tester.close_text_block if Origen.tester.doc?
-
end
-
end
-
end
-
end
-
# This shim is temporary to help NXP transition to Origen from
-
# our original internal version (RGen)
-
2
if defined? RGen::ORIGENTRANSITION
-
require 'rgen/generator/resources'
-
else
-
2
require 'origen/generator/resources'
-
end
-
2
module Origen
-
2
class Generator
-
2
class Resources
-
2
alias_method :orig_create, :create
-
-
# Patching to make resources_mode apply much earlier
-
2
def create(options = {}, &block)
-
19
OrigenTesters::Interface.with_resources_mode do
-
19
orig_create(options, &block)
-
end
-
end
-
end
-
end
-
end
-
# This code is used to extend Origen Core's pin class with additional functionality
-
-
2
require 'origen/pins/pin'
-
-
2
module Origen
-
2
module Pins
-
2
class Pin
-
# Returns the channel number for the pin on a given tester site (default = 0), based on a given tester channel
-
# map (default_channelmap). Optionally user can specify site or channelmap.
-
2
def channel(options = {})
-
options = {
-
chanmapname: $tester.default_channelmap, # Default is to use default_channelmap
-
site: 0 # Default is to use site 0.
-
}.merge(options)
-
unless $tester.channelmap[options[:chanmapname]]
-
fail "You must first import the tester channel map (e.g. $tester.channelmap = \"probe_x32\") before calling pin.channel"
-
end
-
-
channelinfo = Struct.new(:channel, :chanmapname, :site)
-
channelinfo.new($tester.get_tester_channel(options[:chanmapname], name, options[:site]), options[:chanmapname], options[:site])
-
end
-
-
# Returns the instrument type for the pin on a given tester site (default = 0), based on a given tester channel
-
# map (default_channelmap) and a given tester configuration (default_testerconfig).
-
# Optionally user can specify site, channelmap, or testerconfig.
-
2
def instrument_type(options = {})
-
options = {
-
1
chanmapname: $tester.default_channelmap, # Default is to use default_channelmap
-
site: 0, # Default is to use site 0.
-
testerconfigname: $tester.default_testerconfig # Default is to use default_testerconfig
-
}.merge(options)
-
-
1
unless $tester.channelmap[options[:chanmapname]]
-
fail "You must first import the tester channel map (e.g. $tester.channelmap = \"probe_x32\") before calling pin.channel"
-
end
-
1
unless $tester.testerconfig[options[:testerconfigname]]
-
fail "You must first import the tester configuration (e.g. $tester.testerconfig = \"UflexConfigA\") before calling pin.instrument_type"
-
end
-
-
1
instrumentinfo = Struct.new(:instrument, :chanmapname, :site, :testerconfigname)
-
1
instrumentinfo.new($tester.get_tester_instrument(options[:testerconfigname], $tester.get_tester_channel(options[:chanmapname], name, options[:site]).split('.')[0].to_i), options[:chanmapname], options[:site], options[:testerconfigname])
-
end
-
-
# Returns ATE Hardware information for the pin (channel # and instrument type) on a given tester site
-
# (default = 0), based on a given tester channelmap (default_channelmap) and a given tester
-
# configuration (default_testerconfig). # Optionally user can specify site, channelmap, or testerconfig.
-
2
def ate_hardware(options = {})
-
options = {
-
2
chanmapname: $tester.default_channelmap, # Default is to use default_channelmap
-
site: 0, # Default is to use site 0.
-
testerconfigname: $tester.default_testerconfig # Default is to use default_testerconfig
-
}.merge(options)
-
-
2
unless $tester.channelmap[options[:chanmapname]]
-
fail "You must first import the tester channel map (e.g. $tester.channelmap = \"probe_x32\") before calling pin.channel"
-
end
-
2
unless $tester.testerconfig[options[:testerconfigname]]
-
fail "You must first import the tester configuration (e.g. $tester.testerconfig = \"UflexConfigA\") before calling pin.instrument_type"
-
end
-
2
if Origen.top_level.power_pin_groups.keys.include?(name) # Power Pin Groups do not need :ppmu, but need :supply
-
instrumentinfo = Struct.new(:channel, :instrument, :chanmapname, :site, :testerconfigname, :supply)
-
@channel = $tester.get_tester_channel(options[:chanmapname], name, options[:site])
-
@instrument = $tester.get_tester_instrument(options[:testerconfigname], $tester.get_tester_channel(options[:chanmapname], name, options[:site]).split('.')[0].to_i) + $tester.is_vhdvs_hc(options[:chanmapname], name, options[:site]).to_s + $tester.is_hexvs_plus(options[:testerconfigname], @channel.split('.')[0].to_i).to_s + $tester.is_vhdvs_plus(options[:testerconfigname], @channel.split('.')[0].to_i).to_s + $tester.merged_channels(options[:chanmapname], name, options[:site]).to_s
-
@supply = $tester.ate_hardware(@instrument).supply
-
instrumentinfo.new(@channel, @instrument, options[:chanmapname], options[:site], options[:testerconfigname], @supply)
-
else
-
2
if $tester.get_tester_channel(options[:chanmapname], name, options[:site]).split('.')[0].to_i == 24
-
instrumentinfo = Struct.new(:channel, :instrument, :chanmapname, :site, :testerconfigname)
-
instrumentinfo.new($tester.get_tester_channel(options[:chanmapname], name, options[:site]), $tester.get_tester_instrument(options[:testerconfigname], $tester.get_tester_channel(options[:chanmapname], name, options[:site]).split('.')[0].to_i), options[:chanmapname], options[:site], options[:testerconfigname])
-
else
-
2
instrumentinfo = Struct.new(:channel, :instrument, :chanmapname, :site, :testerconfigname, :ppmu)
-
2
instrumentinfo.new($tester.get_tester_channel(options[:chanmapname], name, options[:site]), $tester.get_tester_instrument(options[:testerconfigname], $tester.get_tester_channel(options[:chanmapname], name, options[:site]).split('.')[0].to_i), options[:chanmapname], options[:site], options[:testerconfigname], $tester.ate_hardware($tester.get_tester_instrument(options[:testerconfigname], $tester.get_tester_channel(options[:chanmapname], name, options[:site]).split('.')[0].to_i)).ppmu)
-
end
-
end
-
end
-
end
-
end
-
end
-
# This code is used to extend Origen Core's pin_collection class with additional functionality
-
-
2
require 'origen/pins/pin_collection'
-
-
2
module Origen
-
2
module Pins
-
2
class PinCollection
-
# Returns the channel number for the pin_collection on a given tester site (default = 0), based on a given tester channel
-
# map (default_channelmap). Optionally user can specify site or channelmap.
-
2
def channel(options = {})
-
options = {
-
chanmapname: $tester.default_channelmap, # Default is to use default_channelmap
-
site: 0 # Default is to use site 0.
-
}.merge(options)
-
unless $tester.channelmap[options[:chanmapname]]
-
fail "You must first import the tester channel map (e.g. $tester.channelmap = \"probe_x32\") before calling pin.channel"
-
end
-
-
channelinfo = Struct.new(:channel, :chanmapname, :site)
-
channelinfo.new($tester.get_tester_channel(options[:chanmapname], name, options[:site]), options[:chanmapname], options[:site])
-
end
-
-
# Returns the instrument type for the pin_collection on a given tester site (default = 0), based on a given tester channel
-
# map (default_channelmap) and a given tester configuration (default_testerconfig).
-
# Optionally user can specify site, channelmap, or testerconfig.
-
2
def instrument_type(options = {})
-
options = {
-
chanmapname: $tester.default_channelmap, # Default is to use default_channelmap
-
site: 0, # Default is to use site 0.
-
testerconfigname: $tester.default_testerconfig # Default is to use default_testerconfig
-
}.merge(options)
-
-
unless $tester.channelmap[options[:chanmapname]]
-
fail "You must first import the tester channel map (e.g. $tester.channelmap = \"probe_x32\") before calling pin.channel"
-
end
-
unless $tester.testerconfig[options[:testerconfigname]]
-
fail "You must first import the tester configuration (e.g. $tester.testerconfig = \"UflexConfigA\") before calling pin.instrument_type"
-
end
-
-
instrumentinfo = Struct.new(:instrument, :chanmapname, :site, :testerconfigname)
-
instrumentinfo.new($tester.get_tester_instrument(options[:testerconfigname], $tester.get_tester_channel(options[:chanmapname], name, options[:site]).split('.')[0].to_i), options[:chanmapname], options[:site], options[:testerconfigname])
-
end
-
-
# Returns ATE Hardware information for the pin_collection (channel # and instrument type) on a given tester site
-
# (default = 0), based on a given tester channelmap (default_channelmap) and a given tester
-
# configuration (default_testerconfig). # Optionally user can specify site, channelmap, or testerconfig.
-
2
def ate_hardware(options = {})
-
options = {
-
2
chanmapname: $tester.default_channelmap, # Default is to use default_channelmap
-
site: 0, # Default is to use site 0.
-
testerconfigname: $tester.default_testerconfig # Default is to use default_testerconfig
-
}.merge(options)
-
-
2
unless $tester.channelmap[options[:chanmapname]]
-
fail "You must first import the tester channel map (e.g. $tester.channelmap = \"probe_x32\") before calling pin.channel"
-
end
-
2
unless $tester.testerconfig[options[:testerconfigname]]
-
fail "You must first import the tester configuration (e.g. $tester.testerconfig = \"UflexConfigA\") before calling pin.instrument_type"
-
end
-
-
2
if Origen.top_level.power_pin_groups.keys.include?(name) # Power Pin Groups do not need :ppmu, but need :supply
-
2
instrumentinfo = Struct.new(:channel, :instrument, :chanmapname, :site, :testerconfigname, :supply)
-
2
@channel = $tester.get_tester_channel(options[:chanmapname], name, options[:site])
-
2
@instrument = $tester.get_tester_instrument(options[:testerconfigname], $tester.get_tester_channel(options[:chanmapname], name, options[:site]).split('.')[0].to_i) + $tester.is_vhdvs_hc(options[:chanmapname], name, options[:site]).to_s + $tester.is_hexvs_plus(options[:testerconfigname], @channel.split('.')[0].to_i).to_s + $tester.is_vhdvs_plus(options[:testerconfigname], @channel.split('.')[0].to_i).to_s + $tester.merged_channels(options[:chanmapname], name, options[:site]).to_s
-
2
@supply = $tester.ate_hardware(@instrument).supply
-
2
instrumentinfo.new(@channel, @instrument, options[:chanmapname], options[:site], options[:testerconfigname], @supply)
-
else # Collecting information of individual members and put in arrays
-
instrumentinfo = Struct.new(:members, :channel, :instrument, :chanmapname, :site, :testerconfigname, :ppmu)
-
@members = []
-
@channel = []
-
@instrument = []
-
@ppmu = []
-
Origen.top_level.pin_groups(name).map(&:id).each do |pinname|
-
@members << Origen.top_level.pins(pinname).name
-
@channel << $tester.get_tester_channel(options[:chanmapname], Origen.top_level.pins(pinname).name, options[:site])
-
@instrument << $tester.get_tester_instrument(options[:testerconfigname], $tester.get_tester_channel(options[:chanmapname], Origen.top_level.pins(pinname).name, options[:site]).split('.')[0].to_i)
-
@ppmu << $tester.ate_hardware($tester.get_tester_instrument(options[:testerconfigname], $tester.get_tester_channel(options[:chanmapname], Origen.top_level.pins(pinname).name, options[:site]).split('.')[0].to_i)).ppmu
-
end
-
instrumentinfo.new(@members, @channel, @instrument, options[:chanmapname], options[:site], options[:testerconfigname], @ppmu)
-
end
-
end
-
end
-
end
-
end
-
2
require 'origen/pins/timing'
-
-
2
module Origen
-
2
module Pins
-
2
module Timing
-
2
def current_timeset_period=(p)
-
2
if OrigenTesters::Timing.timeset.nil?
-
1
Origen.app!.fail!(
-
exception_class: OrigenTesters::Timing::InvalidModification,
-
message: 'No current timeset has been defined! Cannot update the current timeset period!'
-
)
-
else
-
1
OrigenTesters::Timing.set_timeset(tester.timeset, p)
-
end
-
end
-
2
alias_method :current_period_in_ns=, :current_timeset_period=
-
-
2
def current_timeset=(t)
-
1
OrigenTesters::Timing.set_timeset(t)
-
end
-
2
alias_method :timeset=, :current_timeset=
-
-
# Returns the current timeset period
-
2
def current_timeset_period
-
144
OrigenTesters::Timing.period_in_ns
-
end
-
2
alias_method :current_period_in_ns, :current_timeset_period
-
-
# Returns the current timeset in seconds
-
# @return [Float] Current period in seconds
-
2
def current_period_in_secs
-
OrigenTesters::Timing.period_in_secs
-
end
-
2
alias_method :current_period_in_seconds, :current_period_in_secs
-
-
# Returns the current timeset
-
2
def current_timeset
-
128
OrigenTesters::Timing.timeset
-
end
-
-
# If a block is given, defines/redefines the timeset.
-
# If a name is given, retrieves that timeset.
-
# Otherwise, returns the current timeset.
-
2
def timeset(*args, &block)
-
47
if block_given?
-
20
timesets(*args, &block)
-
else
-
27
if args.first
-
timesets(args.first)
-
else
-
27
OrigenTesters::Timing.timeset
-
end
-
end
-
end
-
end
-
end
-
end
-
2
require 'origen/pins/timing/timeset'
-
-
2
module Origen
-
2
module Pins
-
2
module Timing
-
2
class Timeset
-
2
attr_reader :_timeset_
-
-
# Bind to the original initialize method in Origen and add registering
-
# the DUT timeset to the tester.
-
2
@orig_init = instance_method(:initialize)
-
2
define_method(:initialize) do |*args|
-
520
self.class.instance_variable_get(:@orig_init).bind(self).call(*args)
-
520
instance_variable_set(:@_timeset_, OrigenTesters::Timing.lookup_or_register_timeset(self))
-
end
-
-
# Defer any missing methods to the corresponding timeset object on the tester side.
-
# If the method isn't found their either, raise the standard NoMethod error.
-
2
def method_missing(m, *args, &block)
-
64
if _timeset_.respond_to?(m)
-
64
_timeset_.send(m, *args, &block)
-
else
-
super
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Parser
-
2
autoload :SearchableArray, 'origen_testers/parser/searchable_array'
-
2
autoload :SearchableHash, 'origen_testers/parser/searchable_hash'
-
2
autoload :DescriptionLookup, 'origen_testers/parser/description_lookup'
-
-
2
def parse(*args, &block)
-
parser.parse(*args, &block)
-
end
-
-
# Returns a SearchableArray containing all tests parsed from flows, this is intended to
-
# be the main API for accessing parsed test program attributes and should be a consistent
-
# method that is implemented accross all tester models.
-
#
-
# Direct access to the underlying structure (which will be specific to the tester model)
-
# can be achieved through the parser method, which returns an instance of J750::Parser
-
# $tester.parser.test_instances
-
2
def tests
-
parser.flow_items
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Parser
-
2
class DescriptionLookup
-
2
def initialize
-
2
@store = { flow: {}, test: {}, usage: {} }
-
end
-
-
2
def for_flow(name, options = {})
-
k = flow_key(name)
-
@store[:flow][k] || []
-
end
-
-
2
def for_test_definition(name, options = {})
-
n = name_key(name)
-
@store[:test][n] || []
-
end
-
-
2
def for_test_usage(name, flow, options = {})
-
k = flow_key(flow)
-
n = name_key(name)
-
@store[:usage][k] ||= {}
-
@store[:usage][k][n] || []
-
end
-
-
2
def add_for_flow(flow, description, options = {})
-
155
k = flow_key(flow)
-
155
@store[:flow][k] ||= []
-
155
[description].flatten.each do |d|
-
@store[:flow][k] << d
-
end
-
end
-
-
2
def add_for_test_definition(test, description, option = {})
-
978
n = name_key(test)
-
978
@store[:test][n] ||= []
-
978
[description].flatten.each do |d|
-
@store[:test][n] << d
-
end
-
end
-
-
2
def add_for_test_usage(test, flow, description, option = {})
-
k = flow_key(flow)
-
n = name_key(test)
-
@store[:usage][k] ||= {}
-
@store[:usage][k][n] ||= []
-
[description].flatten.each do |d|
-
@store[:usage][k][n] << d
-
end
-
end
-
-
2
private
-
-
2
def flow_key(flow)
-
155
Pathname.new(flow).basename('.*').to_s
-
end
-
-
2
def name_key(name)
-
978
name.to_s.downcase
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module PatternCompilers
-
2
require 'origen_testers/pattern_compilers/base'
-
2
require 'origen_testers/pattern_compilers/igxl_based'
-
2
require 'origen_testers/pattern_compilers/ultraflex'
-
2
require 'origen_testers/pattern_compilers/j750'
-
2
require 'origen_testers/pattern_compilers/v93k'
-
-
PLATFORMS = {
-
2
ultraflex: 'UltraFLEX',
-
j750: 'J750',
-
v93k: 'V93K'
-
}
-
-
# Hash wrapper for compiler instances, defaults to display currently enabled tester platform.
-
# If no tester is set then user must supply a valid tester platform argument
-
# User can also supply alternate tester platform (i.e. not the current tester target)
-
# pattern_compilers() => hash of compilers for current tester platform
-
# pattern_compilers(id1) => inspect options of compiler 'id1' for current tester platfrom
-
# pattern_compiler(platform: :v93k) => hash of compilers for specified tester platfrom (v93k)
-
# pattern_compiler(id2, platform: :v93k) => inspect options of compiler 'id2' for specified tester platfrom (v93k)
-
2
def pattern_compilers(id = nil, options = {})
-
241
id, options = nil, id if id.is_a? Hash
-
241
plat = options[:platform] || platform # use platform option or current tester platform
-
-
# Build up empty hash structure for all supported plaforms
-
240
@pattern_compilers ||= begin
-
15
hash = {}
-
60
PLATFORMS.keys.each { |p| hash[p] = {} }
-
15
hash
-
end
-
-
240
@default_pattern_compiler ||= begin
-
15
hash = {}
-
60
PLATFORMS.keys.each { |p| hash[p] = nil }
-
15
hash
-
end
-
-
240
if id.nil?
-
236
@pattern_compilers[plat]
-
else
-
4
@pattern_compilers[plat][id].inspect_options
-
end
-
end
-
# alias_method :compilers, :pattern_compilers # DEPRECATING
-
-
# Add a compiler for a particular tester platform and pattern type
-
2
def add_pattern_compiler(id, plat, options = {})
-
49
pattern_compilers
-
49
id = id.to_sym
-
49
plat = plat.to_sym
-
49
options[:location] = options[:location].to_sym unless options[:location].nil?
-
-
49
verify_unique_platform_id(id, plat) # do not allow duplicate ids for a given platform
-
47
@pattern_compilers[plat][id] = platform_compiler(plat).new(id, options)
-
-
35
default = options[:default] || false
-
35
@default_pattern_compiler[plat] = id if default
-
end
-
# alias_method :add_compiler, :add_pattern_compiler # DEPRECATING
-
-
# Get the default pattern compiler for the current of speficied platform
-
2
def default_pattern_compiler(p = platform)
-
10
@default_pattern_compiler[p.to_sym]
-
end
-
-
# Set a (already created) pattern compiler as the default for current or specified platform
-
2
def set_default_pattern_compiler(id, p = platform)
-
3
@default_pattern_compiler[p.to_sym] = id
-
end
-
-
# All platforms that have supported pattern compilers (returns Array)
-
2
def pattern_compiler_platforms
-
1
PLATFORMS.keys.sort
-
end
-
# alias_method :compiler_platforms, :pattern_compiler_platforms # DEPRECATING
-
-
# Delete all pattern compiler instances for a given platform. If no
-
# argument default to current platform
-
2
def delete_pattern_compilers(p = platform)
-
5
@pattern_compilers[p].delete_if { |k, v| true }
-
end
-
# alias_method :delete_compilers, :delete_pattern_compilers # DEPRECATING
-
-
# Delete a pattern compiler instance.
-
2
def delete_pattern_compiler(id, p = platform)
-
3
@pattern_compilers[p].delete(id)
-
end
-
# alias_method :delete_compiler, :delete_pattern_compiler # DEPRECATING
-
-
# Check compiler instance name is unique for given platform
-
2
def verify_unique_platform_id(id, platform, options = {})
-
49
if @pattern_compilers[platform].keys.include? id
-
1
fail_msg = "Compiler ID #{id} for platform #{platform} already exists! "
-
1
fail_msg += 'Pick another name, delete the compiler, or clear all compilers'
-
1
fail fail_msg
-
end
-
end
-
-
# Returns an array of the pattern compiler instance ids
-
# for the currently selected tester platform.
-
2
def pattern_compiler_instances(p = platform)
-
# Check if nil which means no tester is defined so ask user to supply it
-
10
if p.nil?
-
1
fail "No tester platform defined, supply one of the following as an argument: #{PLATFORMS.keys.sort.join(', ')}"
-
end
-
9
p = p.to_sym
-
9
@pattern_compilers[p].keys
-
end
-
# alias_method :compiler_instances, :pattern_compiler_instances # DEPRECATING
-
-
# Return the Compiler Class of the current or specified platform
-
2
def platform_compiler(p = platform)
-
50
if pattern_compiler_supported?(p)
-
49
"OrigenTesters::PatternCompilers::#{PLATFORMS[p]}PatternCompiler".constantize
-
else
-
1
fail "Platform #{platform} is not valid, please choose from #{PLATFORMS.keys.sort.join(', ')}"
-
end
-
end
-
-
# Execute the compiler with 'help' switch
-
2
def pattern_compiler_options(p = platform)
-
1
system("#{platform_compiler(p).compiler_options}")
-
end
-
# alias_method :compiler_options, :pattern_compiler_options # DEPRECATING
-
-
# Execute the compiler with 'version' swtich
-
2
def pattern_compiler_version(p = platform)
-
1
system("#{platform_compiler(p).compiler_version}")
-
end
-
# alias_method :compiler_version, :pattern_compiler_version # DEPRECATING
-
-
# Check if the current tester is supported
-
2
def pattern_compiler_supported?(p = platform)
-
50
PLATFORMS.keys.include?(p) ? true : false
-
end
-
# alias_method :compiler_supported?, :pattern_compiler_supported? # DEPRECATING
-
-
2
private
-
-
# # Check if the current tester is an Ultraflex
-
# def is_ultraflex?
-
# platform == :ultraflex ? true : false
-
# end
-
-
# # Check if the current tester is an Ultraflex
-
# def is_j750?
-
# platform == :j750 ? true : false
-
# end
-
-
# # Check if the current tester is an Ultraflex
-
# def is_v93k?
-
# platform == :v93k ? true : false
-
# end
-
-
# Return the current tester target
-
2
def platform
-
243
if tester.nil?
-
1
fail 'No tester instantiated, $tester is set to nil'
-
else
-
242
tester.class.to_s.downcase.split('::').last.to_sym
-
end
-
end
-
-
# # Check if a target has been set
-
# def target_enabled?
-
# Origen.target.name.nil? ? true : false
-
# end
-
end
-
end
-
2
module OrigenTesters
-
2
module PatternCompilers
-
2
class BasePatternCompiler
-
2
private
-
-
# Check the file extension of a file, return status can be 'atp', 'avc', 'list', or nil
-
2
def check_file_ext(file)
-
66
status = nil
-
66
ext = file.extname
-
66
name = file.basename
-
66
if ext == '.atp'
-
20
status = 'atp'
-
46
elsif ext == '.avc'
-
32
status = 'avc'
-
14
elsif ext == '.gz'
-
# Ensure we have a .atp.gz or .avc.gz
-
4
sub_ext = name.to_s.split('.')[-2]
-
4
if sub_ext == 'atp'
-
2
status = 'atp'
-
end
-
10
elsif ext == '.list'
-
4
status = 'list'
-
end
-
66
status
-
end
-
-
# Parse a pattern list file recursively until all .atp or .atp.gz files are found
-
2
def parse_list(path, files)
-
4
list_name = path.basename
-
4
dir = path.dirname
-
4
line_number = 0
-
4
path.open('r') do |f|
-
22
while (line = f.gets)
-
14
line_number += 1
-
# Strip the leading and trailing whitespace for sloppy typers
-
14
line.strip!
-
# Skip a blank line
-
14
next if line.match(/^\s+$/)
-
# Check if the pattern or list exists
-
14
line_path = Pathname.new("#{dir}/#{line}")
-
14
unless line_path.file?
-
# puts "Skipping #{line_path.to_s} at line ##{line_number} in file #{path.to_s} because it is not a file"
-
2
next
-
end
-
# Process the file
-
12
process_file(line_path, files)
-
end
-
end
-
end
-
-
# Processes a file looking for a valid .atp or .list
-
2
def process_file(file, files)
-
# puts "processing file #{file.to_s}"
-
66
case check_file_ext(file)
-
when 'atp'
-
22
files << file unless files.include?(file)
-
when 'avc'
-
32
files << file unless files.include?(file)
-
when 'list'
-
4
parse_list(file, files)
-
end
-
end
-
-
# Processes a diretcory looking for files in '.' or recursively
-
2
def process_directory(dir, files, rec)
-
7
dir.children(true).each do |f|
-
# ignore sub-directories
-
37
if f.directory?
-
5
if rec == false
-
3
next
-
else
-
2
process_directory(f.expand_path, files, rec)
-
end
-
end
-
34
process_file(f.expand_path, files)
-
end
-
end
-
-
# Deletes the pattern compiler log files
-
2
def clean_output
-
6
@jobs.each do |job|
-
19
logfile = Pathname.new("#{job.pattern.dirname}/#{job.pattern.basename.to_s.chomp(job.pattern.extname)}.log")
-
19
logfile.cleanpath
-
19
if logfile.file?
-
# puts "Deleting log file #{logfile}"
-
16
logfile.delete
-
end
-
end
-
end
-
end
-
end
-
end
-
2
require 'digest/md5'
-
2
module OrigenTesters
-
2
module PatternCompilers
-
2
class BasePatternCompiler
-
2
require 'origen_testers/pattern_compilers/assembler'
-
2
require 'origen_testers/pattern_compilers/job'
-
-
# ID will allow users to set default configurations for the compiler for unique pattern types
-
2
attr_accessor :id
-
-
# Compiler commands array
-
2
attr_accessor :jobs
-
-
2
def initialize(id, options = {})
-
47
unless Origen.site_config.origen_testers
-
1
fail 'Adding a pattern compiler without site config specifying bin location not allowed'
-
end
-
-
46
@id = id.to_sym
-
-
# The following are pattern compiler options that are common between all platforms, the specific platforms
-
# can add on additional options in their respective initialize methods.
-
@user_options = {
-
46
path: nil, # required: will be passed in or parsed from a .list file
-
reference_directory: nil, # optional: will be set to @path or Origen.app.config.pattern_output_directory
-
target: nil, # optional: allows user to temporarily set target and run compilation
-
recursive: false, # optional: controls whether to look for patterns in a directory recursively
-
}
-
-
@job_options = {
-
46
id: @id, # required
-
location: :local, # optional: controls whether the commands go to the LSF or run locally
-
clean: false, # optional: controls whether compiler log files are deleted after compilation
-
output_directory: nil, # optional:
-
verbose: false, # optional: controls whether the compiler output gets put to STDOUT
-
}
-
46
@compiler_options = {}
-
46
@compiler_options_with_args = {}
-
-
# Compiler jobs
-
46
@jobs = []
-
46
@files = []
-
end
-
-
# Return the id/name of the compiler instance
-
2
def name
-
1
@id
-
end
-
-
# Returns the number of jobs in the compiler
-
2
def count
-
14
@jobs.size
-
end
-
-
# Checks if the compiler queue is empty
-
2
def empty?
-
61
@jobs.empty?
-
end
-
-
# Allow users to search for a pattern in the job queue or default to return all jobs
-
2
def jobs(search = nil)
-
13
found = false
-
13
if search.nil?
-
1
inspect_jobs
-
1
found = true
-
12
elsif search.is_a? String
-
3
@jobs.each_with_index do |job, index|
-
4
if job.pattern.to_s.match(search)
-
3
inspect_jobs(index)
-
3
found = true
-
else
-
1
puts "No match found for #{search}"
-
end
-
end
-
9
elsif search.is_a? Regexp
-
4
@jobs.each_with_index do |job, index|
-
6
if search.match(job.pattern.to_s)
-
3
inspect_jobs(index)
-
3
found = true
-
else
-
3
puts "No match found for #{search}"
-
end
-
end
-
5
elsif search.is_a? Integer
-
4
if @jobs[search].nil?
-
2
puts "The compiler queue does not contain a job at index #{search}"
-
else
-
2
inspect_jobs(search)
-
2
found = true
-
end
-
else
-
1
fail 'Search argument must be of type String, Regexp, or Integer'
-
end
-
12
found
-
end
-
-
# Clear the job queue
-
2
def clear
-
23
@jobs = []
-
23
@files = []
-
end
-
-
2
def platform
-
17
if tester.nil?
-
fail 'No tester instantiated, $tester is set to nil'
-
else
-
17
tester.class.to_s.downcase.split('::').last.to_sym
-
end
-
end
-
-
# Check if the current tester is an Ultraflex
-
2
def is_ultraflex?
-
6
platform == :ultraflex ? true : false
-
end
-
-
# Check if the current tester is an J750
-
2
def is_j750?
-
2
platform == :j750 ? true : false
-
end
-
-
# Check if the current tester is an V93K
-
2
def is_v93k?
-
9
platform == :v93k ? true : false
-
end
-
-
# Output the compiler options to the console
-
2
def inspect_options(verbose = nil)
-
2
desc = []
-
# Find the longest option argument string
-
2
my_job_options = @job_options
-
2
my_job_options.delete(:compiler)
-
2
all_arguments = @user_options.values + my_job_options.values + @compiler_options.values + @compiler_options_with_args.values
-
2
min_argument_padding = 'Argument'.length + 2
-
61
argument_padding = all_arguments.max_by { |e| e.to_s.length }.to_s.length + 3
-
2
argument_padding = min_argument_padding if argument_padding < min_argument_padding
-
2
puts "\n"
-
2
header = '| Option ' + '| Argument'.ljust(argument_padding) + '| Required |'
-
2
desc << header
-
2
desc << '-' * header.length
-
2
[@user_options, my_job_options, @compiler_options, @compiler_options_with_args].each do |opt|
-
8
opt.each_pair do |k, v|
-
59
if k.match(/pinmap_workbook|path|id|directory|clean|location|recursive/i)
-
15
req = 'true '
-
else
-
44
next if v.nil? || v == false
-
7
req = 'false'
-
end
-
22
desc << "| #{k}".ljust(22) + "| #{v}".ljust(argument_padding) + "| #{req} |"
-
end
-
end
-
2
puts desc
-
end
-
-
2
private
-
-
2
def update_common_options(options = {})
-
46
@user_options.update_common(options)
-
46
@job_options.update_common(options)
-
46
@compiler_options.update_common(options)
-
46
@compiler_options_with_args.update_common(options)
-
end
-
-
2
def clean_and_verify_options
-
35
verify_exclusive_compiler_options
-
35
clean_path_options
-
35
set_reference_directory
-
35
create_output_directory
-
-
# Logfile is optional
-
35
unless @compiler_options[:logfile].nil?
-
@compiler_options[:logfile] = convert_to_pathname(@compiler_options[:logfile])
-
end
-
-
# Check if the LSF is setup in the application
-
35
if Origen.app.config.lsf.project.nil? || Origen.app.config.lsf.project.empty?
-
35
msg = 'LSF is not set at Origen.app.config.lsf.project, changing to local compilation'
-
35
Origen.log.warn msg
-
35
@job_options[:location] = :local
-
end
-
end
-
-
# Check to make sure @compiler_options and @compiler_options_with_args do not have any keys in common
-
2
def verify_exclusive_compiler_options
-
35
if @compiler_options.intersect? @compiler_options_with_args
-
fail_msg = 'Error: @compiler_options and @compiler_options_with_args share keys '
-
fail_msg += "#{@compiler_options.intersections(@compiler_options_with_args)}. "
-
fail_msg += 'They should be mutually exclusive, exiting...'
-
fail fail_msg
-
end
-
end
-
-
2
def clean_path_options
-
35
unless @user_options[:path].nil?
-
5
if @user_options[:path].is_a? Pathname
-
@path = @user_options[:path]
-
else
-
5
@path = Pathname.new(@user_options[:path])
-
end
-
5
@path = @path.expand_path
-
# path is set but output_directory is not so set output_directory to path
-
5
@job_options[:output_directory] = @path if @job_options[:output_directory].nil?
-
end
-
end
-
-
2
def set_reference_directory
-
60
if @user_options[:reference_directory].nil?
-
# Nothing passed for reference directory so set it to @path or Origen.app.config.pattern_output_directory
-
35
if @path
-
5
if @path.directory?
-
5
@user_options[:reference_directory] = @path
-
else
-
@user_options[:reference_directory] = @path.dirname
-
end
-
else
-
# @path has not been specified, so set to Origen.app.config.pattern_output_directory (create if necessary)
-
30
if Origen.app.config.pattern_output_directory.nil?
-
fail "Something went wrong, can't create pattern compiler without output_directory"
-
else
-
30
@user_options[:reference_directory] = Pathname.new(Origen.app.config.pattern_output_directory)
-
30
unless @user_options[:reference_directory].directory?
-
FileUtils.mkdir_p(@user_options[:reference_directory])
-
end
-
end
-
end
-
25
elsif File.directory?(@user_options[:reference_directory])
-
25
@user_options[:reference_directory] = Pathname.new(@user_options[:reference_directory])
-
else
-
debug 'Reference directory not set, creating it...'
-
@user_options[:reference_directory] = Pathname.new(@user_options[:reference_directory])
-
FileUtils.mkdir_p(@user_options[:reference_directory])
-
end
-
60
@user_options[:reference_directory] = @user_options[:reference_directory].expand_path
-
# reference_directory must be a subset of @path. if it is not then set to @path if @path exists
-
60
unless @path.nil?
-
12
if @path.directory?
-
9
@user_options[:reference_directory] = @path unless @path.to_s.include? @user_options[:reference_directory].to_s
-
3
elsif @path.file?
-
3
@user_options[:reference_directory] = @path.dirname
-
else
-
fail "Path is set to #{@path} which is not a valid directory or file!"
-
end
-
end
-
end
-
-
2
def create_output_directory
-
# if output directory given, create it now, otherwise it will be created on the fly later
-
35
unless @job_options[:output_directory].nil?
-
8
@job_options[:output_directory] = convert_to_pathname(@job_options[:output_directory])
-
# output_directory can not exist, will create for user
-
8
unless @job_options[:output_directory].directory?
-
2
puts "Output directory #{@job_options[:output_directory]} does not exist, creating it..."
-
2
FileUtils.mkdir_p(@job_options[:output_directory])
-
end
-
end
-
end
-
-
2
def empty_msg
-
2
puts "No compiler jobs created, check the compiler options\n" if self.empty?
-
end
-
-
2
def convert_to_pathname(opt)
-
29
if opt.is_a? String
-
28
opt = Pathname.new(opt)
-
28
opt = opt.expand_path
-
1
elsif opt.is_a? Pathname
-
1
opt = opt.expand_path
-
else
-
fail "Option #{opt} is not a String, cannot convert to Pathname"
-
end
-
29
opt
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module PatternCompilers
-
2
class IGXLBasedPatternCompiler < BasePatternCompiler
-
2
def initialize(id, options = {})
-
16
super
-
-
# The following are pattern compiler options that are common between all IGXL platforms, these
-
# are added onto the base options. Specifc IGXL platforms can add on additional options
-
# in their respective initialize methods.
-
16
@user_options = {}.merge(@user_options)
-
-
@job_options = {
-
16
pinmap_workbook: dut.pinmap, # required: will default to $dut.pinmap
-
}.merge(@job_options)
-
-
# These are compiler options that are common to both the UltraFLEX and J750 compilers
-
# Set all of these compiler options that don't have args to true/flase. if true then send compiler '-opt'
-
@compiler_options = {
-
16
comments: false, # preserves comments in pattern binary
-
cpp: false, # runs C++ preprocessor on pattern file
-
debug: false, # generate intermediate file(s) to simplify debug ( application dependent )
-
import_all_undefineds: false, # automatically import all undefined symbols. the key is mis-spelled but correct!
-
suppress_log: false, # disables output to main log file
-
template: false, # generate setup template
-
timestamp: false, # enable log timestamp
-
}.merge(@compiler_options)
-
-
# These are compiler options that are common to both the UltraFLEX and J750 compilers
-
@compiler_options_with_args = {
-
16
define: nil, # Define macro values to be passed to C-preprocessor
-
digital_inst: nil, # Name of digital instrument
-
logfile: nil, # Messages go to <filename> instead of <infile> log
-
opcode_mode: nil, # Patgen opcode mode, specific to digital instrument
-
output: nil, # Name of output file
-
pinmap_sheet: nil, # Name of workbook containing pinmap
-
# pinmap_workbook: nil, # Name of sheet in workbook which contains pinmap (moved to @job_options)
-
setup: nil, # path to setup file
-
}.merge(@compiler_options_with_args)
-
end
-
-
2
def verify_pinmap_is_specified
-
16
if @job_options[:pinmap_workbook].nil?
-
# Check if the app has dut.pinmap defined
-
3
if dut.pinmap && File.exist?(dut.pinmap)
-
1
@job_options[:pinmap_workbook] = dut.pinmap
-
else
-
2
fail 'Pinmap is not defined! Pass as an option or set $dut.pinmap.'
-
end
-
end
-
14
@job_options[:pinmap_workbook] = convert_to_pathname(@job_options[:pinmap_workbook])
-
14
fail 'Pinmap is not a file!' unless @job_options[:pinmap_workbook].file?
-
end
-
-
# Return the compiler instance pinmap
-
2
def pinmap
-
2
@job_options[:pinmap_workbook]
-
end
-
-
# Executes the compiler for each job in the queue
-
2
def run(list = nil, options = {})
-
# Check if there was a pattern list passed as an argument
-
# If so, then compile the patterns inside it.
-
# Otherwise compile the jobs in the queue
-
8
if list.nil?
-
7
if empty?
-
1
empty_msg
-
1
return
-
end
-
6
@jobs.each do |job|
-
19
fail "Error: compiler #{job.id} not ready for pattern #{job.name}" unless job.ready?
-
19
if job.location == :lsf
-
Origen.app.lsf.submit(ATPC_SETUP + '; ' + job.cmd)
-
else
-
19
Origen.profile "Linux pattern compiler compiles pattern #{job.pattern}" do
-
19
system job.cmd
-
end
-
end
-
end
-
6
if @job_options[:location] == :local
-
6
if @job_options[:clean] == true
-
5
puts 'Log file :clean option set to true, deleting log files'
-
5
clean_output
-
end
-
end
-
# Clear @jobs
-
6
clear
-
else
-
1
list = convert_to_pathname(list)
-
1
fail "Error: pattern list #{list} does not exist, exiting..." unless list.file?
-
1
File.open(list, 'r') do |file|
-
5
while (line = file.gets)
-
3
current_job_options = @job_options.merge(@compiler_options_with_args)
-
3
current_job_options.update_common(options)
-
# puts "current job options is #{current_job_options}"
-
3
compiler_opts = {}
-
3
line.strip!
-
3
pattern = line.match(/^(\S+)\s+(.*)/).captures[0]
-
3
unless File.file? pattern
-
puts "Warning: Pattern #{pattern} does not exist, skipping..."
-
next
-
end
-
3
pattern = convert_to_pathname(pattern)
-
3
line.match(/^\S+\s+(.*)/).captures[0].split(/\s+/).each do |e|
-
9
opt, arg = e.split(':')
-
9
opt.gsub!('-', '')
-
9
if arg.nil?
-
compiler_opts[opt.to_sym] = true
-
else
-
# Check for some specific options
-
9
case opt
-
when 'pinmap_workbook'
-
3
current_job_options[opt.to_sym] = Pathname.new(arg)
-
when 'output'
-
3
dot_pat = Pathname.new(arg)
-
3
current_job_options[:output_directory] = dot_pat.dirname
-
else
-
3
current_job_options[opt.to_sym] = arg
-
end
-
end
-
end
-
3
@jobs << Job.new(pattern, current_job_options, compiler_opts)
-
3
inspect_jobs
-
end
-
end
-
1
run
-
# Clear @jobs
-
1
clear
-
end
-
end
-
-
# Finds the patterns and creates a compiler job for each one found.
-
# Handles singles files (.atp, .atp.gz, or .list) and directories (recursively or flat)
-
2
def find_jobs(path = @path)
-
8
fail 'Pattern path is set to nil, pass in a valid file (.atp or .atp.gz) or a valid directory' if path.nil?
-
7
@path = Pathname.new(path)
-
7
fail 'Pattern path does not exist, pass in a valid file (.atp or .atp.gz) or a valid directory' unless @path.exist?
-
7
@path = @path.expand_path
-
# Set the reference directory for pattern sub-dir mirroring
-
7
set_reference_directory
-
7
Origen.profile 'Linux pattern compiler finds patterns' do
-
# Check if the path is a file or a directory
-
7
if @path.directory?
-
# Get all of the patterns inside this dir or inside this directory recursively
-
4
process_directory(@path, @files, @user_options[:recursive])
-
3
elsif @path.file? # Found a file so no searching is necessary
-
3
process_file(@path, @files)
-
else # Didn't find a directory or a file so user must want a search for this arg string * NOT SUPPORTED YET
-
fail 'Error: Did not find a file or directory to compile, exiting...'
-
end
-
end
-
-
7
Origen.profile 'Linux pattern compiler creates jobs' do
-
7
@files.each do |f|
-
16
rel_dir = Pathname.new("#{f.dirname.to_s[@user_options[:reference_directory].to_s.size..-1]}")
-
16
if @job_options[:output_directory].nil?
-
# job output dir not specified, create a unique (hash) based on path/compiler_name
-
s = Digest::MD5.new
-
s << @user_options[:reference_directory].to_s
-
s << @id.to_s
-
out = "#{@user_options[:reference_directory]}/job_#{@id}_#{s.to_s[0..6].upcase}#{rel_dir}"
-
output_dir = Pathname.new(out)
-
else
-
16
output_dir = Pathname.new("#{@job_options[:output_directory]}#{rel_dir}")
-
end
-
16
unless output_dir.directory?
-
2
puts "Output directory #{output_dir} for pattern #{f.basename} does not exist, creating it..."
-
2
FileUtils.mkdir_p(output_dir)
-
end
-
16
current_job_options = @job_options.merge(@compiler_options_with_args)
-
16
current_job_options[:output_directory] = output_dir
-
16
@jobs << Job.new(f, current_job_options, @compiler_options)
-
16
current_job_options = {}
-
end
-
end
-
7
@files = []
-
7
if empty?
-
empty_msg
-
else
-
7
inspect_jobs
-
end
-
end
-
-
# Output all of the jobs into a pattern list so it can be compiled later
-
# Must be executed after the 'find_jobs' method and before the 'run' method
-
# or @jobs will be empty
-
2
def to_list(options = {})
-
options = {
-
1
name: @id,
-
output_directory: Dir.pwd,
-
expand: true,
-
force: false
-
}.update_common(options)
-
1
list = "#{options[:output_directory]}/#{options[:name]}.list"
-
1
list = convert_to_pathname(list)
-
1
if empty?
-
empty_msg
-
return
-
end
-
1
if list.file?
-
if options[:force] == true
-
puts "Pattern list file #{list} already exists, deleting it..."
-
list.delete
-
else
-
fail "Pattern list file #{list} already exists, exiting..."
-
end
-
end
-
1
File.open(list, 'w') do |patlist|
-
1
@jobs.each do |job|
-
3
if options[:expand] == true
-
3
pinmap = job.pinmap_workbook
-
3
dot_pat_name = "#{job.output_directory}/#{job.pattern.basename.to_s.split('.').first}.PAT"
-
3
dot_atp_name = job.pattern
-
else
-
pinmap = job.pinmap_workbook.basename
-
dot_pat_name = "#{job.pattern.basename.to_s.split('.').first}.PAT"
-
dot_atp_name = job.pattern.basename
-
end
-
3
patlist.print("#{dot_atp_name} -pinmap_workbook:#{pinmap} -output:#{dot_pat_name}")
-
3
job.compiler_options.each_key { |k| patlist.print(" -#{k}") }
-
6
job.compiler_options_with_args.each_pair { |k, v| patlist.print(" -#{k}:#{v}") }
-
3
patlist.puts('')
-
end
-
end
-
end
-
-
# alias_method :find, :find_jobs
-
#
-
# Output the compiler jobs in the queue to the console
-
2
def inspect_jobs(index = nil)
-
18
return empty_msg if empty?
-
18
desc = []
-
18
puts "\n"
-
18
@jobs.each_with_index do |j, i|
-
38
unless index.nil?
-
13
next unless i == index
-
end
-
33
desc << '| Job: ' + "#{i + 1} ".rjust(8) + '|' + 'Pattern:'.rjust(18) + " #{j.pattern.basename}".ljust(120) + '|'
-
33
desc << '| |' + 'Compiler ID:'.rjust(18) + " #{j.id} ".ljust(120) + '|'
-
33
desc << '| |' + 'Pinmap:'.rjust(18) + " #{j.pinmap_workbook} ".ljust(120) + '|'
-
33
desc << '| |' + '.atp directory:'.rjust(18) + " #{j.pattern.dirname} ".ljust(120) + '|'
-
33
desc << '| |' + '.pat directory:'.rjust(18) + " #{j.output_directory} ".ljust(120) + '|'
-
33
desc << '| |' + 'LSF:'.rjust(18) + " #{j.location == :lsf ? true : false} ".ljust(120) + '|'
-
33
desc << '| |' + 'Delete log files:'.rjust(18) + " #{j.clean} ".ljust(120) + '|'
-
33
desc << '| |' + 'Verbose:'.rjust(18) + " #{j.verbose} ".ljust(120) + '|'
-
33
fragment = '| |' + 'Compiler args:'.rjust(18)
-
33
overflow_fragment = '| |' + ' '.rjust(18)
-
33
compiler_args = []
-
33
compiler_fragment = ''
-
33
j.compiler_options.each_key do |k|
-
4
if compiler_fragment.size + " -#{k}".size >= 120
-
compiler_args << compiler_fragment
-
compiler_fragment = nil
-
end
-
4
compiler_fragment += " -#{k}"
-
end
-
33
compiler_args << compiler_fragment unless compiler_fragment.nil?
-
33
compiler_fragment = ''
-
33
j.compiler_options_with_args.each_pair do |k, v|
-
33
if compiler_fragment.size + " -#{k}:#{v}".size >= 120
-
compiler_args << compiler_fragment
-
compiler_fragment = nil
-
end
-
33
compiler_fragment += " -#{k}:#{v}"
-
end
-
33
compiler_args << compiler_fragment unless compiler_fragment.nil?
-
33
if compiler_args.join.length <= 120
-
33
desc << fragment + "#{compiler_args.join}".ljust(120) + '|'
-
else
-
# Need to cycle through compiler args and build a fragment <= 100 characters
-
# and print it. Keep going until the remaining args is <= 100 and print again
-
char_cnt = 0
-
line_cnt = 0
-
args = []
-
compiler_args = compiler_args.join.strip.split(/\s+/)
-
until compiler_args.empty?
-
args = compiler_args.select { |e| (char_cnt += e.length + 1) < 120 }
-
# remove the args that fit on the first line
-
compiler_args -= args
-
if line_cnt == 0
-
desc << fragment + " #{args.join(' ')}".ljust(120) + '|'
-
else
-
desc << overflow_fragment + " #{args.join(' ')}".ljust(120) + '|'
-
end
-
args = []
-
line_cnt += 1
-
char_cnt = 0
-
end
-
end
-
33
desc << '-' * desc.first.size
-
end
-
18
puts desc.flatten.join("\n")
-
end
-
# For future checks on incorrect or incompatible arguments to compiler options
-
2
def options_ok?
-
end
-
-
2
def ready?
-
ready = true
-
paths_contain_data = true
-
ready &= paths_contain_data
-
ready &= !@job_options[:output_directory].nil?
-
ready &= !@user_options[:reference_directory].nil?
-
ready &= !@path.nil?
-
ready &= !@job_options[:pinmap_workbook].nil?
-
ready &= @job_options[:output_directory].directory?
-
ready &= @user_options[:reference_directory].directory?
-
ready &= @path.exist?
-
ready &= @job_options[:pinmap_workbook].file?
-
ready &= [true, false].include?(@job_options[:clean])
-
ready &= [:local, :lsf].include?(@job_options[:location])
-
ready &= File.exist?(@job_options[:compiler])
-
ready
-
end
-
-
2
def bad_options
-
bad = []
-
options = {
-
output_directory: @job_options[:output_directory],
-
reference_directory: @user_options[:reference_directory],
-
path: @path,
-
pinmap_workbook: @job_options[:pinmap_workbook],
-
clean: @job_options[:clean],
-
location: @job_options[:location],
-
compiler: @job_options[:compiler]
-
}
-
options.each do |k, v|
-
bad << k if v.nil?
-
if v.is_a? String # compiler
-
v = Pathname.new(v)
-
bad << k unless v.file?
-
elsif v.is_a? Symbol # clean
-
bad << k unless [:local, :lsf].include? v
-
elsif v.is_a? Pathname
-
if k.match(/directory/)
-
bad << k unless v.directory?
-
elsif k == :path
-
bad << k unless v.exist?
-
else # pinmap
-
bad << k unless v.file?
-
end
-
end
-
end
-
bad
-
end
-
2
alias_method :bad_opts, :bad_options
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module PatternCompilers
-
2
class J750PatternCompiler < IGXLBasedPatternCompiler
-
# Linux compiler executable path
-
2
def self.linux_compiler
-
16
Origen.site_config.origen_testers[:j750_linux_pattern_compiler]
-
end
-
-
# Windows compiler executable path
-
2
def self.windows_compiler
-
1
Origen.site_config.origen_testers[:j750_windows_pattern_compiler]
-
end
-
-
# Pre-compile environment setup if necessary
-
2
def self.atpc_setup
-
1
Origen.site_config.origen_testers[:j750_atpc_setup]
-
end
-
-
# Resolves to correct compiler based on operating system
-
2
def self.compiler
-
15
Origen.running_on_windows? ? windows_compiler : linux_compiler
-
end
-
-
2
def self.compiler_cmd
-
3
Pathname.new(compiler).absolute? ? compiler : eval('"' + compiler + '"')
-
end
-
-
2
def self.compiler_options
-
1
"#{compiler_cmd} -help"
-
end
-
-
2
def self.compiler_version
-
1
"#{compiler_cmd} -version"
-
end
-
-
2
def initialize(id, options = {})
-
8
super
-
-
8
@user_options = {}.merge(@user_options)
-
-
@job_options = {
-
8
tester: :j750,
-
compiler: self.class.compiler, # required
-
}.merge(@job_options)
-
-
# These are compiler options that are specific to J750 compiler (builds on options from IGXL-Based)
-
# Set all of these compiler options that don't have args to true/flase. if true then send compiler '-opt'
-
@compiler_options = {
-
8
compress: false, # Compress the compiled output file.
-
extended: false, # Compiles the pattern for extended mode.
-
scan_parallel: false, # Expands scan vectors into parallel SVM/LVM vectors.
-
svm_only: false, # Compile all vectors in the file for SVM.
-
svm_subr_only: false, # Only SVM subroutines in file being used.
-
}.merge(@compiler_options)
-
-
# These are compiler options that are specific to J750 compiler (builds on options from IGXL-Based)
-
@compiler_options_with_args = {
-
8
i: nil, # Includes paths to be passed to C++ preprocessor.
-
lvm_size: nil, # Number of LVM vectors to allow in a single pattern.
-
max_errors: nil, # Number of errors that will cause compilation of the pattern file to be aborted.
-
min_period: nil, # Minimum period, in seconds, that will be used during a pattern burst.
-
}.merge(@compiler_options_with_args)
-
-
8
update_common_options(options) # Update common options with default (see BasePatternCompiler)
-
8
verify_pinmap_is_specified # verify pinmap specified correctly - IGXL specific
-
5
clean_and_verify_options # Standard cleaning and verifying (see BasePatternCompiler)
-
end
-
-
# Executes the compiler for each job in the queue
-
2
def run(list = nil, options = {})
-
2
fail "Error: the tester #{Origen.tester} is not an J750 tester,exiting..." unless is_j750?
-
2
msg = "Error: application #{Origen.app.name} is running on Windows, "
-
2
msg += 'to run the pattern compiler you must be on a Linux machine'
-
2
fail msg if Origen.running_on_windows?
-
-
2
super
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module PatternCompilers
-
2
class Job
-
# Pattern to be compiled, is Pathname class. Will use full path
-
2
attr_accessor :pattern
-
-
# Type of pattern as designated by the LinuxPatternCompiler
-
2
attr_accessor :id
-
-
# Where the job is to be executed, either locally ('local') or on Linux Server Farm ('lsf')
-
2
attr_accessor :location
-
-
# Controls whether the compiler log files are kept: true/false
-
2
attr_accessor :clean
-
-
# Controls whether the compiler STDOUT is displayed
-
2
attr_accessor :verbose
-
-
# Output directory for the .PAT file
-
2
attr_accessor :output_directory
-
-
# Pinmap file (IGXL-Based)
-
2
attr_accessor :pinmap_workbook
-
-
# Pin Config file (Smartest-Based)
-
2
attr_accessor :pinconfig
-
-
# Pattern input dir (Smartest-Based)
-
2
attr_accessor :avc_dir
-
-
# Pattern output dir (Smartest-Based)
-
2
attr_accessor :binl_dir
-
-
# Pattern count - should be 1 for IGXL; number of AVC files listed in AIV file for Smartest
-
2
attr_accessor :count
-
-
# tmf file (Smartest-Based)
-
2
attr_accessor :tmf
-
-
# aiv2b options (Smartest-Based)
-
2
attr_accessor :aiv2b_opts
-
-
# Compiler options where only the opt has to be passed as '-opt'
-
2
attr_accessor :compiler_options
-
-
# Compiler options where an opt and an arg have to be passed '-opt:arg'
-
2
attr_accessor :compiler_options_with_args
-
-
# linux compiler full path
-
2
attr_reader :compiler
-
-
2
def initialize(pattern, options_with_args, options)
-
36
@pattern = pattern
-
36
@tester = options_with_args.delete(:tester)
-
36
@compiler = options_with_args.delete(:compiler)
-
36
@id = options_with_args.delete(:id)
-
36
@location = options_with_args.delete(:location)
-
36
@clean = options_with_args.delete(:clean)
-
36
@verbose = options_with_args.delete(:verbose)
-
36
@output_directory = options_with_args.delete(:output_directory)
-
36
@pinmap_workbook = options_with_args.delete(:pinmap_workbook)
-
36
@pinconfig = options_with_args.delete(:pinconfig)
-
36
@avc_dir = options_with_args.delete(:avc_dir)
-
36
@binl_dir = options_with_args.delete(:binl_dir)
-
36
@count = options_with_args.delete(:count) || 1
-
36
@tmf = options_with_args.delete(:tmf)
-
36
@aiv2b_opts = options_with_args.delete(:aiv2b_opts)
-
467
@compiler_options_with_args = options_with_args.delete_if { |k, v| v.nil? } # Whatever's left has to be valid compiler options
-
92
@compiler_options = options.delete_if { |k, v| v == false }
-
end
-
-
2
def name
-
@pattern.basename
-
end
-
-
2
def cmd
-
25
cmd = ''
-
25
case @tester
-
when :v93k
-
6
cmd = "#{resolve_compiler_location} #{@pattern} "
-
when :ultraflex, :j750
-
19
cmd = "#{resolve_compiler_location} -pinmap_workbook:#{@pinmap_workbook} -output:#{@output_directory}/#{@pattern.basename.to_s.split('.').first}.PAT #{@pattern} "
-
# add in any remaining compiler options
-
20
compiler_options.each_key { |k| cmd += "-#{k} " }
-
38
compiler_options_with_args.each_pair { |k, v| cmd += "-#{k}:#{v} " }
-
else
-
fail 'Unsupported tester'
-
end
-
25
if @verbose
-
11
cmd += ';'
-
else
-
14
cmd += '2>&1 > /dev/null;'
-
end
-
# If the job is to be run on the LSF add in the clean .log and mv the files if necessary
-
25
if @location == 'lsf'
-
cmd += clean_lsf if @clean == true
-
end
-
25
cmd
-
end
-
-
2
def resolve_compiler_location
-
25
Pathname.new(@compiler).absolute? ? @compiler : eval('"' + @compiler + '"')
-
end
-
-
2
def ready?
-
24
ready = true
-
24
ready &= @output_directory.directory?
-
24
ready &= @pattern.file?
-
24
ready &= @pinmap_workbook.file? if @tester == :ultraflex || @tester == :j750
-
24
ready &= @pinconfig.file? if @tester == :v93k
-
24
ready &= @tmf.file? if @tester == :v93k
-
24
ready &= [true, false].include?(@clean)
-
24
ready &= [:local, :lsf].include?(@location)
-
24
ready
-
end
-
-
2
private
-
-
2
def orig_dir
-
@pattern.dirname
-
end
-
-
# Generates the LSF commands to delete the pattern compiler log files
-
2
def clean_lsf
-
cmd = ''
-
logfile = Pathname.new("#{@pattern.dirname}/#{@pattern.basename.to_s.split('.').first}.log")
-
logfile.cleanpath
-
logfile.cleanpath
-
if @clean == true
-
cmd += "rm #{logfile}; "
-
end
-
cmd
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module PatternCompilers
-
2
module Runner
-
# Run the pattern (or list) through the (specified) compiler
-
2
def self.run_compiler(pattern, options = {})
-
7
compiler = nil
-
7
if options[:compiler_instance]
-
3
compiler = options[:compiler_instance]
-
3
unless dut.pattern_compilers.include? compiler
-
1
fail_msg = "Pattern Compiler instance '#{compiler}' does not exist for this tester, "
-
1
fail_msg += "choose from \(#{dut.pattern_compilers.keys.join(', ')}\) or change tester target."
-
1
fail fail_msg
-
end
-
else
-
4
if dut.pattern_compilers.count == 1
-
# Only one compiler defined (for current platform), use that one
-
1
compiler = dut.pattern_compilers.keys[0]
-
else
-
# Multiple compilers defined, used one assigned to default or named :default, otherwise fail
-
3
if dut.default_pattern_compiler
-
1
compiler = dut.default_pattern_compiler
-
2
elsif dut.pattern_compilers.keys.include? :default
-
1
compiler = :default
-
else
-
1
fail_msg = "No 'default' Pattern Compiler defined, choose from "
-
1
fail_msg += "\(#{dut.pattern_compilers.keys.join(', ')}\) or set one to be the default."
-
1
fail fail_msg
-
end
-
end
-
end
-
-
5
Origen.log.info "Compiling... #{pattern}"
-
-
# Everything is verified and ready, last thing to do is COMPILE
-
5
dut.pattern_compilers[compiler].find_jobs(pattern)
-
5
dut.pattern_compilers[compiler].run
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module PatternCompilers
-
2
class UltraFLEXPatternCompiler < IGXLBasedPatternCompiler
-
# Linux compiler executable path
-
2
def self.linux_compiler
-
16
Origen.site_config.origen_testers[:uflex_linux_pattern_compiler]
-
end
-
-
# Windows compiler executable path
-
2
def self.windows_compiler
-
1
Origen.site_config.origen_testers[:uflex_windows_pattern_compiler]
-
end
-
-
# Pre-compile environment setup if necessary
-
2
def self.atpc_setup
-
1
Origen.site_config.origen_testers[:uflex_atpc_setup]
-
end
-
-
# Resolves to correct compiler based on operating system
-
2
def self.compiler
-
15
Origen.running_on_windows? ? windows_compiler : linux_compiler
-
end
-
-
2
def self.compiler_cmd
-
3
Pathname.new(compiler).absolute? ? compiler : eval('"' + compiler + '"')
-
end
-
-
2
def self.compiler_options
-
1
"#{compiler_cmd} -help"
-
end
-
-
2
def self.compiler_version
-
1
"#{compiler_cmd} -version"
-
end
-
-
2
def initialize(id, options = {})
-
8
super
-
-
8
@user_options = {}.merge(@user_options)
-
-
@job_options = {
-
8
tester: :ultraflex,
-
compiler: self.class.compiler, # required
-
}.merge(@job_options)
-
-
# These are compiler options that are specific to UltraFLEX (builds on options from IGXL-Based)
-
# Set all of these compiler options that don't have args to true/flase. if true then send compiler '-opt'
-
@compiler_options = {
-
8
lock: false, # prevents pattern from being reverse compiled or opened in PatternTool
-
multiinst: false, # indicates more than one instrument is connected to a single pin
-
nocompress: false, # do not compress pattern data blocks
-
stdin: false, # Compile data from standard input. Do not use -cpp or specify any pattern file(s) when using this option.
-
}.merge(@compiler_options)
-
-
# These are compiler options that are specific to UltraFLEX (builds on options from IGXL-Based)
-
@compiler_options_with_args = {
-
8
pat_version: nil, # version of pattern file to compile
-
scan_type: nil, # type of scan data
-
includes: nil, # include paths to be passed to C- preprocessor.
-
post_processor: nil, # <pathname> customer's post-process executable.
-
post_processor_args: nil, # <args> customer's post-process executable arguments
-
cdl_cache: nil, # 'yes' | 'no', turns on/off CDL caching, default on compiler side is 'yes'
-
init_pattern: nil, # <pattern>, uses the specified pattern module/file/set as an init patterns
-
check_set_msb: nil, # 'yes' | 'no', turns on/off check the 'set' or 'set_infinite' opcode
-
time_domain: nil, # <time domain>, specifies time domain for pins in patterns
-
allow_mto_dash: nil, # Turn on/off support for channel data runtime repeat,i.e. vector dash in MTO patterns. Default value is "no".
-
check_vm_min_size: nil, # Turns on/off the check on minimum size of a VM pattern. Default value is "yes".
-
check_vm_mod_size: nil, # Turns on/off the check on a VM pattern module size. Default value is "yes".
-
check_oob_size: nil, # Turns on/off the check on size of OOB regions. Yes means size must be modulo 10. Default value is "no".
-
allow_mixed_1x2x: nil, # Turns on/off the support of mixed 1x/2x pin groups. Default value is "no".
-
allow_differential: nil, # Turns on/off support for differential pins. Default value is "yes".
-
allow_scan_in_srm: nil, # Allow/disallow scan vectors in SRM pattern modules. Default value is "no".
-
vm_block_size: nil, # Specifies uncompressed size in bytes of a pattern data block
-
}.merge(@compiler_options_with_args)
-
-
8
update_common_options(options) # Update common options with default (see BasePatternCompiler)
-
8
verify_pinmap_is_specified # verify pinmap specified correctly - IGXL specific
-
5
clean_and_verify_options # Standard cleaning and verifying (see BasePatternCompiler)
-
end
-
-
# Executes the compiler for each job in the queue
-
2
def run(list = nil, options = {})
-
6
fail "Error: the tester #{Origen.tester} is not an Ultrflex tester,exiting..." unless is_ultraflex?
-
6
msg = "Error: application #{Origen.app.name} is running on Windows, "
-
6
msg += 'to run the pattern compiler you must be on a Linux machine'
-
6
fail msg if Origen.running_on_windows?
-
-
6
super
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module PatternCompilers
-
2
class V93KPatternCompiler < BasePatternCompiler
-
2
require_relative 'v93k/multiport'
-
2
include MultiportAPI
-
2
require_relative 'v93k/digcap'
-
2
include DigCapAPI
-
-
2
attr_reader :avc_files, :max_avcfilename_size, :vec_per_frame
-
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/pattern_compilers/templates/template.aiv.erb"
-
-
# Linux compiler executable path
-
2
def self.linux_compiler
-
34
Origen.site_config.origen_testers[:v93k_linux_pattern_compiler]
-
end
-
-
# Windows compiler executable path - not available for V93K
-
2
def self.windows_compiler
-
nil
-
end
-
-
# Resolves to correct compiler (linux is only available)
-
2
def self.compiler
-
34
linux_compiler
-
end
-
-
2
def self.compiler_cmd
-
2
Pathname.new(compiler).absolute? ? compiler : eval('"' + compiler + '"')
-
end
-
-
2
def self.compiler_options
-
1
"#{compiler_cmd} -h"
-
end
-
-
2
def self.compiler_version
-
1
"#{compiler_cmd} -V"
-
end
-
-
2
def initialize(id, options = {})
-
31
super
-
-
@user_options = {
-
30
config_dir: nil, # Common directory where all configs can be stored
-
pinconfig_dir: nil, # Can override common config_dir if pinconfig stored elsewhere
-
pinconfig: nil, # Can specify just file name (to use config_dir/pinconfig_dir), or give full path
-
tmf_dir: nil, # Can override common config_dir if tmf stored elsewhere
-
tmf: nil, # Can specify just file name (to use config_dir/tmf_dir), or give full path
-
vbc_dir: nil, # Can override common config_dir if vbc stored elsewhere
-
vbc: nil, # Can specify just file name (to use config_dir/vbc_dir), or give full path
-
incl_dir: nil,
-
includes: [], # Array of files that will be copied into tmp job workspace before compilation
-
tmp_dir: nil,
-
avc_dir: nil,
-
binl_dir: nil,
-
multiport: nil, # Optional hash for multiport settings: port_bursts, port_in_focus, prefix, postfix
-
digcap: nil, # Optional hash for digcap settings: pins, vps, nrf, char
-
}.merge(@user_options)
-
-
@job_options = {
-
30
tester: :v93k,
-
compiler: self.class.compiler, # required
-
}.merge(@job_options)
-
-
30
@compiler_options = {
-
-
}.merge(@compiler_options)
-
-
@compiler_options_with_args = {
-
30
aiv2b_opts: nil
-
}.merge(@compiler_options_with_args)
-
-
30
@avc_files = []
-
30
@vec_per_frame = {}
-
-
30
update_common_options(options) # Update common options with default (see BasePatternCompiler)
-
30
verify_pinconfig_is_specified # Verify pinconfig specified correctly - Smartest specific
-
27
verify_tmf_is_specified # Verify tmf specified correctly - Smartest specific
-
25
clean_and_verify_options # Standard cleaning and verifying (see BasePatternCompiler)
-
end
-
-
2
def pinconfig_file
-
95
@pinconfig_file ||= build_file(:pinconfig)
-
end
-
-
2
def tmf_file
-
136
@tmf_file ||= build_file(:tmf)
-
end
-
-
2
def vbc_file
-
54
@vbc_file ||= build_file(:vbc)
-
end
-
-
2
def verify_pinconfig_is_specified
-
30
fail 'Pinconfig file is not defined! Pass as an option.' if pinconfig_file.nil?
-
28
fail 'Pinconfig is not a file!' unless pinconfig_file.file?
-
end
-
-
2
def verify_tmf_is_specified
-
27
fail 'Timing Map File (tmf) is not defined! Pass as an option.' if tmf_file.nil?
-
26
fail 'Timing Map File (tmf) is not a file!' unless tmf_file.file?
-
end
-
-
# Executes the compiler for each job in the queue
-
2
def run(aiv = nil, options = {})
-
9
aiv, options = nil, aiv if aiv.is_a? Hash
-
-
9
fail "Error: the tester #{Origen.tester} is not an V93K tester, exiting..." unless is_v93k?
-
-
9
msg = "Error: application #{Origen.app.name} is running on Windows, "
-
9
msg += 'to run the pattern compiler you must be on a Linux machine'
-
9
fail msg if Origen.running_on_windows?
-
-
# Check if there was a pattern list passed as an argument
-
# If so, then compile the patterns inside it.
-
# Otherwise compile the jobs in the queue
-
9
if aiv.nil?
-
7
if empty?
-
1
empty_msg
-
1
return
-
end
-
6
@jobs.each do |job|
-
6
unless options[:ignore_ready]
-
5
fail "Error: compiler #{job.id} not ready for pattern #{job.name}" unless job.ready?
-
end
-
6
if job.location == :lsf
-
# puts "#{self.class.aiv_setup} ; #{job.cmd}"
-
# Origen.app.lsf.submit(self.class.aiv_setup + '; ' + job.cmd)
-
Origen.app.lsf.submit(job.cmd)
-
else
-
6
Origen.profile "Linux pattern compiler compiles pattern #{job.pattern}" do
-
6
Dir.chdir(job.output_directory) do
-
# puts "#{job.cmd}"
-
6
system job.cmd
-
end
-
end
-
end
-
end
-
6
if @job_options[:location] == :local
-
6
if @job_options[:clean] == true
-
1
puts 'Log file :clean option set to true, deleting log files'
-
1
clean_output
-
end
-
end
-
# Clear @jobs
-
6
clear
-
-
else
-
# Assumes .aiv file and all workspace collateral has been built up
-
2
aiv = convert_to_pathname(aiv)
-
2
fail 'File does not exist! Please specify existing aiv file.' unless aiv.file?
-
1
current_job_options = @job_options.merge(@compiler_options_with_args)
-
1
current_job_options = current_job_options.merge(extract_job_options_from_aiv(aiv))
-
1
current_job_options = current_job_options.merge(options)
-
1
current_job_options[:output_directory] = aiv.dirname
-
-
1
@jobs << Job.new(Pathname.new(aiv), current_job_options, @compiler_options)
-
1
inspect_jobs
-
1
run(options)
-
end
-
end
-
-
# Output the compiler jobs in the queue to the console
-
2
def inspect_jobs(index = nil)
-
19
return empty_msg if empty?
-
19
desc = []
-
19
puts "\n"
-
19
@jobs.each_with_index do |j, i|
-
20
unless index.nil?
-
1
next unless i == index
-
end
-
20
desc << '| Job: ' + " #{i + 1} ".rjust(8) + '|' + 'Pattern/AIV:'.rjust(18) + " #{j.pattern.basename}".ljust(125) + '|'
-
20
desc << '| |' + 'Compiler ID:'.rjust(18) + " #{j.id} ".ljust(125) + '|'
-
20
desc << '| |' + 'AVC Files:'.rjust(18) + " #{j.count} ".ljust(125) + '|'
-
20
desc << '| |' + 'Output Directory:'.rjust(18) + " #{j.output_directory} ".ljust(125) + '|'
-
20
desc << '| |' + '.avc directory:'.rjust(18) + " #{j.avc_dir} ".ljust(125) + '|'
-
20
desc << '| |' + '.binl directory:'.rjust(18) + " #{j.binl_dir} ".ljust(125) + '|'
-
20
desc << '| |' + 'LSF:'.rjust(18) + " #{j.location == :lsf ? true : false} ".ljust(125) + '|'
-
20
desc << '| |' + 'Delete log files:'.rjust(18) + " #{j.clean} ".ljust(125) + '|'
-
20
desc << '| |' + 'Verbose:'.rjust(18) + " #{j.verbose} ".ljust(125) + '|'
-
20
if j.aiv2b_opts && j.aiv2b_opts.is_a?(String)
-
13
aiv2b_opts = j.aiv2b_opts.gsub('AI_V2B_OPTIONS ', '')
-
else
-
7
aiv2b_opts = render_aiv2b_options_line.gsub('AI_V2B_OPTIONS', '')
-
end
-
20
desc << '| |' + 'AI_V2B Options:'.rjust(18) + " #{aiv2b_opts} ".ljust(125) + '|'
-
20
desc << '-' * desc.first.size
-
end
-
19
puts desc.flatten.join("\n")
-
end
-
-
# Finds the patterns and creates a compiler job for each one found.
-
# Handles singles files (.atp, .atp.gz, or .list) and directories (recursively or flat)
-
2
def find_jobs(p = @path)
-
# First-level verification: file/directory was given and exists
-
21
msg = 'Pass in a valid file (.avc, .avc.gz, .list) or a valid directory'
-
21
fail "Pattern path is set to nil! #{msg}" if p.nil?
-
20
path = Pathname.new(p)
-
20
fail "Pattern path does not exist! #{msg}" unless path.exist?
-
18
path = path.expand_path
-
-
# Set the reference directory for pattern sub-dir mirroring
-
18
set_reference_directory
-
-
# Collect file, list, or directory (recursively)
-
18
Origen.profile 'Linux pattern compiler finds patterns' do
-
18
if path.directory?
-
# Get all of the patterns inside this dir or inside this directory recursively
-
1
process_directory(path, @files, @user_options[:recursive])
-
else
-
# Found a file so no searching is necessary, process as single pattern or list
-
17
process_file(path, @files)
-
end
-
end
-
-
18
fail "Did not fild a valid file to compile! #{msg}" if @files.empty?
-
-
17
Origen.profile 'Linux pattern compiler creates job' do
-
# For V93K, only single AIV file is really sent to the compiler, but need list of all
-
# avc files that will be compiled using that aiv file, so keep a separate array.
-
17
@max_avcfilename_size = 0
-
17
@files.each do |f|
-
30
@avc_files << Pathname.new(f).basename.sub_ext('').to_s
-
30
@max_avcfilename_size = @avc_files[-1].size > @max_avcfilename_size ? @avc_files[-1].size : @max_avcfilename_size
-
end
-
-
17
rel_dir = Pathname.new("#{path.dirname.to_s[@user_options[:reference_directory].to_s.size..-1]}")
-
-
# Resolve output directory
-
17
if @job_options[:output_directory].nil?
-
# job output dir not specified, create a unique (hash) based on path/compiler_name
-
15
s = Digest::MD5.new
-
15
s << @user_options[:reference_directory].to_s
-
15
s << @id.to_s
-
15
out = "#{@user_options[:reference_directory]}/job_#{@id}_#{s.to_s[0..6].upcase}#{rel_dir}"
-
15
job_output_dir = Pathname.new(out)
-
else
-
2
job_output_dir = Pathname.new("#{@job_options[:output_directory]}#{rel_dir}")
-
end
-
-
# Create any necessary output directories before trying to compile
-
17
unless job_output_dir.directory?
-
4
puts "Output directory #{job_output_dir} does not exist, creating it..."
-
4
FileUtils.mkdir_p(job_output_dir)
-
end
-
-
17
job_avc_dir = avc_dir.absolute? ? avc_dir : Pathname.new("#{job_output_dir}/#{avc_dir}").cleanpath
-
17
unless job_avc_dir.directory?
-
6
puts "AVC Output directory #{job_avc_dir} does not exist, creating it..."
-
6
FileUtils.mkdir_p(job_avc_dir)
-
end
-
17
job_binl_dir = binl_dir.absolute? ? binl_dir : Pathname.new("#{job_output_dir}/#{binl_dir}").cleanpath
-
17
unless job_binl_dir.directory?
-
6
puts "BINL Output directory #{job_binl_dir} does not exist, creating it..."
-
6
FileUtils.mkdir_p(job_binl_dir)
-
end
-
-
# Move AVC files into job space (through pre-processor)
-
17
@files.each do |file|
-
60
contents = File.open(file, 'rb') { |f| f.read }
-
30
new_contents = preprocess_avc(contents)
-
30
new_avc_file = Pathname.new("#{job_avc_dir}/#{Pathname.new(file).basename}").cleanpath
-
60
File.open(new_avc_file, 'w') { |f| f.write(new_contents.force_encoding('UTF-8')) }
-
30
avc_key = Pathname.new(file).basename.sub_ext('').to_s.to_sym
-
30
@vec_per_frame[avc_key] = digcap? ? avc_digcap_vpf(new_contents) : 0
-
end
-
-
# Generate the AIV file using the template with all the pattern compiler parameters
-
17
aiv_file = "#{job_output_dir}/#{path.basename.to_s.split('.')[0]}.aiv"
-
17
Origen.log.info "Creating... #{aiv_file}"
-
17
contents = Origen.compile(self.class::TEMPLATE, scope: self, preserve_target: true)
-
32
File.open(aiv_file, 'w') { |f| f.write(contents) }
-
-
# Copy Timing Map File to local AIV workspace
-
16
dest = Pathname.new("#{job_output_dir}/#{tmf_file.basename}").cleanpath
-
16
FileUtils.cp tmf_file, dest
-
-
# Copy VBC file to local AIV workspace (if specified)
-
16
if vbc_file
-
4
dest = Pathname.new("#{job_output_dir}/#{vbc_file.basename}").cleanpath
-
4
FileUtils.cp vbc_file, dest
-
end
-
-
# Copy any extra files needed (includes)
-
16
@user_options[:includes].each do |incl|
-
1
src = build_file(:incl, incl)
-
1
dest = Pathname.new("#{job_output_dir}/#{src.basename}").cleanpath
-
1
FileUtils.cp src, dest
-
end
-
-
# Gather up job options
-
16
current_job_options = @job_options.merge(@compiler_options_with_args)
-
16
current_job_options[:output_directory] = job_output_dir
-
16
current_job_options[:pinconfig] = pinconfig_file
-
16
current_job_options[:tmf] = tmf_file
-
16
current_job_options[:count] = @avc_files.count
-
16
current_job_options[:avc_dir] = avc_dir
-
16
current_job_options[:binl_dir] = binl_dir
-
-
# Create new job
-
16
@jobs << Job.new(Pathname.new(aiv_file), current_job_options, @compiler_options)
-
16
current_job_options = {}
-
end
-
-
# Clear files and avc_files now that job has successfully been queued
-
16
@files = []
-
16
@avc_files = []
-
16
@vec_per_frame = {}
-
16
inspect_jobs
-
end
-
-
# Given the file contents, parse and calculate number of capture vectors
-
2
def avc_digcap_vpf(contents)
-
6
capture_vectors = 0
-
6
factor = 1
-
6
contents.each_line do |line|
-
1138
next if line.match(/^\s*\#/)
-
786
if line.match(/^\s*SQPG\s+LBGN\s+(\d+)\s*;/)
-
6
factor = Regexp.last_match(1).to_i
-
end
-
786
factor = 1 if line.match(/^\s*SQPG\s+LEND\s*;/)
-
786
capture_vectors += factor if /#{digcap.capture_string}/.match(line)
-
end
-
6
capture_vectors
-
end
-
-
2
def avc_dir
-
67
@avc_dir ||= begin
-
9
if @user_options[:avc_dir]
-
1
clean_path(@user_options[:avc_dir].to_s)
-
else
-
8
Pathname.new('./AVC') # default value
-
end
-
end
-
end
-
-
2
def binl_dir
-
67
@binl_dir ||= begin
-
9
if @user_options[:binl_dir]
-
1
clean_path(@user_options[:binl_dir].to_s)
-
else
-
8
Pathname.new('./BINL') # default value
-
end
-
end
-
end
-
-
2
def tmp_dir
-
17
@tmp_dir ||= begin
-
9
if @user_options[:tmp_dir]
-
2
clean_path(@user_options[:tmp_dir].to_s)
-
else
-
7
Pathname.new('./tmp') # default value
-
end
-
end
-
end
-
-
# Given path string, return Pathname object with cleaned up path
-
2
def clean_path(path_str)
-
4
path = Pathname.new(path_str).cleanpath
-
4
if path.absolute?
-
2
return path
-
else
-
2
return Pathname.new("./#{path}")
-
end
-
end
-
-
# Placeholder - TopLevel can monkey patch this method to do more
-
# sophisticated AVC modification prior to compilation
-
2
def preprocess_avc(contents)
-
30
new_contents = contents # no manipulation done here
-
30
new_contents
-
end
-
-
2
def render_aiv2b_options_line
-
24
line = 'AI_V2B_OPTIONS'
-
24
if @compiler_options_with_args[:aiv2b_opts]
-
18
if @compiler_options_with_args[:aiv2b_opts].is_a? Array
-
6
@compiler_options_with_args[:aiv2b_opts].each do |opt|
-
18
line += " #{opt}"
-
end
-
12
elsif @compiler_options_with_args[:aiv2b_opts].is_a? String
-
11
line += " #{@compiler_options[:aiv2b]}"
-
else
-
1
fail 'aiv2b options must be an array or string'
-
end
-
end
-
23
line += " -c #{vbc_file.basename}" if vbc_file
-
23
line
-
end
-
-
2
def render_aiv_patterns_header
-
18
line = 'PATTERNS '
-
18
line += 'name'.ljust(max_avcfilename_size + 2)
-
18
line += 'port'.ljust(multiport.port_in_focus.size + 2) if multiport?
-
18
line += 'tmf_file'
-
18
line
-
end
-
-
2
def render_aiv_patterns_entry(pattern)
-
31
line = ' '
-
31
line += "#{pattern}".ljust(max_avcfilename_size + 2)
-
31
line += "#{multiport.port_in_focus}".ljust(multiport.port_in_focus.size + 2) if multiport?
-
31
line += "#{tmf_file.basename}"
-
31
line
-
end
-
-
2
private
-
-
2
def extract_job_options_from_aiv(file)
-
1
options = {}
-
2
contents = File.open(file, 'rb') { |f| f.read }
-
1
count = 0
-
1
counting = false
-
1
contents.each_line do |line|
-
12
if match = line.match(/^avc_dir\s*(\S*)/)
-
1
options[:avc_dir] = match.captures[0]
-
end
-
12
if match = line.match(/^pinconfig_file\s*(\S*)/)
-
1
options[:pinconfig] = Pathname.new(match.captures[0])
-
end
-
12
if match = line.match(/^single_binary_pattern_dir\s*(\S*)/)
-
1
options[:binl_dir] = match.captures[0]
-
end
-
12
if match = line.match(/^AI_V2B_OPTIONS/)
-
1
options[:aiv2b_opts] = match.captures[0]
-
end
-
12
if counting
-
1
if line.match(/\w+/)
-
1
count += 1
-
else
-
counting = false
-
end
-
end
-
12
if match = line.match(/^PATTERNS/)
-
1
counting = true
-
end
-
end
-
1
options[:count] = count
-
1
options
-
end
-
-
2
def build_file(type, fstr = nil)
-
88
type_dir = "#{type}_dir".to_sym
-
88
fstr ||= @user_options[type]
-
88
if fstr.nil?
-
nil
-
else
-
57
if Pathname.new(fstr).absolute?
-
4
Pathname.new(fstr)
-
53
elsif @user_options[type_dir]
-
2
Pathname.new("#{@user_options[type_dir]}/#{fstr}").cleanpath
-
51
elsif @user_options[:config_dir]
-
47
Pathname.new("#{@user_options[:config_dir]}/#{fstr}").cleanpath
-
else
-
4
Pathname.new("#{Origen.root!}/#{fstr}").cleanpath
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module PatternCompilers
-
2
class V93KPatternCompiler
-
2
module MultiportAPI
-
2
class Multiport
-
2
attr_accessor :port_in_focus, :port_bursts, :prefix, :postfix
-
-
2
def initialize(options)
-
11
@port_in_focus = nil
-
-
11
if options && options[:port_in_focus]
-
4
@port_in_focus = options[:port_in_focus]
-
4
@port_bursts = options[:port_bursts]
-
4
@prefix = options[:prefix].nil? ? '' : "#{options[:prefix]}_"
-
4
@postfix = options[:postfix].nil? ? '' : "_#{options[:postfix]}"
-
end
-
end
-
-
2
def render_aiv_lines(pattern)
-
8
mpb_entry = []
-
8
mpb_entry << ''
-
8
mpb_entry << render_mpb_header(pattern)
-
8
mpb_entry << render_mpb_port_line(pattern)
-
8
mpb_entry << render_mpb_burst_line(pattern)
-
8
mpb_entry
-
end
-
-
2
def enabled?
-
68
port_in_focus.nil? ? false : true
-
end
-
-
2
private
-
-
2
def render_mpb_header(pattern)
-
8
"MULTI_PORT_BURST #{prefix}#{pattern}#{postfix}"
-
end
-
-
2
def render_mpb_port_line(pattern)
-
8
line = 'PORTS '
-
8
line += port_in_focus.to_s
-
8
line += mpb_padding(port_in_focus.to_s, pattern, 0)
-
8
if port_bursts
-
4
port_bursts.each do |k, v|
-
8
line += k.to_s
-
8
line += mpb_padding(k.to_s, v.to_s, 0)
-
end
-
end
-
8
line
-
end
-
-
2
def render_mpb_burst_line(pattern)
-
8
line = ' '
-
8
line += pattern.to_s
-
8
line += mpb_padding(port_in_focus.to_s, pattern, 1)
-
8
if port_bursts
-
4
port_bursts.each do |k, v|
-
8
line += v.to_s
-
8
line += mpb_padding(k.to_s, v.to_s, 1)
-
end
-
end
-
8
line
-
end
-
-
2
def mpb_padding(str0, str1, index = 0)
-
32
width = str0.size > str1.size ? str0.size : str1.size
-
32
index == 0 ? ' ' * (width + 2 - str0.size) : ' ' * (width + 2 - str1.size)
-
end
-
end
-
-
2
def multiport
-
100
@multiport ||= Multiport.new(@user_options[:multiport])
-
end
-
-
2
def multiport?
-
68
multiport.enabled?
-
end
-
end
-
end
-
end
-
end
-
2
require 'active_support/concern'
-
2
module OrigenTesters
-
# Include this module to create an interface that supports multiple tester
-
# types.
-
#
-
# This module will expose generators for all test platforms supported by
-
# the Testers plugin.
-
2
module ProgramGenerators
-
2
extend ActiveSupport::Concern
-
2
include Interface
-
-
2
PLATFORMS = [J750, J750_HPT, UltraFLEX, V93K]
-
-
2
included do
-
12
Origen.add_interface(self)
-
end
-
-
2
module ClassMethods
-
# Ensures that the correct generator is loaded before initialize is called
-
2
def new(*args, &block)
-
160
x = allocate
-
160
x._load_generator
-
160
x.send(:initialize, *args, &block)
-
160
x
-
end
-
-
# Returns true if the interface class supports the
-
# given tester instance
-
2
def supports?(tester_instance)
-
52
PLATFORMS.include?(tester_instance.class)
-
end
-
end
-
-
# @api private
-
2
def pre_initialize(options = {})
-
48
_load_generator
-
end
-
-
2
def initialize(options = {})
-
end
-
-
2
def tester
-
10458
Origen.tester
-
end
-
-
2
def _load_generator
-
422
if tester.v93k?
-
221
if tester.smt8?
-
84
class << self; include OrigenTesters::V93K_SMT8::Generator; end
-
else
-
358
class << self; include OrigenTesters::V93K::Generator; end
-
end
-
201
elsif tester.j750_hpt?
-
30
class << self; include OrigenTesters::J750_HPT::Generator; end
-
186
elsif tester.j750?
-
34
class << self; include OrigenTesters::J750::Generator; end
-
169
elsif tester.ultraflex?
-
338
class << self; include OrigenTesters::UltraFLEX::Generator; end
-
elsif defined? tester.class::TEST_PROGRAM_GENERATOR
-
class << self; include tester.class::TEST_PROGRAM_GENERATOR; end
-
else
-
fail "The OrigenTesters::ProgramGenerators module does not support #{tester.class}!"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
autoload :Base, 'origen_testers/smartest_based_tester/base'
-
2
autoload :V93K, 'origen_testers/smartest_based_tester/v93k'
-
-
2
require 'origen_testers/smartest_based_tester/decompiler'
-
end
-
# Convenience/Legacy names without the SmartestBasedTester namespace
-
2
autoload :V93K, 'origen_testers/smartest_based_tester/v93k'
-
2
autoload :V93K_SMT8, 'origen_testers/smartest_based_tester/v93k_smt8'
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class Base
-
2
include VectorBasedTester
-
-
# Disable inline (end of vector) comments, enabled by default
-
2
attr_accessor :inline_comments
-
-
# Returns whether the tester has been configured to wrap top-level flow modules with an
-
# enable or not.
-
#
-
# Returns nil if not.
-
#
-
# Returns :enabled if the enable is configured to be on by default, or :disabled if it is
-
# configured to be off by default.
-
2
attr_reader :add_flow_enable
-
-
# Returns the value defined at target-level on if/how to make test names unique within a
-
# flow, the default value is :signature
-
2
attr_reader :unique_test_names
-
-
# use flow variable grouping or not
-
2
attr_accessor :flow_variable_grouping
-
-
# Returns the SMT version, defaults to 7
-
2
attr_reader :smt_version
-
-
# permit modification of minimum repeat count
-
2
attr_accessor :min_repeat_loop
-
2
alias_method :min_repeat_count, :min_repeat_loop
-
2
alias_method :min_repeat_count=, :min_repeat_loop=
-
-
# Control literal flag definitions
-
2
attr_accessor :literal_flags # whether flags should be exactly as indicated
-
2
attr_accessor :literal_enables # whether enables should be exactly as indicated
-
-
# permit option to generate multiport type patterns
-
# and use multiport type code
-
2
attr_accessor :multiport
-
2
alias_method :multi_port, :multiport
-
2
alias_method :multi_port=, :multiport=
-
2
attr_accessor :multiport_prefix # multiport burst name prefix
-
2
attr_accessor :multiport_postfix # multiport burst name postfix
-
-
# When set to true, all test flows will be generated with a corresponding testtable limits
-
# file, rather than having the limits attached inline to the test suites
-
2
attr_accessor :create_limits_file
-
-
# Returns an array of strings that indicate which test modes will be included in limits files,
-
# by default returns an empty array.
-
# If no test modes have been specified then the limits file will simply be generated with no
-
# test modes.
-
2
attr_reader :limitfile_test_modes
-
2
alias_method :limitsfile_test_modes, :limitfile_test_modes
-
-
# When set to true, tests which are marked with continue: true will be forced to pass in
-
# generated test program flows. Flow branching based on the test result will be handled via
-
# some other means to give the same flow if the test 'fails', however the test will always
-
# appear as if it passed for data logging purposes.
-
#
-
# Testers which do not implement this option will ignore it.
-
2
attr_accessor :force_pass_on_continue
-
-
# When set to true, tests will be set to delayed binning by default (overon = on) unless
-
# delayed: false is supplied when defining the test
-
2
attr_accessor :delayed_binning
-
-
# Sets the package namespace that all generated test collateral should be placed under,
-
# defaults to the application's namespace if not defined (SMT8 only)
-
2
attr_writer :package_namespace
-
-
2
attr_writer :spec_path, :seq_path
-
-
# When set to true, the bins and softbins sheets from the limits spreadsheet will
-
# be written out to a standalone (spreadsheet) file instead (SMT8 only)
-
2
attr_accessor :separate_bins_file
-
-
# When set to true (the default), patterns will be generated in ZIP format instead of ASCII
-
# format (SMT8 only)
-
2
attr_accessor :zip_patterns
-
-
# When set to true (the default), parameters will be generated in the flow file regardless if the default is selected
-
# (SMT8 only)
-
2
attr_accessor :print_all_params
-
-
# When set to true, the flow path will have insertion in the subdirectories
-
# (SMT8 only)
-
2
attr_reader :insertion_in_the_flow_path
-
-
2
def initialize(options = {})
-
options = {
-
# whether to use multiport bursts or not, if so this indicates the name of the port to use
-
263
multiport: false,
-
multiport_prefix: false,
-
multiport_postfix: false
-
}.merge(options)
-
-
263
@smt_version = options[:smt_version] || 7
-
-
263
@separate_bins_file = options[:separate_bins_file] || false
-
263
if options.key?(:zip_patterns)
-
90
@zip_patterns = options.delete(:zip_patterns)
-
else
-
173
@zip_patterns = true
-
end
-
-
263
if smt8?
-
94
require_relative 'smt8'
-
94
extend SMT8
-
else
-
169
require_relative 'smt7'
-
169
extend SMT7
-
end
-
-
263
@max_repeat_loop = 65_535
-
263
@min_repeat_loop = 33
-
263
if smt8?
-
94
@pat_extension = 'pat'
-
94
@program_comment_char = ['println', '//']
-
94
@print_all_params = options[:print_all_params].nil? ? true : options[:print_all_params]
-
else
-
169
@pat_extension = 'avc'
-
169
@program_comment_char = ['print_dl', '//']
-
end
-
263
@compress = true
-
# @support_repeat_previous = true
-
263
@match_entries = 10
-
263
@name = 'v93k'
-
263
@comment_char = '#'
-
263
@level_period = true
-
263
@inline_comments = true
-
263
@multiport = options[:multiport]
-
263
@multiport_prefix = options[:multiport_prefix]
-
263
@multiport_postfix = options[:multiport_postfix]
-
263
@overlay_style = :subroutine # default to use subroutine for overlay
-
263
@capture_style = :hram # default to use hram for capture
-
263
@overlay_subr = nil
-
263
@overlay_history = {} # used to track labels, subroutines, digsrc pins used etc
-
263
@insertion_in_the_flow_path = options[:insertion_in_the_flow_path] # add insertion for path to the flows
-
-
263
if options[:add_flow_enable]
-
28
self.add_flow_enable = options[:add_flow_enable]
-
end
-
263
if options.key?(:unique_test_names)
-
34
@unique_test_names = options[:unique_test_names]
-
else
-
229
if smt8?
-
94
@unique_test_names = nil
-
else
-
135
@unique_test_names = :signature
-
end
-
end
-
263
if options.key?(:create_limits_file)
-
92
@create_limits_file = options[:create_limits_file]
-
else
-
171
if smt8?
-
4
@create_limits_file = true
-
else
-
167
@create_limits_file = false
-
end
-
end
-
-
263
if options.key?(:flow_variable_grouping)
-
38
@flow_variable_grouping = options[:flow_variable_grouping]
-
end
-
-
263
if options[:literal_flags]
-
@literal_flags = true
-
end
-
263
if options[:literal_enables]
-
@literal_enables = true
-
end
-
-
263
@package_namespace = options.delete(:package_namespace)
-
263
@spec_path = options.delete(:spec_path)
-
263
@seq_path = options.delete(:seq_path)
-
263
self.limitfile_test_modes = options[:limitfile_test_modes] || options[:limitsfile_test_modes]
-
263
self.force_pass_on_continue = options[:force_pass_on_continue]
-
263
self.delayed_binning = options[:delayed_binning]
-
end
-
-
2
def disable_pattern_diffs
-
31
smt8? && zip_patterns
-
end
-
-
# Returns the package namespace that all generated test collateral should be placed under,
-
# defaults to the application's namespace if not defined
-
2
def package_namespace
-
1468
@package_namespace || Origen.app.namespace
-
end
-
-
2
def spec_path
-
632
@spec_path || 'specs'
-
end
-
-
2
def seq_path
-
632
@seq_path || 'specs'
-
end
-
# Set the test mode(s) that you want to see in the limits files, supply an array of mode names
-
# to set multiple.
-
2
def limitfile_test_modes=(val)
-
263
@limitfile_test_modes = Array(val).map(&:to_s)
-
end
-
2
alias_method :limitsfile_test_modes, :limitfile_test_modes=
-
-
# return the multiport burst name
-
# provide the name you want to obtain multiport for
-
2
def multiport_name(patt_name)
-
245
name = "#{patt_name}"
-
245
if @multiport
-
245
name = "#{@multiport_prefix}_#{name}" if @multiport_prefix
-
245
name = "#{name}_#{@multiport_postfix}" if @multiport_postfix
-
245
unless @multiport_prefix || @multiport_postfix
-
245
name = "#{@multiport}_#{name}"
-
end
-
end
-
245
name
-
end
-
-
# Set to :enabled to have all top-level flow modules wrapped by an enable flow variable
-
# that is enabled by default (top-level flow has to disable modules it doesn't want).
-
#
-
# Set to :disabled to have the opposite, where the top-level flow has to enable all
-
# modules.
-
#
-
# Note that the interface can override this setting for each flow during program generation.
-
2
def add_flow_enable=(value)
-
28
if value == :enable || value == :enabled
-
14
@add_flow_enable = :enabled
-
14
elsif value == :disable || value == :disabled
-
14
@add_flow_enable = :disabled
-
else
-
fail "Unknown add_flow_enable value, #{value}, must be :enabled or :disabled"
-
end
-
end
-
-
2
def cycle(options = {})
-
# handle overlay if requested
-
13408
ovly_style = nil
-
13408
if options.key?(:overlay)
-
28
ovly_style = options[:overlay][:overlay_style].nil? ? @overlay_style : options[:overlay][:overlay_style]
-
28
overlay_str = options[:overlay][:overlay_str]
-
-
# route the overlay request to the appropriate method
-
28
case ovly_style
-
when :subroutine, :default
-
8
subroutine_overlay(overlay_str, options)
-
8
ovly_style = :subroutine
-
when :label, :global_label
-
12
options[:dont_compress] = true
-
12
unless @overlay_history.key?(overlay_str)
-
4
cc "#{overlay_str}"
-
4
@overlay_history[overlay_str] = { is_label: true }
-
end
-
when :handshake
-
6
if @delayed_handshake
-
4
if @delayed_handshake != overlay_str
-
handshake
-
@delayed_handshake = overlay_str
-
end
-
else
-
2
@delayed_handshake = overlay_str
-
end
-
else
-
2
ovly_style = overlay_style_warn(options[:overlay][:overlay_str], options)
-
end # case ovly_style
-
else
-
13380
handshake if @delayed_handshake
-
13380
@delayed_handshake = nil
-
13380
@overlay_subr = nil
-
end # of handle overlay
-
-
13408
options_overlay = options.delete(:overlay) if options.key?(:overlay)
-
-
13408
unless ovly_style == :subroutine || ovly_style == :handshake
-
13392
super(options)
-
end
-
-
13408
unless options_overlay.nil?
-
# stage = :body if ovly_style == :subroutine # always set stage back to body in case subr overlay was selected
-
end
-
end
-
-
# Warn user of unsupported overlay style
-
2
def overlay_style_warn(overlay_str, options)
-
2
Origen.log.warn("Unrecognized overlay style :#{@overlay_style}, defaulting to subroutine")
-
2
Origen.log.warn('Available overlay styles :subroutine')
-
2
subroutine_overlay(overlay_str, options)
-
2
@overlay_style = :subroutine # Just give 1 warning
-
end
-
-
# Implement subroutine overlay, called by tester.cycle
-
2
def subroutine_overlay(sub_name, options = {})
-
10
if @overlay_subr != sub_name
-
# unless last staged vector already has the subr call do the following
-
8
i = -1
-
8
i -= 1 until stage.bank[i].is_a?(OrigenTesters::Vector)
-
8
if stage.bank[i].microcode !~ /#{sub_name}/
-
-
# check for repeat on new last vector, unroll 1 if needed
-
8
if stage.bank[i].repeat > 1
-
2
v = OrigenTesters::Vector.new
-
2
v.pin_vals = stage.bank[i].pin_vals
-
2
v.timeset = stage.bank[i].timeset
-
2
stage.bank[i].repeat -= 1
-
2
stage.store(v)
-
2
i = -1
-
end
-
-
# mark last vector as dont_compress
-
8
stage.bank[i].dont_compress = true
-
# insert subroutine call
-
8
call_subroutine sub_name
-
end # if microcode not placed
-
8
@overlay_subr = sub_name
-
end
-
-
# stage = sub_name
-
end # subroutine_overlay
-
-
# Capture the pin data from a vector to the tester.
-
#
-
# This method uses the Digital Capture feature (Selective mode) of the V93000 to capture
-
# the data from the given pins on the previous vector.
-
# Note that is does not actually generate a new vector.
-
#
-
# Note also that any drive cycles on the target pins can also be captured, to avoid this
-
# the wavetable should be set up like this to infer a 'D' (Don't Capture) on vectors where
-
# the target pin is being used to drive data:
-
#
-
# PINS nvm_fail
-
# 0 d1:0 r1:D 0
-
# 1 d1:1 r1:D 1
-
# 2 r1:C Capt
-
# 3 r1:D NoCapt
-
#
-
# Sometimes when generating vectors within a loop you may want to apply a capture
-
# retrospectively to a previous vector, passing in an offset option will allow you
-
# to do this.
-
#
-
# ==== Examples
-
# $tester.cycle # This is the vector you want to capture
-
# $tester.store :pin => pin(:fail) # This applys the required opcode to the given pins
-
#
-
# $tester.cycle # This one gets captured
-
# $tester.cycle
-
# $tester.cycle
-
# $tester.store(:pin => pin(:fail), :offset => -2) # Just realized I need to capture that earlier vector
-
#
-
# # Capturing multiple pins:
-
# $tester.cycle
-
# $tester.store :pins => [pin(:fail), pin(:done)]
-
#
-
# Since the V93K store operates on a pin level (rather than vector level as on the J750)
-
# equivalent functionality can also be achieved by setting the store attribute of the pin
-
# itself prior to calling $tester.cycle.
-
# However it is recommended to use the tester API to do the store if cross-compatiblity with
-
# other platforms, such as the J750, is required.
-
2
def store(*pins)
-
32
options = pins.last.is_a?(Hash) ? pins.pop : {}
-
32
options = { offset: 0
-
}.merge(options)
-
32
pins = pins.flatten.compact
-
32
if pins.empty?
-
fail 'For the V93K you must supply the pins to store/capture'
-
end
-
32
pins.each do |pin|
-
35
pin.restore_state do
-
35
pin.capture
-
35
update_vector_pin_val pin, offset: options[:offset]
-
35
unless @inhibit_vectors
-
32
last_vector(options[:offset]).dont_compress = true
-
32
last_vector(options[:offset]).contains_capture = true
-
end
-
end
-
end
-
end
-
2
alias_method :capture, :store
-
-
# Same as the store method, except that the capture will be applied to the next
-
# vector to be generated.
-
#
-
# @example
-
# $tester.store_next_cycle
-
# $tester.cycle # This is the vector that will be captured
-
2
def store_next_cycle(*pins)
-
7
options = pins.last.is_a?(Hash) ? pins.pop : {}
-
7
options = {
-
}.merge(options)
-
7
pins = pins.flatten.compact
-
7
if pins.empty?
-
fail 'For the V93K you must supply the pins to store/capture'
-
end
-
14
pins.each { |pin| pin.save; pin.capture }
-
# Register this clean up function to be run after the next vector
-
# is generated, cool or what!
-
7
preset_next_vector do |vector|
-
6
vector.contains_capture = true
-
6
pins.each(&:restore)
-
end
-
end
-
2
alias_method :store!, :store_next_cycle
-
-
# Start a subroutine.
-
#
-
# Generates a global subroutine label. Global is used to adhere to the best practice of
-
# containing all subroutines in dedicated patterns, e.g. global_subs.atp
-
#
-
# ==== Examples
-
# $tester.start_subroutine("wait_for_done")
-
# < generate your subroutine vectors here >
-
# $tester.end_subroutine
-
2
def start_subroutine(name)
-
2
local_subroutines << name.to_s.chomp unless local_subroutines.include?(name.to_s.chomp) || @inhibit_vectors
-
# name += "_subr" unless name =~ /sub/
-
2
::Pattern.open name: name, call_startup_callbacks: false, subroutine: true
-
end
-
-
# Ends the current subroutine that was started with a previous call to start_subroutine
-
2
def end_subroutine(_cond = false)
-
2
::Pattern.close call_shutdown_callbacks: false, subroutine: true
-
end
-
-
# Call a subroutine.
-
#
-
# This calls a subroutine immediately following previous vector, it does not
-
# generate a new vector.
-
#
-
# Subroutines should always be called through this method as it ensures a running
-
# log of called subroutines is maintained and which then gets output in the pattern
-
# header to import the right dependencies.
-
#
-
# An offset option is available to make the call on earlier vectors.
-
#
-
# Repeated calls to the same subroutine will automatically be compressed unless
-
# option :suppress_repeated_calls is supplied and set to false. This means that for
-
# the common use case of calling a subroutine to implement an overlay the subroutine
-
# can be called for every bit that has the overlay and the pattern will automatically
-
# generate correctly.
-
#
-
# ==== Examples
-
# $tester.call_subroutine("mysub")
-
# $tester.call_subroutine("my_other_sub", :offset => -1)
-
2
def call_subroutine(name, options = {})
-
options = {
-
26
offset: 0,
-
suppress_repeated_calls: true
-
}.merge(options)
-
26
called_subroutines << name.to_s.chomp unless called_subroutines.include?(name.to_s.chomp) || @inhibit_vectors
-
-
26
code = "SQPG JSUB #{name};"
-
26
if !options[:suppress_repeated_calls] ||
-
last_object != code
-
26
microcode code, offset: (options[:offset] * -1)
-
end
-
end
-
-
# Handshake with the tester.
-
#
-
# ==== Examples
-
# $tester.handshake # Pass control to the tester for a measurement
-
2
def handshake(options = {})
-
2
options = {
-
}.merge(options)
-
2
::Pattern.split(options)
-
end
-
-
# Do a frequency measure.
-
#
-
# ==== Examples
-
# $tester.freq_count($top.pin(:d_out)) # Freq measure on pin "d_out"
-
2
def freq_count(_pin, options = {})
-
options = {
-
}.merge(options)
-
::Pattern.split(options)
-
end
-
-
# Generates a match loop on up to two pins.
-
#
-
# This method is not really intended to be called directly, rather you should call
-
# via Tester#wait e.g. $tester.wait(:match => true).
-
#
-
# The timeout should be provided in cycles, however when called via the wait method the
-
# time-based helpers (time_in_us, etc) will be converted to cycles for you.
-
# The following options are available to tailor the match loop behavior, defaults in
-
# parenthesis:
-
#
-
# * :pin - The pin object to match on (*required*)
-
# * :state - The pin state to match on, :low or :high (*required*)
-
# * :check_for_fails (false) - Flushes the pipeline and checks for fails prior to the match (to allow binout of fails encountered before the match)
-
# * :pin2 (nil) - Optionally supply a second pin to match on
-
# * :state2 (nil) - State for the second pin (required if :pin2 is supplied)
-
# * :force_fail_on_timeout (true) - Force a vector mis-compare if the match loop times out
-
#
-
# ==== Examples
-
# $tester.wait(:match => true, :time_in_us => 5000, :pin => $top.pin(:done), :state => :high)
-
2
def match(pin, state, timeout_in_cycles, options = {})
-
options = {
-
6
check_for_fails: false,
-
pin2: false,
-
state2: false,
-
global_loops: false,
-
generate_subroutine: false,
-
force_fail_on_timeout: true
-
}.merge(options)
-
-
# Ensure the match pins are don't care by default
-
6
pin.dont_care
-
6
options[:pin2].dont_care if options[:pin2]
-
6
if !options[:pin2]
-
3
cc "for the #{pin.name.upcase} pin to go #{state.to_s.upcase}"
-
3
match_block(timeout_in_cycles, options) do |match_or_conditions, fail_conditions|
-
3
match_or_conditions.add do
-
3
state == :low ? pin.expect_lo : pin.expect_hi
-
3
cycle
-
3
pin.dont_care
-
end
-
end
-
else
-
3
cc "for the #{pin.name.upcase} pin to go #{state.to_s.upcase}"
-
3
cc "or the #{options[:pin2].name.upcase} pin to go #{options[:state2].to_s.upcase}"
-
3
match_block(timeout_in_cycles, options) do |match_or_conditions, fail_conditions|
-
3
match_or_conditions.add do
-
3
state == :low ? pin.expect_lo : pin.expect_hi
-
3
cycle
-
3
pin.dont_care
-
end
-
3
match_or_conditions.add do
-
3
options[:state2] == :low ? options[:pin2].expect_lo : options[:pin2].expect_hi
-
3
cycle
-
3
options[:pin2].dont_care
-
end
-
3
fail_conditions.add do
-
3
cc 'To get here something has gone wrong, strobe again to force a pattern failure'
-
3
state == :low ? pin.expect_lo : pin.expect_hi
-
3
options[:state2] == :low ? options[:pin2].expect_lo : options[:pin2].expect_hi
-
3
cycle
-
3
pin.dont_care
-
3
options[:pin2].dont_care
-
end
-
end
-
end
-
end
-
-
2
def match_block(timeout_in_cycles, options = {}, &block)
-
9
unless block_given?
-
fail 'ERROR: block not passed to match_block!'
-
end
-
-
# Create BlockArgs objects in order to receive multiple blocks
-
9
match_conditions = Origen::Utility::BlockArgs.new
-
9
fail_conditions = Origen::Utility::BlockArgs.new
-
-
9
if block.arity > 0
-
6
yield match_conditions, fail_conditions
-
else
-
3
match_conditions.add(&block)
-
end
-
-
# Generate a conventional match loop when there is only one match condition block
-
9
if match_conditions.instance_variable_get(:@block_args).size == 1
-
# Need to ensure at least 8 cycles with no compares before entering
-
6
dut.pins.each do |name, pin|
-
162
pin.save
-
162
pin.dont_care if pin.comparing?
-
end
-
6
8.cycles
-
168
dut.pins.each { |name, pin| pin.restore }
-
-
# Placeholder, real number of loops required to implement the required timeout will be
-
# concatenated onto the end later once the length of the match loop is known
-
6
microcode 'SQPG MACT'
-
6
match_microcode = stage.current_bank.last
-
-
6
prematch_cycle_count = cycle_count
-
6
match_conditions.each(&:call)
-
-
6
match_loop_cycle_count = cycle_count - prematch_cycle_count
-
-
# Pad the compare vectors out to a multiple of 8 per the ADV documentation
-
6
until match_loop_cycle_count % 8 == 0
-
28
cycle
-
28
match_loop_cycle_count += 1
-
end
-
-
# Use 8 wait vectors by default to keep the overall number of cycles as a multiple of 8
-
6
mrpt = 8
-
-
6
number_of_loops = (timeout_in_cycles.to_f / (match_loop_cycle_count + mrpt)).ceil
-
-
# There seems to be a limit on the max MACT value, so account for longer times by expanding
-
# the wait loop
-
6
while number_of_loops > 262_144
-
mrpt = mrpt * 2 # Keep this as a multiple of 8
-
number_of_loops = (timeout_in_cycles.to_f / (match_loop_cycle_count + mrpt)).ceil
-
end
-
-
6
match_microcode.concat(" #{number_of_loops};") unless @inhibit_vectors
-
-
# Now do the wait loop, mrpt should always be a multiple of 8
-
6
microcode "SQPG MRPT #{mrpt};"
-
-
# Should be no compares in the wait cycles
-
6
dut.pins.each do |name, pin|
-
162
pin.save
-
162
pin.dont_care if pin.comparing?
-
end
-
6
mrpt.cycles
-
168
dut.pins.each { |name, pin| pin.restore }
-
-
# This is just used as a marker by the vector translator to indicate the end of the MRPT
-
# vectors, it does not end up in the final pattern binary.
-
# It is also used in a similar manner by Origen when generating SMT8 patterns.
-
6
microcode 'SQPG PADDING;'
-
-
# For multiple match conditions do something more like the J750 approach where branching based on
-
# miscompares is used to keep the loop going
-
else
-
3
if options[:check_for_fails]
-
cc 'Return preserving existing errors if the pattern has already failed before arriving here'
-
cycle(repeat: propagation_delay)
-
microcode 'SQPG RETC 1 1;'
-
end
-
-
3
loop_microcode = ''
-
3
loop_cycles = 0
-
3
loop_vectors 2 do
-
3
loop_microcode = stage.current_bank.last
-
3
preloop_cycle_count = cycle_count
-
3
match_conditions.each do |condition|
-
6
condition.call
-
6
cc 'Wait for failure to propagate'
-
6
cycle(repeat: propagation_delay)
-
6
cc 'Exit match loop if pin has matched (no error), otherwise clear error and remain in loop'
-
6
microcode 'SQPG RETC 0 0;'
-
end
-
3
loop_cycles = cycle_count - preloop_cycle_count
-
end
-
-
3
unless @inhibit_vectors
-
2
number_of_loops = (timeout_in_cycles.to_f / loop_cycles).ceil
-
-
2
loop_microcode.sub!('2', number_of_loops.to_s)
-
end
-
-
3
if options[:force_fail_on_timeout]
-
3
fail_conditions.each(&:call)
-
end
-
end
-
end
-
-
# Returns the number of cycles to wait for any fails to propagate through the pipeline based on
-
# the current timeset
-
2
def propagation_delay
-
# From 'Calculating the buffer cycles for JMPE and RETC (and match loops)' in SmarTest docs
-
6
data_queue_buffer = (([105, 64 + ((125 + current_period_in_ns - 1) / current_period_in_ns).ceil].min + 3) * 8) + 72
-
# Don't know how to calculate at runtime, hardcoding these to some default values for now
-
6
number_of_sites = 128
-
6
sclk_period = 40
-
6
prop_delay_buffer = 195 + ((2 * number_of_sites + 3) * (sclk_period / 2))
-
6
data_queue_buffer + prop_delay_buffer
-
end
-
-
# Add a loop to the pattern.
-
#
-
# Pass in the number of times to execute it, all vectors
-
# generated by the given block will be captured in the loop.
-
#
-
# ==== Examples
-
# $tester.loop_vectors 3 do # Do this 3 times...
-
# $tester.cycle
-
# some_other_method_to_generate_vectors
-
# end
-
#
-
# For compatibility with the J750 you can supply a name as the first argument
-
# and that will simply be ignored when generated for the V93K tester...
-
#
-
# $tester.loop_vectors "my_loop", 3 do # Do this 3 times...
-
# $tester.cycle
-
# some_other_method_to_generate_vectors
-
# end
-
2
def loop_vectors(name = nil, number_of_loops = 1, _global = false)
-
# The name argument is present to maych J750 API, sort out the
-
12
unless name.is_a?(String)
-
6
name, number_of_loops, global = nil, name, number_of_loops
-
end
-
12
if number_of_loops > 1
-
9
microcode "SQPG LBGN #{number_of_loops};"
-
9
yield
-
9
microcode 'SQPG LEND;'
-
else
-
3
yield
-
end
-
end
-
2
alias_method :loop_vector, :loop_vectors
-
-
# An internal method called by Origen to create the pattern header
-
2
def pattern_header(options = {})
-
16
options = {
-
}.merge(options)
-
16
pin_list = ordered_pins.map do |p|
-
85
if Origen.app.pin_pattern_order.include?(p.id)
-
# specified name overrides pin name
-
if (p.is_a?(Origen::Pins::PinCollection)) || p.id != p.name
-
p.id.to_s # groups or aliases can be lower case
-
else
-
p.id.to_s.upcase # pins must be uppercase
-
end
-
else
-
85
if (p.is_a?(Origen::Pins::PinCollection)) || p.id != p.name
-
25
p.name.to_s # groups or aliases can be lower case
-
else
-
60
p.name.to_s.upcase # pins must be uppercase
-
end
-
end
-
end.join(' ')
-
16
microcode "FORMAT #{pin_list};"
-
16
if ordered_pins.size > 0
-
85
max_pin_name_length = ordered_pins.map(&:name).max { |a, b| a.length <=> b.length }.length
-
101
pin_widths = ordered_pins.map { |p| p.size - 1 }
-
-
16
max_pin_name_length.times do |i|
-
600
cc((' ' * 50) + ordered_pins.map.with_index { |p, x| ((p.name[i] || ' ') + ' ' * pin_widths[x]).gsub('_', '-') }.join(' '))
-
end
-
end
-
end
-
-
# An internal method called by Origen to generate the pattern footer
-
2
def pattern_footer(options = {})
-
options = {
-
16
end_in_ka: false
-
}.merge(options)
-
16
if options[:end_in_ka]
-
1
Origen.log.warning '93K keep alive not yet implemented!'
-
1
ss 'WARNING: 93K keep alive not yet implemented!'
-
end
-
16
microcode 'SQPG STOP;' unless options[:subroutine]
-
end
-
-
# Returns an array of subroutines called while generating the current pattern
-
2
def called_subroutines
-
46
@called_subroutines ||= []
-
end
-
-
# Returns an array of subroutines created by the current pattern
-
2
def local_subroutines # :nodoc:
-
4
@local_subroutines ||= []
-
end
-
-
# All vectors generated with the supplied block will have all pins set
-
# to the repeat previous state. Any pins that are changed state within
-
# the block will still update to the supplied value.
-
# ==== Example
-
# # All pins except invoke will be assigned the repeat previous code
-
# # in the generated vector. On completion of the block they will
-
# # return to their previous state, except for invoke which will
-
# # retain the value assigned within the block.
-
# $tester.repeat_previous do
-
# $top.pin(:invoke).drive(1)
-
# $tester.cycle
-
# end
-
2
def repeat_previous
-
Origen.app.pin_map.each { |_id, pin| pin.repeat_previous = true }
-
yield
-
Origen.app.pin_map.each { |_id, pin| pin.repeat_previous = false }
-
end
-
-
2
def before_timeset_change(options = {})
-
24
microcode "SQPG CTIM #{options[:new].name};" unless level_period?
-
end
-
end
-
end
-
end
-
2
require 'origen_testers/smartest_based_tester/base/processors/extract_flow_vars'
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class Base
-
2
class Flow < ATP::Formatter
-
2
include OrigenTesters::Flow
-
-
RELATIONAL_OPERATOR_STRINGS = {
-
2
eq: '==',
-
ne: '!=',
-
gt: '>',
-
ge: '>=',
-
lt: '<',
-
le: '<='
-
}
-
-
2
attr_accessor :test_suites, :test_methods, :lines, :stack, :var_filename
-
# Returns an array containing all runtime variables which get set by the flow
-
2
attr_reader :set_runtime_variables
-
-
2
attr_accessor :add_flow_enable, :flow_name, :flow_bypass, :flow_description, :subdirectory
-
-
2
def self.generate_flag_name(flag)
-
1697
case flag[0]
-
when '$'
-
237
flag[1..-1]
-
else
-
1460
flag.upcase
-
end
-
end
-
-
2
def smt8?
-
17866
tester.smt8?
-
end
-
-
2
def var_filename
-
15
@var_filename || 'global'
-
end
-
-
2
def set_var_filename(new_var_filename)
-
@var_filename = new_var_filename
-
end
-
-
2
def subdirectory
-
1338
@subdirectory ||= begin
-
111
if smt8?
-
70
parents = []
-
70
f = parent
-
70
while f
-
86
parents.unshift(File.basename(f.filename, '.*').to_s.downcase)
-
86
f = f.parent
-
end
-
70
if Origen.interface.respond_to?(:insertion) && tester.insertion_in_the_flow_path
-
File.join tester.package_namespace, Origen.interface.insertion.to_s, 'flows', *parents
-
else
-
70
File.join tester.package_namespace, 'flows', *parents
-
end
-
else
-
41
'testflow/mfh.testflow.group'
-
end
-
end
-
end
-
-
2
def filename
-
3356
base = super.gsub('_flow', '')
-
3356
if smt8?
-
2864
flow_name(base) + '.flow'
-
else
-
492
base
-
end
-
end
-
-
2
def flow_enable_var_name
-
24
var = filename.sub(/\..*/, '').upcase
-
24
if smt8?
-
6
'ENABLE'
-
else
-
18
generate_flag_name("#{var}_ENABLE")
-
end
-
end
-
-
2
def flow_name(filename = nil)
-
2948
@flow_name_ = @flow_name unless smt8?
-
2948
@flow_name_ ||= begin
-
86
flow_name = (filename || self.filename).sub(/\..*/, '').upcase
-
86
if smt8?
-
72
flow_name.gsub(' ', '_')
-
else
-
14
flow_name
-
end
-
end
-
end
-
-
2
def flow_bypass
-
103
@flow_bypass || false
-
end
-
-
2
def flow_description
-
16
@flow_description || ''
-
end
-
-
2
def hardware_bin_descriptions
-
23
@hardware_bin_descriptions ||= {}
-
end
-
-
2
def flow_variables
-
6034
@flow_variables ||= begin
-
84
vars = Processors::ExtractFlowVars.new.run(ast)
-
84
if !smt8? || (smt8? && top_level?)
-
30
if add_flow_enable
-
8
if add_flow_enable == :enabled
-
7
vars[:all][:referenced_enables] << [flow_enable_var_name, 1]
-
7
vars[:this_flow][:referenced_enables] << [flow_enable_var_name, 1]
-
else
-
1
vars[:all][:referenced_enables] << [flow_enable_var_name, 0]
-
1
vars[:this_flow][:referenced_enables] << [flow_enable_var_name, 0]
-
end
-
8
vars[:empty?] = false
-
end
-
end
-
84
vars
-
end
-
end
-
-
2
def at_flow_start
-
112
model # Call to ensure the signature gets populated
-
end
-
-
2
def on_top_level_set
-
59
if top_level?
-
59
if smt8?
-
16
@limits_file = platform::LimitsFile.new(self, manually_register: true, filename: filename.sub(/\..*/, ''), test_modes: @test_modes)
-
else
-
43
@limits_file = platform::LimitsFile.new(self, manually_register: true, filename: "#{name}_limits", test_modes: @test_modes)
-
end
-
else
-
@limits_file = top_level.limits_file
-
end
-
end
-
-
2
def limits_file
-
156
@limits_file
-
end
-
-
2
def at_flow_end
-
# Take whatever the test modes are set to at the end of the flow as what we go with
-
59
@test_modes = tester.limitfile_test_modes
-
end
-
-
2
def ast
-
349
@ast = nil unless @finalized
-
349
@ast ||= begin
-
30
unique_id = smt8? ? nil : sig
-
30
atp.ast(unique_id: unique_id, optimization: :smt,
-
implement_continue: !tester.force_pass_on_continue,
-
optimize_flags_when_continue: !tester.force_pass_on_continue
-
)
-
end
-
end
-
-
# Returns an array containing all sub-flow objects, not just the immediate children
-
2
def all_sub_flows
-
826
@all_sub_flows ||= begin
-
68
sub_flows = []
-
68
extract_sub_flows(self, sub_flows)
-
68
sub_flows
-
end
-
end
-
-
# @api private
-
2
def extract_sub_flows(flow, sub_flows)
-
154
flow.children.each do |id, sub_flow|
-
86
sub_flows << sub_flow
-
86
extract_sub_flows(sub_flow, sub_flows)
-
end
-
154
sub_flows
-
end
-
-
# Returns the sub_flow object corresponding to the given sub_flow AST
-
2
def sub_flow_from(sub_flow_ast)
-
108
path = sub_flow_ast.find(:path).value
-
768
sub_flow = all_sub_flows.find { |f| File.join(f.subdirectory, f.filename) == path }
-
end
-
-
# This is called by Origen on each flow after they have all been executed but before they
-
# are finally written/rendered
-
2
def finalize(options = {})
-
138
if smt8?
-
122
return unless top_level? || options[:called_by_top_level]
-
68
super
-
# Refresh the ast before finalized gets set to true
-
# If ast gets called by the user the finalized flag will lock it to the incorrect value
-
68
ast
-
68
@finalized = true
-
# All flows have now been executed and the top-level contains the final AST.
-
# The AST contained in each child flow may not be complete since it has not been subject to the
-
# full-flow processing, e.g. to set flags in the event of a reference to a test being made from
-
# outside of a sub-flow.
-
# So here we substitute the AST in all sub-flows with the corresponding sub-flow node from the
-
# top-level AST, then we finalize the sub-flows with the final AST in place and then later final
-
# writing/rendering will be called as normal.
-
68
if top_level?
-
14
ast.find_all(:sub_flow, recursive: true).each do |sub_flow_ast|
-
54
sub_flow = sub_flow_from(sub_flow_ast)
-
54
unless sub_flow
-
fail "Something went wrong, couldn't find the sub-flow object for path #{path}"
-
end
-
# on_fail and on_pass nodes are removed because they will be rendered by the sub-flow's parent
-
54
sub_flow.instance_variable_set(:@ast, sub_flow_ast.remove(:on_fail, :on_pass).updated(:flow))
-
54
sub_flow.instance_variable_set(:@finalized, true) # To stop the AST being regenerated
-
end
-
14
options[:called_by_top_level] = true
-
68
all_sub_flows.each { |f| f.finalize(options) }
-
14
options.delete(:called_by_top_level)
-
end
-
else
-
16
super
-
16
@finalized = true
-
end
-
84
if smt8?
-
68
@indent = (add_flow_enable && top_level?) ? 3 : 2
-
else
-
16
@indent = add_flow_enable ? 2 : 1
-
end
-
84
@lines = []
-
84
@lines_buffer = []
-
84
@open_test_methods = []
-
84
@open_test_names = []
-
84
@post_test_lines = []
-
84
@stack = { on_fail: [], on_pass: [] }
-
84
@set_runtime_variables = ast.excluding_sub_flows.set_flags
-
84
global_flags.each do |global_var_name|
-
756
@set_runtime_variables.delete(global_var_name)
-
756
@set_runtime_variables.delete('$' + global_var_name)
-
end
-
84
process(ast)
-
84
unless smt8?
-
16
unless flow_variables[:empty?]
-
12
Origen.interface.variables_file(self).add_variables(flow_variables)
-
end
-
end
-
84
test_suites.finalize
-
84
test_methods.finalize
-
84
if smt8?
-
68
shmoo_tests.finalize
-
end
-
84
if tester.create_limits_file && top_level?
-
15
render_limits_file
-
end
-
end
-
-
2
def render_limits_file
-
15
if limits_file
-
15
limits_file.test_modes = @test_modes
-
15
limits_file.generate(ast)
-
15
limits_file.write_to_file
-
end
-
end
-
-
2
def line(str, options = {})
-
7274
if options[:already_indented]
-
263
line = str
-
else
-
7011
if smt8?
-
2222
line = (' ' * @indent) + str
-
else
-
4789
line = ' ' + (' ' * (@indent - 1)) + str
-
end
-
end
-
7274
if @lines_buffer.last
-
263
@lines_buffer.last << line
-
else
-
7011
@lines << line
-
end
-
end
-
-
# Any calls to line made within the given block will be returned in an array, rather than
-
# immediately being put into the @lines array
-
2
def capture_lines
-
460
@lines_buffer << []
-
460
yield
-
460
@lines_buffer.pop
-
end
-
-
2
def on_test(node)
-
925
test_suite = node.find(:object).to_a[0]
-
925
if test_suite.is_a?(String)
-
82
name = test_suite
-
else
-
843
name = test_suite.name
-
843
test_method = test_suite.test_method
-
843
if test_method.respond_to?(:test_name) && test_method.test_name == '' &&
-
n = node.find(:name)
-
test_method.test_name = n.value
-
end
-
end
-
-
4776
if node.children.any? { |n| t = n.try(:type); t == :on_fail || t == :on_pass } ||
-
!stack[:on_pass].empty? || !stack[:on_fail].empty?
-
250
if smt8?
-
line "#{name}.execute();"
-
else
-
250
line "run_and_branch(#{name})"
-
end
-
1510
process_all(node.to_a.reject { |n| t = n.try(:type); t == :on_fail || t == :on_pass })
-
250
on_pass = node.find(:on_pass)
-
250
on_fail = node.find(:on_fail)
-
-
250
if on_fail && on_fail.find(:continue) && tester.force_pass_on_continue
-
if test_method.respond_to?(:force_pass)
-
test_method.force_pass = 1
-
else
-
Origen.log.error 'Force pass on continue has been enabled, but the test method does not have a force_pass attribute!'
-
Origen.log.error " #{node.source}"
-
exit 1
-
end
-
@open_test_methods << test_method
-
else
-
250
if test_method.respond_to?(:force_pass)
-
test_method.force_pass = 0
-
end
-
250
@open_test_methods << nil
-
end
-
-
250
if smt8?
-
line "if (#{name}.pass) {"
-
else
-
250
line 'then'
-
250
line '{'
-
end
-
250
@indent += 1
-
250
pass_branch do
-
250
process_all(on_pass) if on_pass
-
250
stack[:on_pass].each { |n| process_all(n) }
-
end
-
250
@indent -= 1
-
250
if smt8?
-
line '} else {'
-
else
-
250
line '}'
-
250
line 'else'
-
250
line '{'
-
end
-
250
@indent += 1
-
250
fail_branch do
-
250
process_all(on_fail) if on_fail
-
272
stack[:on_fail].each { |n| process_all(n) }
-
end
-
250
@indent -= 1
-
250
line '}'
-
-
250
@open_test_methods.pop
-
else
-
675
if smt8?
-
line "#{name}.execute();"
-
else
-
675
line "run(#{name});"
-
end
-
end
-
end
-
-
2
def on_render(node)
-
15
node.to_a[0].split("\n").each do |l|
-
15
line(l)
-
end
-
end
-
-
2
def on_if_job(node)
-
80
jobs, *nodes = *node
-
80
jobs = clean_job(jobs)
-
80
state = node.type == :if_job
-
80
if smt8?
-
32
if jobs.size == 1
-
22
condition = jobs.first
-
else
-
30
condition = jobs.map { |j| "(#{j})" }.join(' || ')
-
end
-
32
line "if (#{condition}) {"
-
else
-
48
condition = jobs.join(' or ')
-
48
line "if #{condition} then"
-
48
line '{'
-
end
-
80
@indent += 1
-
80
process_all(node) if state
-
80
@indent -= 1
-
80
if smt8?
-
32
line '} else {'
-
else
-
48
line '}'
-
48
line 'else'
-
48
line '{'
-
end
-
80
@indent += 1
-
80
process_all(node) unless state
-
80
@indent -= 1
-
80
line '}'
-
end
-
2
alias_method :on_unless_job, :on_if_job
-
-
2
def on_condition_flag(node, state)
-
403
flag, *nodes = *node
-
403
else_node = node.find(:else)
-
403
if smt8?
-
184
if flag.is_a?(Array)
-
42
condition = flag.map { |f| "(#{generate_flag_name(f)} == 1)" }.join(' || ')
-
else
-
170
condition = "#{generate_flag_name(flag)} == 1"
-
end
-
184
line "if (#{condition}) {"
-
else
-
219
if flag.is_a?(Array)
-
54
condition = flag.map { |f| "@#{generate_flag_name(f)} == 1" }.join(' or ')
-
else
-
198
condition = "@#{generate_flag_name(flag)} == 1"
-
end
-
219
line "if #{condition} then"
-
219
line '{'
-
end
-
403
@indent += 1
-
403
if state
-
343
process_all(node.children - [else_node])
-
else
-
60
process(else_node) if else_node
-
end
-
403
@indent -= 1
-
403
if smt8?
-
184
line '} else {'
-
else
-
219
line '}'
-
219
line 'else'
-
219
line '{'
-
end
-
403
@indent += 1
-
403
if state
-
343
process(else_node) if else_node
-
else
-
60
process_all(node.children - [else_node])
-
end
-
403
@indent -= 1
-
403
line '}'
-
end
-
-
2
def on_if_enabled(node)
-
154
flag, *nodes = *node
-
154
state = node.type == :if_enabled
-
154
on_condition_flag(node, state)
-
end
-
2
alias_method :on_unless_enabled, :on_if_enabled
-
-
2
def on_if_flag(node)
-
249
flag, *nodes = *node
-
249
state = node.type == :if_flag
-
249
on_condition_flag(node, state)
-
end
-
2
alias_method :on_unless_flag, :on_if_flag
-
-
2
def on_whenever(node)
-
12
expressions, *nodes = *node
-
12
and_string = ' and '
-
12
or_string = ' or '
-
12
if smt8?
-
8
and_string = ' && '
-
8
or_string = ' || '
-
end
-
12
case node.type
-
when :whenever_all
-
9
condition = expressions.map { |e| "#{generate_expr_string(e)}" }.join(and_string)
-
when :whenever_any
-
9
condition = expressions.map { |e| "#{generate_expr_string(e)}" }.join(or_string)
-
else
-
12
condition = expressions.map { |e| "#{generate_expr_string(e)}" }.join('ERROR')
-
end
-
-
12
if smt8?
-
8
line "if (#{condition})"
-
else
-
4
line "if #{condition} then"
-
end
-
12
line '{'
-
12
@indent += 1
-
12
process_all(node.children)
-
12
@indent -= 1
-
12
line '}'
-
12
line 'else'
-
12
line '{'
-
12
line '}'
-
end
-
2
alias_method :on_whenever_any, :on_whenever
-
2
alias_method :on_whenever_all, :on_whenever
-
-
2
def on_loop(node, options = {})
-
22
start = node.to_a[0]
-
22
if start.is_a?(String)
-
3
start = generate_flag_name(start)
-
3
unless smt8?
-
1
start = "@#{start}"
-
end
-
end
-
22
stop = node.to_a[1]
-
22
if stop.is_a?(String) && smt8?
-
stop = generate_flag_name(stop)
-
22
elsif stop.is_a?(String)
-
fail 'loops with \'stop\' defined as a variable cannot be supported in the defined environments.'
-
end
-
22
step = node.to_a[2]
-
22
if smt8? && !(step == -1 || step == 1)
-
fail 'SMT8 does not support steps other than -1 or 1.'
-
end
-
22
if node.to_a[3].nil?
-
fail 'You must supply a loop variable name!'
-
else
-
22
var = generate_flag_name(node.to_a[3])
-
end
-
22
test_num_inc = node.to_a[4]
-
22
unless smt8?
-
8
var = "@#{var}"
-
end
-
# num = (stop - start) / step + 1
-
# Handle increment/decrement
-
22
if step < 0
-
6
compare = '>'
-
6
incdec = "- #{step * -1}"
-
else
-
16
compare = '<'
-
16
incdec = "+ #{step}"
-
end
-
22
if tester.smt7?
-
8
line "for #{var} = #{start}; #{var} #{compare} #{stop + step} ; #{var} = #{var} #{incdec}; do"
-
8
line "test_number_loop_increment = #{test_num_inc}"
-
8
line '{'
-
8
@indent += 1
-
8
process_all(node.children)
-
8
@indent -= 1
-
8
line '}'
-
14
elsif smt8?
-
14
line "for (#{var} : #{start}..#{stop})"
-
14
line '{'
-
14
@indent += 1
-
14
process_all(node.children)
-
14
@indent -= 1
-
14
line '}'
-
else
-
fail 'Environment was not supported for flow loops.'
-
end
-
end
-
-
2
def generate_expr_string(node, options = {})
-
18
return node unless node.respond_to?(:type)
-
18
case node.type
-
when :eq, :ne, :gt, :ge, :lt, :le
-
18
result = "#{generate_expr_term(node.to_a[0])} " # operand 1
-
18
result += "#{RELATIONAL_OPERATOR_STRINGS[node.type]} " # relational condition
-
18
result += "#{generate_expr_term(node.to_a[1])}" # operand 2
-
18
result
-
else
-
fail "Relational operator '#{node.type}' not supported"
-
end
-
end
-
-
2
def generate_expr_term(val)
-
50
return val if val.is_a?(Fixnum) || val.is_a?(Integer) || val.is_a?(Float)
-
21
case val[0]
-
when '$'
-
12
if smt8?
-
8
"#{val[1..-1]}"
-
else
-
4
"@#{val[1..-1]}"
-
end
-
else
-
9
if val.is_a? String
-
9
"\"#{val}\""
-
else
-
val
-
end
-
end
-
end
-
-
2
def on_set(node)
-
14
flag = generate_flag_name(node.to_a[0])
-
14
val = generate_expr_term(node.to_a[1])
-
14
if smt8?
-
4
line "#{flag} = #{val};"
-
else
-
10
line "@#{flag} = #{val};"
-
end
-
end
-
-
2
def on_enable(node)
-
6
flag = node.value.upcase
-
6
if smt8?
-
4
line "#{flag} = 1;"
-
else
-
2
line "@#{flag} = 1;"
-
end
-
end
-
-
2
def on_disable(node)
-
3
flag = node.value.upcase
-
3
if smt8?
-
2
line "#{flag} = 0;"
-
else
-
1
line "@#{flag} = 0;"
-
end
-
end
-
-
2
def on_set_flag(node)
-
245
flag = generate_flag_name(node.value)
-
# This means if we are currently generating an on_test node and tester.force_pass_on_continue has been set
-
245
if @open_test_methods.last
-
if pass_branch?
-
if smt8?
-
@post_test_lines.last << "#{flag} = #{@open_test_names.last}.setOnPassFlags;"
-
else
-
if @open_test_methods.last.respond_to?(:on_pass_flag)
-
if @open_test_methods.last.on_pass_flag == ''
-
@open_test_methods.last.on_pass_flag = flag
-
else
-
Origen.log.error "The test method cannot set #{flag} on passing, because it already sets: #{@open_test_methods.last.on_pass_flag}"
-
Origen.log.error " #{node.source}"
-
exit 1
-
end
-
else
-
Origen.log.error 'Force pass on continue has been requested, but the test method does not have an :on_pass_flag attribute:'
-
Origen.log.error " #{node.source}"
-
exit 1
-
end
-
end
-
else
-
if smt8?
-
@post_test_lines.last << "#{flag} = #{@open_test_names.last}.setOnFailFlags;"
-
else
-
if @open_test_methods.last.respond_to?(:on_fail_flag)
-
if @open_test_methods.last.on_fail_flag == ''
-
@open_test_methods.last.on_fail_flag = flag
-
else
-
Origen.log.error "The test method cannot set #{flag} on failing, because it already sets: #{@open_test_methods.last.on_fail_flag}"
-
Origen.log.error " #{node.source}"
-
exit 1
-
end
-
else
-
Origen.log.error 'Force pass on continue has been requested, but the test method does not have an :on_fail_flag attribute:'
-
Origen.log.error " #{node.source}"
-
exit 1
-
end
-
end
-
end
-
else
-
245
if smt8?
-
106
line "#{flag} = 1;"
-
else
-
139
line "@#{flag} = 1;"
-
end
-
end
-
end
-
-
2
def on_unset_flag(node)
-
3
flag = generate_flag_name(node.value)
-
3
if smt8?
-
2
line "#{flag} = 0;"
-
else
-
1
line "@#{flag} = 0;"
-
end
-
end
-
-
# Note that for smt8?, this should never be hit anymore since groups are now generated as sub-flows
-
2
def on_group(node)
-
1148
on_fail = node.children.find { |n| n.try(:type) == :on_fail }
-
1148
on_pass = node.children.find { |n| n.try(:type) == :on_pass }
-
104
group_name = unique_group_name(node.find(:name).value)
-
104
if smt8?
-
line '// *******************************************************'
-
line "// GROUP - #{group_name}"
-
line '// *******************************************************'
-
else
-
104
line '{'
-
end
-
104
@indent += 1
-
104
stack[:on_fail] << on_fail if on_fail
-
104
stack[:on_pass] << on_pass if on_pass
-
104
process_all(node.children - [on_fail, on_pass])
-
104
stack[:on_fail].pop if on_fail
-
104
stack[:on_pass].pop if on_pass
-
104
@indent -= 1
-
104
bypass = node.find(:bypass).try(:value) || flow_bypass
-
104
comment = node.find(:comment).try(:value) || ''
-
104
if smt8?
-
line '// *******************************************************'
-
line "// /GROUP - #{group_name}"
-
line '// *******************************************************'
-
else
-
104
if bypass
-
9
line "}, groupbypass, open,\"#{group_name}\", \"\""
-
else
-
95
line "}, open,\"#{group_name}\", \"\""
-
end
-
end
-
end
-
-
2
def on_set_result(node)
-
234
bin = node.find(:bin).try(:value)
-
234
desc = node.find(:bin).to_a[1]
-
234
sbin = node.find(:softbin).try(:value)
-
234
sdesc = node.find(:softbin).to_a[1] || 'fail'
-
234
overon = (node.find(:not_over_on).try(:value) == true) ? 'not_over_on' : 'over_on'
-
234
if bin && desc
-
7
hardware_bin_descriptions[bin] ||= desc
-
end
-
-
234
if smt8?
-
# Currently only rendering pass bins or those not associated with a test (should come from the bin
-
# table if its associated with a test)
-
110
if node.to_a[0] == 'pass' || @open_test_methods.empty?
-
6
line "addBin(#{sbin || bin});"
-
end
-
else
-
124
if node.to_a[0] == 'pass'
-
10
line "stop_bin \"#{sbin}\", \"\", , good, noreprobe, green, #{bin}, over_on;"
-
else
-
114
if tester.create_limits_file
-
6
line 'multi_bin;'
-
else
-
108
line "stop_bin \"#{sbin}\", \"#{sdesc}\", , bad, noreprobe, red, #{bin}, #{overon};"
-
end
-
end
-
end
-
end
-
-
2
def on_log(node)
-
418
if smt8?
-
202
line "println(\"#{node.to_a[0]}\");"
-
else
-
216
line "print_dl(\"#{node.to_a[0]}\");"
-
end
-
end
-
-
2
def unique_group_name(name)
-
104
@group_names ||= {}
-
104
if @group_names[name]
-
29
@group_names[name] += 1
-
29
"#{name}_#{@group_names[name]}"
-
else
-
75
@group_names[name] = 1
-
75
name
-
end
-
end
-
-
2
def clean_job(job)
-
80
var = smt8? ? 'JOB' : '@JOB'
-
183
[job].flatten.map { |j| "#{var} == \"#{j.to_s.upcase}\"" }
-
end
-
-
2
private
-
-
2
def pass_branch
-
476
open_branch_types << :pass
-
476
yield
-
476
open_branch_types.pop
-
end
-
-
2
def fail_branch
-
484
open_branch_types << :fail
-
484
yield
-
484
open_branch_types.pop
-
end
-
-
2
def pass_branch?
-
open_branch_types.last == :pass
-
end
-
-
2
def fail_branch?
-
open_branch_types.last == :fail
-
end
-
-
2
def open_branch_types
-
1920
@open_branch_types ||= []
-
end
-
-
2
def generate_flag_name(flag)
-
851
self.class.generate_flag_name(flag)
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class Base
-
2
module Generator
-
2
extend ActiveSupport::Concern
-
-
2
autoload :Placeholder, 'origen_testers/generator/placeholder'
-
-
2
included do
-
112
include Interface # adds the interface helpers/Origen hook-up
-
end
-
-
# This is just to give all interfaces an initialize that takes
-
# one argument. The super is important for cases where this module
-
# is included late via Testers::ProgramGenerators
-
2
def initialize(options = {})
-
109
super
-
109
@initialized = true
-
end
-
-
# @api private
-
# This will be called at the start of every Flow.create block, :top_level will be
-
# true when it is a top-level Flow.create block
-
2
def _internal_startup(options)
-
59
if options[:top_level]
-
59
if options.key?(:unique_test_names)
-
3
self.unique_test_names = options[:unique_test_names]
-
end
-
59
flow.flow_name = options[:flow_name]
-
59
flow.flow_bypass = options[:flow_bypass].nil? ? false : options[:flow_bypass]
-
59
flow.flow_description = options[:flow_description] || OrigenTesters::Flow.flow_comments.join(' ')
-
end
-
end
-
-
2
def add_tml(name, methods)
-
159
methods[:class_name] ||= name.to_s.camelize
-
159
custom_tmls[name] = methods
-
end
-
2
alias_method :add_test_method_library, :add_tml
-
-
# @api private
-
2
def at_flow_start
-
112
f = flow
-
112
f.at_flow_start
-
# Initialize this to the value currently set on the tester, any further setting of
-
# this by the interface will override
-
112
flow.add_flow_enable = tester.add_flow_enable
-
112
self.unique_test_names = tester.unique_test_names
-
112
@pattern_master_filename = nil
-
end
-
-
# @api private
-
2
def at_flow_end
-
59
flow.at_flow_end
-
end
-
-
# @api private
-
2
def at_run_start
-
34
flow.at_run_start
-
34
@@flow_sheets = nil
-
34
@@pattern_masters = nil
-
34
@@pattern_compilers = nil
-
34
@@variables_files = nil
-
34
@@limits_workbook = nil
-
34
limits_workbook if tester.smt8? && !generating_sub_program?
-
end
-
2
alias_method :reset_globals, :at_run_start
-
-
2
def resources_filename=(name)
-
46
self.pattern_master_filename = name
-
46
self.pattern_references_name = name
-
46
flow.var_filename = name
-
end
-
-
2
def pattern_master_filename=(name)
-
46
@pattern_master_filename = name
-
end
-
-
2
def pattern_master_filename
-
3029
@pattern_master_filename || 'global'
-
end
-
-
# Returns the current flow object (Origen.interface.flow)
-
2
def flow(id = Origen.file_handler.current_file.basename('.rb').to_s)
-
9677
return @current_flow if @current_flow
-
8431
id = id.to_s.sub(/_resources?/, '')
-
8431
filename = id.split('.').last
-
8431
return flow_sheets[id] if flow_sheets[id] # will return flow if already existing
-
136
p = platform::Flow.new
-
136
p.inhibit_output if Origen.interface.resources_mode?
-
136
if id == Origen.file_handler.current_file.basename('.rb').to_s && Origen.interface.try(:use_flow_name_for_top_level)
-
p.filename = Origen.interface.flow_name
-
else
-
136
p.filename = filename
-
end
-
136
p.test_suites ||= platform::TestSuites.new(p)
-
136
p.test_methods ||= platform::TestMethods.new(p)
-
136
flow_sheets[id] = p
-
end
-
-
# @api private
-
2
def with_flow(name)
-
54
@flow_stack ||= []
-
54
@current_flow = nil
-
54
f = flow(name)
-
54
@flow_stack << f
-
54
@current_flow = @flow_stack.last
-
54
yield
-
54
@flow_stack.pop
-
54
@current_flow = @flow_stack.last
-
54
f
-
end
-
-
# Returns the pattern master file (.pmfl) for the current flow, by default a common pattern
-
# master file called 'global' will be used for all flows.
-
# To use a different one set the resources_filename at the start of the flow.
-
2
def pattern_master
-
1477
pattern_masters[pattern_master_filename] ||= begin
-
20
m = platform::PatternMaster.new(manually_register: true)
-
20
name = "#{pattern_master_filename}.pmfl"
-
20
name = "#{Origen.config.program_prefix}_#{name}" if Origen.config.program_prefix
-
20
m.filename = name
-
20
m.id = pattern_master_filename
-
20
m
-
end
-
end
-
-
# Returns a hash containing all pattern master generators
-
2
def pattern_masters
-
1672
@@pattern_masters ||= {}
-
end
-
-
# Returns the pattern compiler file (.aiv) for the current flow, by default a common pattern
-
# compiler file called 'global' will be used for all flows.
-
# To use a different one set the resources_filename at the start of the flow.
-
2
def pattern_compiler
-
1474
pattern_compilers[pattern_master_filename] ||= begin
-
19
m = platform::PatternCompiler.new(manually_register: true)
-
19
name = "#{pattern_master_filename}.aiv"
-
19
name = "#{Origen.config.program_prefix}_#{name}" if Origen.config.program_prefix
-
19
m.filename = name
-
19
m.id = pattern_master_filename
-
19
m
-
end
-
end
-
-
# Returns a hash containing all pattern compiler generators
-
2
def pattern_compilers
-
1669
@@pattern_compilers ||= {}
-
end
-
-
# Returns the variables file for the current or given flow, by default a common variable
-
# file called 'global' will be used for all flows.
-
# To use a different one set the resources_filename at the start of the flow.
-
2
def variables_file(flw = nil)
-
15
name = (flw || flow).var_filename
-
15
variables_files[name] ||= begin
-
11
m = platform::VariablesFile.new(manually_register: true)
-
11
filename = "#{name}_vars.tf"
-
11
filename = "#{Origen.config.program_prefix}_#{filename}" if Origen.config.program_prefix
-
11
m.filename = filename
-
11
m.id = name
-
11
m
-
end
-
end
-
-
# Returns a hash containing all variables file generators
-
2
def variables_files
-
210
@@variables_files ||= {}
-
end
-
-
# @api private
-
2
def pattern_reference_recorded(name, options = {})
-
# Will be called everytime a pattern reference is made that the ATE should be aware of,
-
# don't need to remember it as it can be fetched from all_pattern_references later, but
-
# need to instantiate a pattern master and compiler to handle it later
-
1474
pattern_master
-
1474
pattern_compiler
-
end
-
-
2
def test_suites
-
1506
flow.test_suites
-
end
-
-
2
def test_methods
-
1512
flow.test_methods
-
end
-
-
2
def flow_sheets
-
17059
@@flow_sheets ||= {}.with_indifferent_access
-
end
-
-
# Returns an array containing all sheet generators.
-
# All Origen program generators must implement this method
-
2
def sheet_generators # :nodoc:
-
195
g = []
-
195
flow_sheets.each do |_name, sheet|
-
1709
g << sheet
-
end
-
195
pattern_masters.each do |name, sheet|
-
326
g << sheet
-
end
-
195
pattern_compilers.each do |name, sheet|
-
325
g << sheet
-
end
-
195
variables_files.each do |name, sheet|
-
11
g << sheet
-
end
-
195
g << limits_workbook if tester.smt8? && !generating_sub_program?
-
195
g
-
end
-
-
# Returns an array containing all flow sheet generators.
-
# All Origen program generators must implement this method
-
2
def flow_generators
-
g = []
-
flow_sheets.each do |_name, sheet|
-
g << sheet
-
end
-
g
-
end
-
-
2
private
-
-
2
def custom_tmls
-
172
@custom_tmls ||= {}
-
end
-
end
-
end
-
end
-
end
-
2
require 'origen_testers/smartest_based_tester/base/processors/extract_bin_names'
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class Base
-
2
class LimitsFile < ATP::Formatter
-
2
include OrigenTesters::Generator
-
-
2
attr_reader :flow, :test_modes, :flowname, :bin_names
-
-
2
def initialize(flow, options = {})
-
59
@flow = flow
-
59
@flowname = flow.filename.sub(/\..*/, '') # Base off the filename since it will include any prefix
-
59
@used_test_numbers = {}
-
59
@test_modes = Array(options[:test_modes])
-
59
@empty = true
-
59
@smt8 = tester.smt8?
-
end
-
-
2
def header
-
15
if smt8?
-
14
@test_path = []
-
14
l = 'Test Suite,Test,Test Number,Test Text'
-
14
if test_modes.empty?
-
14
l += ',Low Limit,High Limit'
-
else
-
l += ',Low Limit'
-
(test_modes.size - 1).times { l += ',' }
-
l += ',High Limit'
-
(test_modes.size - 1).times { l += ',' }
-
end
-
14
l += ',Unit,Soft Bin'
-
14
lines << l
-
-
14
l = ',,,'
-
14
if test_modes.empty?
-
14
l += ',default,default'
-
else
-
test_modes.each { |mode| l += ",#{mode}" }
-
test_modes.each { |mode| l += ",#{mode}" }
-
end
-
14
lines << l
-
-
else
-
1
l = '"Suite name","Pins","Test name","Test number"'
-
1
if test_modes.empty?
-
1
l += ',"Lsl","Lsl_typ","Usl_typ","Usl","Units","Bin_s_num","Bin_s_name","Bin_h_num","Bin_h_name","Bin_type","Bin_reprobe","Bin_overon","Test_remarks"'
-
1
lines << l
-
else
-
l += (',"Lsl","Lsl_typ","Usl_typ","Usl","Units"' * test_modes.size) + ',"Bin_s_num","Bin_s_name","Bin_h_num","Bin_h_name","Bin_type","Bin_reprobe","Bin_overon","Test_remarks"'
-
lines << l
-
l = '"Test mode",,,'
-
test_modes.each do |mode|
-
l += ",\"#{mode}\",\"#{mode}\",\"#{mode}\",\"#{mode}\",\"#{mode}\""
-
end
-
l += ',,,,,,,,'
-
lines << l
-
end
-
end
-
end
-
-
2
def test_modes=(modes)
-
15
@test_modes = Array(modes)
-
end
-
-
2
def generate(ast)
-
15
@bin_names = Processors::ExtractBinNames.new.run(ast)
-
15
header
-
15
process(ast)
-
end
-
-
2
def lines
-
774
@lines ||= []
-
end
-
-
2
def subdirectory
-
104
if tester.smt7?
-
6
'testtable/limits'
-
else
-
98
"#{tester.package_namespace}/limits"
-
end
-
end
-
-
2
def on_test(node)
-
730
o = {}
-
730
o[:suite_name] = extract_test_suite_name(node)
-
-
730
lines << line(extract_line_options(node, o))
-
-
730
node.find_all(:sub_test).each do |sub_test|
-
lines << line(extract_line_options(sub_test, o.dup))
-
end
-
-
730
process_all(node.children)
-
end
-
-
2
def on_sub_flow(node)
-
54
@test_path << Pathname.new(node.find(:path).value).basename('.*').to_s
-
54
process_all(node.children)
-
54
@test_path.pop
-
end
-
-
# Returns true if the AST provided when initializing this limits table generator did not
-
# contain any tests, i.e. the resultant limits file is empty
-
2
def empty?
-
@empty
-
end
-
-
2
def limits_workbook
-
124
Origen.interface.limits_workbook
-
end
-
-
2
private
-
-
2
def smt8?
-
6861
@smt8
-
end
-
-
2
def extract_line_options(node, o)
-
730
o[:test_name] = extract_test_name(node, o)
-
730
o[:test_number] = extract_test_number(node, o)
-
730
o[:limits] = extract_limits(node, o)
-
730
o[:priority] = extract_priority(node, o)
-
730
o[:test_text] = node.find(:test_text).try(:value)
-
730
if on_fail = node.find(:on_fail)
-
204
if set_result = on_fail.find(:set_result)
-
102
if bin = set_result.find(:bin)
-
102
o[:bin_h_num] = bin.to_a[0] || o[:bin_h_num]
-
102
o[:bin_h_name] = bin_names[:hard][bin.to_a[0]][:name]
-
end
-
102
if sbin = set_result.find(:softbin)
-
34
o[:bin_s_num] = sbin.to_a[0] || o[:bin_s_num]
-
34
if o[:bin_s_name].nil?
-
34
o[:bin_s_name] = bin_names[:soft][sbin.to_a[0]][:name]
-
end
-
end
-
end
-
204
delayed = on_fail.find(:delayed)
-
204
if delayed && !delayed.to_a[0]
-
o[:bin_overon] = 'no'
-
204
elsif (delayed && delayed.to_a[0]) || tester.delayed_binning
-
o[:bin_overon] = 'on'
-
else
-
204
o[:bin_overon] = 'no'
-
end
-
204
if smt8?
-
198
if o[:bin_s_num]
-
28
limits_workbook.add_softbin o[:bin_s_num], name: o[:bin_s_name], bin: o[:bin_h_num], priority: o[:priority]
-
end
-
198
if o[:bin_h_num]
-
96
limits_workbook.add_bin o[:bin_h_num], name: o[:bin_h_name]
-
end
-
end
-
end
-
730
o
-
end
-
-
2
def extract_limits(node, o)
-
730
modes = test_modes
-
730
lims = {}
-
730
(modes + [nil]).each do |mode|
-
730
lims[mode] = {}
-
730
if node.find(:nolimits)
-
lims[mode][:lsl] = nil
-
lims[mode][:lsl_typ] = 'NA'
-
lims[mode][:usl] = nil
-
lims[mode][:usl_typ] = 'NA'
-
else
-
730
limits = node.find_all(:limit)
-
730
if limits.empty?
-
# Assume it is a functional test in this case
-
695
lims[mode][:lsl] = 0
-
695
lims[mode][:lsl_typ] = 'GE'
-
695
lims[mode][:usl] = 0
-
695
lims[mode][:usl_typ] = 'LE'
-
else
-
95
limits.find_all { |l| l.to_a[3].to_s == mode.to_s }.each do |limit|
-
60
limit = limit.to_a
-
60
if limit[1] =~ /^G/i
-
30
lims[mode][:lsl] = limit[0]
-
30
lims[mode][:lsl_typ] = limit[0] ? limit[1].to_s.upcase : nil
-
30
lims[mode][:lsl_typ] = 'GE' if lims[mode][:lsl_typ] == 'GTE'
-
else
-
30
lims[mode][:usl] = limit[0]
-
30
lims[mode][:usl_typ] = limit[0] ? limit[1].to_s.upcase : nil
-
30
lims[mode][:usl_typ] = 'LE' if lims[mode][:usl_typ] == 'LTE'
-
end
-
60
lims[mode][:units] = limit[2]
-
end
-
end
-
end
-
end
-
730
lims
-
end
-
-
2
def extract_test_number(node, o)
-
730
number = (node.find(:number) || []).to_a[0]
-
730
if number
-
714
if n1 = @used_test_numbers[number]
-
if n1.has_source? && node.has_source?
-
Origen.log.error "Test number #{number} has been assigned more than once in limits file #{filename} (flow: #{flowname}):"
-
Origen.log.error " #{n1.source}"
-
Origen.log.error " #{node.source}"
-
exit 1
-
else
-
fail "Test number #{number} cannot be assigned to #{o[:suite_name]} in limits file #{filename} (flow: #{flowname}), since it has already be used for #{@used_test_numbers[number]}!"
-
end
-
end
-
714
@used_test_numbers[number] = node
-
714
number
-
end
-
end
-
-
2
def extract_test_suite_name(node)
-
730
test_obj = node.find(:object).to_a[0]
-
730
if test_obj.is_a?(Hash)
-
name = test_obj['Test']
-
else
-
730
name = test_obj.respond_to?(:name) ? test_obj.name : test_obj if test_obj
-
end
-
730
name
-
end
-
-
2
def extract_priority(node, o)
-
730
test_obj = node.find(:priority).to_a[0]
-
730
if test_obj.is_a?(Hash)
-
priority = test_obj['Priority']
-
else
-
730
priority = test_obj.respond_to?(:priority) ? test_obj.priority : test_obj if test_obj
-
end
-
730
priority
-
end
-
-
2
def extract_test_name(node, o)
-
730
test_obj = node.find(:object).to_a[0]
-
730
if smt8?
-
722
if test_obj.is_a?(Hash) && test_obj['Sub Test Name']
-
name = test_obj['Sub Test Name']
-
else
-
722
name = test_obj.try(:sub_test_name)
-
end
-
end
-
730
unless name
-
730
if test_obj.is_a?(Hash) && test_obj['Test Name']
-
name = test_obj['Test Name']
-
730
elsif test_obj.is_a?(String)
-
100
name = test_obj
-
else
-
630
name = (node.find(:name) || []).to_a[0] || extract_test_suite_name(node, o) || o[:suite_name]
-
end
-
end
-
730
name
-
end
-
-
2
def line(options)
-
730
@empty = false
-
-
730
if smt8?
-
# "Test Suite"
-
722
if @test_path.empty?
-
384
l = "#{options[:suite_name]}"
-
else
-
338
l = "#{@test_path.join('.')}.#{options[:suite_name]}"
-
end
-
# "Test"
-
722
l << f(options[:test_name])
-
# "Test Number"
-
722
l << f(options[:test_number])
-
# "Test Text"
-
722
if options[:test_text]
-
2
l << f(options[:test_text])
-
else
-
720
names = ["#{options[:suite_name]}", "#{options[:test_name]}"]
-
720
l << f(names.uniq.join('.'))
-
end
-
722
if test_modes.empty?
-
# "Low Limit"
-
722
l << f((options[:limits][nil] || {})[:lsl])
-
# "High Limit"
-
722
l << f((options[:limits][nil] || {})[:usl])
-
else
-
test_modes.each do |mode|
-
# "Low Limit"
-
l << f((options[:limits][mode] || options[:limits][nil] || {})[:lsl] || 'na')
-
end
-
test_modes.each do |mode|
-
# "High Limit"
-
l << f((options[:limits][mode] || options[:limits][nil] || {})[:usl] || 'na')
-
end
-
end
-
# "Unit"
-
722
l << f((options[:limits][nil] || {})[:units])
-
# "Soft Bin"
-
722
l << f(options[:bin_s_num])
-
-
else
-
# "Suite name"
-
8
l = "\"#{options[:suite_name]}\""
-
# "Pins"
-
8
l << f(options[:pins])
-
# "Test name"
-
8
l << f(options[:test_name])
-
# "Test number"
-
8
l << f(options[:test_number])
-
8
if test_modes.empty?
-
# "Lsl"
-
8
l << f((options[:limits][nil] || {})[:lsl])
-
# "Lsl_typ"
-
8
l << f((options[:limits][nil] || {})[:lsl_typ])
-
# "Usl_typ"
-
8
l << f((options[:limits][nil] || {})[:usl_typ])
-
# "Usl"
-
8
l << f((options[:limits][nil] || {})[:usl])
-
# "Units"
-
8
l << f((options[:limits][nil] || {})[:units])
-
else
-
test_modes.each do |mode|
-
# "Lsl"
-
l << f((options[:limits][mode] || options[:limits][nil] || {})[:lsl])
-
# "Lsl_typ"
-
l << f((options[:limits][mode] || options[:limits][nil] || {})[:lsl_typ])
-
# "Usl_typ"
-
l << f((options[:limits][mode] || options[:limits][nil] || {})[:usl_typ])
-
# "Usl"
-
l << f((options[:limits][mode] || options[:limits][nil] || {})[:usl])
-
# "Units"
-
l << f((options[:limits][mode] || options[:limits][nil] || {})[:units])
-
end
-
end
-
# "Bin_s_num"
-
8
l << f(options[:bin_s_num])
-
# "Bin_s_name"
-
8
l << f(options[:bin_s_name])
-
# "Bin_h_num"
-
8
l << f(options[:bin_h_num])
-
# "Bin_h_name"
-
8
l << f(options[:bin_h_name])
-
# "Bin_type"
-
8
l << f(options[:bin_type])
-
# "Bin_reprobe"
-
8
l << f(options[:bin_reprobe])
-
# "Bin_overon"
-
8
l << f(options[:bin_overon])
-
# "Test_remarks"
-
8
l << f(options[:test_remarks])
-
end
-
730
l
-
end
-
-
2
def f(value)
-
5182
if smt8?
-
5054
",#{value}"
-
else
-
128
",\"#{value}\""
-
end
-
end
-
end
-
end
-
end
-
end
-
2
require 'pathname'
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class Base
-
2
class PatternCompiler
-
2
include OrigenTesters::Generator
-
-
2
attr_accessor :filename, :part_patterns, :id
-
-
2
def initialize(flow = nil)
-
19
@part_patterns = []
-
end
-
-
2
def subroutines
-
11
(references[:subroutine][:all] + references[:subroutine][:ate]).map do |p|
-
p.strip.sub(/\..*/, '')
-
end.uniq.sort
-
end
-
-
2
def patterns
-
12
(references[:main][:all] + references[:main][:ate]).map do |p|
-
958
p.strip.sub(/\..*/, '')
-
end.uniq.sort
-
end
-
-
2
def references
-
46
Origen.interface.all_pattern_references[id]
-
end
-
-
2
def to_be_written?
-
19
tester.smt7?
-
end
-
end
-
end
-
end
-
end
-
2
require 'pathname'
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class Base
-
2
class PatternMaster
-
2
include OrigenTesters::Generator
-
-
2
attr_reader :flow, :paths
-
2
attr_accessor :filename, :id, :subdirectory
-
-
2
def initialize(flow = nil)
-
20
@flow = flow
-
20
@paths = {}
-
end
-
-
2
def filename
-
356
@filename || flow.filename.sub('.tf', '.pmfl')
-
end
-
-
2
def subdirectory
-
68
@subdirectory ||= 'vectors'
-
end
-
-
2
def paths
-
11
{ '../vectors' => patterns }
-
end
-
-
# def add(name, options = {})
-
# name, subdir = extract_subdir(name, options)
-
# name += '.binl.gz' unless name =~ /binl.gz$/
-
# # Don't want to ask Origen to compile these, but do want them in the v93k
-
# # compile list
-
# if name =~ /_part\d+\.binl\.gz$/
-
# Origen.interface.pattern_compiler.part_patterns << name
-
# else
-
# Origen.interface.referenced_patterns << name
-
# end
-
# paths[subdir] ||= []
-
# # Just add it, duplicates will be removed at render time
-
# paths[subdir] << name unless paths[subdir].include?(name)
-
# end
-
-
2
def patterns
-
11
return_arr = (references[:subroutine][:all] + references[:subroutine][:ate] +
-
references[:main][:all] + references[:main][:ate]).map do |p|
-
848
p = p.strip
-
848
p += '.binl.gz' unless p =~ /binl.gz$/
-
end.uniq
-
11
if $tester.multiport
-
1
return_arr += (references[:main][:all] + references[:main][:ate]).map do |p|
-
110
p = p.strip
-
110
p = $tester.multiport_name(p)
-
110
p += '.binl.gz' unless p =~ /.binl.gz$/
-
end.uniq
-
end
-
11
return_arr
-
end
-
-
2
def references
-
46
Origen.interface.all_pattern_references[id]
-
end
-
-
2
def to_be_written?
-
19
tester.smt7?
-
end
-
-
2
private
-
-
2
def extract_subdir(name, options = {})
-
p = Pathname.new(name.to_s)
-
name = p.basename.to_s
-
subdir = p.dirname.to_s
-
# if subdir == '.'
-
# # In future may support setting a default subdir via the interface
-
# end
-
[name, subdir]
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class Base
-
2
module Processors
-
2
class ExtractBinNames < ATP::Processor
-
2
def run(node, options = {})
-
15
@bin_names = { soft: {}, hard: {} }
-
15
process(node)
-
15
@bin_names
-
end
-
-
2
def on_bin_descriptions(node)
-
node.children.each do |n|
-
number, name = *n
-
record number, name, type: n.type
-
end
-
end
-
-
2
def on_test(node)
-
730
if on_fail = node.find(:on_fail)
-
204
if set_result = on_fail.find(:set_result)
-
102
if bin = set_result.find(:bin)
-
102
if bin.to_a[1]
-
record(*bin.to_a, supplied: true, type: :hard)
-
else
-
102
record(*bin.to_a, default_name(node), type: :hard)
-
end
-
end
-
102
if sbin = set_result.find(:softbin)
-
34
if sbin.to_a[1]
-
record(*sbin.to_a, supplied: true, type: :soft)
-
else
-
34
record(*sbin.to_a, default_name(node), type: :soft)
-
end
-
end
-
end
-
end
-
730
process_all(node.children)
-
end
-
-
2
private
-
-
2
def default_name(node)
-
136
test_obj = node.find(:object).to_a[0]
-
136
if test_obj.is_a?(Hash)
-
suite_name = test_obj['Test']
-
else
-
136
suite_name = test_obj.respond_to?(:name) ? test_obj.name : test_obj
-
end
-
136
test_name = (node.find(:name) || []).to_a[0] || suite_name
-
136
if suite_name == test_name
-
58
suite_name
-
else
-
78
"#{suite_name}_#{test_name}"
-
end
-
end
-
-
2
def record(number, name, options)
-
136
table = @bin_names[options[:type]]
-
136
if !table[number] || (options[:supplied] && !table[number][:supplied])
-
36
table[number] = { name: name, supplied: options[:supplied] }
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
2
require 'set'
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class Base
-
2
module Processors
-
# Returns an array containing all runtime control variables from the given AST node
-
# and their default values
-
2
class ExtractFlowVars < ATP::Processor
-
2
OWNERS = [:all, :this_flow, :sub_flows]
-
2
CATEGORIES = [:jobs, :referenced_flags, :set_flags, :unset_flags, :add_flags,
-
:set_flags_extern, :unset_flags_extern, :add_flags_extern,
-
:referenced_enables, :set_enables]
-
-
2
def run(node, options = {})
-
84
@variables = {}
-
84
@variables[:empty?] = true
-
84
OWNERS.each do |t|
-
252
@variables[t] = {}
-
2772
CATEGORIES.each { |c| @variables[t][c] = Set.new }
-
end
-
84
@sub_flow_depth = 0
-
84
process(node)
-
84
OWNERS.each do |t|
-
252
CATEGORIES.each do |c|
-
2520
curr_vars = @variables[t][c].to_a.dup
-
2520
flag_classes = curr_vars.map(&:class)
-
2520
if flag_classes.include?(String) && flag_classes.include?(Symbol)
-
10
curr_vars.map!(&:to_s)
-
end
-
2520
@variables[t][c] = curr_vars.sort do |x, y|
-
3500
x = x[0] if x.is_a?(Array)
-
3500
y = y[0] if y.is_a?(Array)
-
3500
x <=> y
-
end
-
end
-
end
-
84
@variables
-
end
-
-
2
def on_sub_flow(node)
-
86
@sub_flow_depth += 1
-
86
children = node.children
-
86
on_fail = node.find_all(:on_fail)
-
86
children -= on_fail
-
86
on_pass = node.find_all(:on_pass)
-
86
children -= on_pass
-
86
process_all(children)
-
86
@sub_flow_depth -= 1
-
86
process_all(on_fail)
-
86
process_all(on_pass)
-
end
-
-
2
def on_if_job(node)
-
96
add ['JOB', ''], :jobs
-
96
process_all(node.children)
-
end
-
2
alias_method :on_unless_job, :on_if_job
-
-
2
def on_if_flag(node)
-
283
flag, *nodes = *node
-
283
[flag].flatten.each do |f|
-
301
add generate_flag_name(f), :referenced_flags
-
end
-
283
process_all(nodes)
-
end
-
2
alias_method :on_unless_flag, :on_if_flag
-
-
2
def on_set_flag(node)
-
279
add generate_flag_name(node.value), :set_flags
-
# Also separate flags which have been set and which should be externally visible
-
279
if !node.to_a.include?('auto_generated') || node.to_a.include?('extern')
-
50
add generate_flag_name(node.value), :set_flags_extern
-
end
-
end
-
-
2
def on_unset_flag(node)
-
3
add generate_flag_name(node.value), :unset_flags
-
# Also separate flags which have been set and which should be externally visible
-
3
if !node.to_a.include?('auto_generated') || node.to_a.include?('extern')
-
3
add generate_flag_name(node.value), :unset_flags_extern
-
end
-
end
-
-
2
def on_add_flag(node)
-
6
add generate_flag_name(node.value), :add_flags
-
# Also separate flags which have been set and which should be externally visible
-
6
if !node.to_a.include?('auto_generated') || node.to_a.include?('extern')
-
6
add generate_flag_name(node.value), :add_flags_extern
-
end
-
end
-
-
2
def on_if_enabled(node)
-
176
flag, *nodes = *node
-
176
[flag].flatten.each do |f|
-
184
add generate_flag_name(f), :referenced_enables
-
end
-
176
process_all(nodes)
-
end
-
2
alias_method :on_unless_enabled, :on_if_enabled
-
-
2
def on_enable(node)
-
9
flag = node.value.upcase
-
9
add flag, :set_enables
-
end
-
2
alias_method :on_disable, :on_enable
-
-
2
def on_set(node)
-
14
flag = generate_flag_name(node.to_a[0])
-
14
add flag, :set_enables
-
end
-
-
2
private
-
-
2
def in_sub_flow?
-
951
@sub_flow_depth > 0
-
end
-
-
2
def add(var, type)
-
951
@variables[:empty?] = false
-
951
@variables[:all][type] << var
-
951
if in_sub_flow?
-
132
@variables[:sub_flows][type] << var
-
else
-
819
@variables[:this_flow][type] << var
-
end
-
end
-
-
2
def generate_flag_name(flag)
-
846
SmartestBasedTester::Base::Flow.generate_flag_name(flag)
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class Base
-
2
class TestMethod
-
2
FORMAT_TYPES = [:current, :voltage, :time, :frequency, :string, :integer, :double, :boolean, :class, :list_strings, :list_classes]
-
-
# Returns the object representing the test method library that the
-
# given test method is defined in
-
2
attr_reader :library
-
2
attr_reader :type
-
2
attr_reader :id
-
2
alias_method :name, :id
-
# Returns an hash corresponding to the parameters that the given test method has.
-
# The keys are the parameter names and the values are the parameter type.
-
2
attr_reader :parameters
-
2
attr_accessor :class_name
-
2
attr_accessor :abs_class_name
-
2
attr_reader :limits
-
2
attr_accessor :limits_id
-
2
alias_method :limit_id, :limits_id
-
2
alias_method :limit_id=, :limits_id=
-
# Used to store the name of the primary test logged in SMT8
-
2
attr_accessor :sub_test_name
-
-
2
def initialize(options)
-
1511
@type = options[:type]
-
1511
@library = options[:library]
-
1511
@class_name = options[:methods].delete(:class_name)
-
1511
@parameters = {}
-
1511
@limits_id = options[:methods].delete(:limits_id) || options[:methods].delete(:limit_id)
-
1511
@limits = TestMethods::Limits.new(self)
-
1511
@limits.render = false if options[:methods].delete(:render_limits_in_tf) == false
-
# Add any methods
-
1511
if options[:methods][:methods]
-
15
methods = options[:methods][:methods]
-
15
@finalize = methods[:finalize]
-
15
methods.each do |method_name, function|
-
24
unless method_name == :finalize
-
9
var_name = "@#{method_name}".gsub(/=|\?/, '_')
-
9
instance_variable_set(var_name, function)
-
9
define_singleton_method method_name do |*args|
-
9
instance_variable_get(var_name).call(self, *args)
-
end
-
end
-
end
-
end
-
# Create attributes corresponding to the test method type represented
-
# by this method instance
-
1511
options[:methods].each do |attr, type_default|
-
4442
unless attr == :limits_type || attr == :aliases || attr == :methods
-
4418
clean_attr = clean_attr_name(attr)
-
4418
type = type_default[0]
-
4418
default = type_default[1]
-
4418
allowed = type_default[2]
-
4418
@parameters[attr] = type
-
4418
aliases = [clean_attr]
-
4418
aliases << clean_attr.underscore if clean_attr.underscore != clean_attr
-
4418
aliases.each do |alias_|
-
4449
define_singleton_method("#{alias_}=") do |v|
-
4515
v = v.to_s if v.is_a?(Symbol)
-
4515
if allowed
-
2101
unless allowed.include?(v)
-
fail "Cannot set #{alias_} to #{v}, valid values are: #{allowed.join(', ')}"
-
end
-
end
-
4515
instance_variable_set("@#{clean_attr}", v)
-
end
-
4449
define_singleton_method(alias_) do
-
12164
instance_variable_get("@#{clean_attr}")
-
end
-
end
-
4418
send("#{clean_attr}=", default)
-
end
-
end
-
1511
if options[:methods][:aliases]
-
9
options[:methods][:aliases].each do |alias_, attr|
-
9
clean_attr = clean_attr_name(attr)
-
9
define_singleton_method("#{alias_}=") do |v|
-
9
send("#{clean_attr}=", v)
-
end
-
9
define_singleton_method(alias_) do
-
send(clean_attr)
-
end
-
end
-
end
-
# Finally set any initial values that have been supplied
-
1511
options[:attrs].each do |k, v|
-
accessor = "#{k}="
-
if respond_to?(accessor)
-
send(accessor, v)
-
else
-
accessor = "#{k.to_s.underscore}="
-
send(accessor, v) if respond_to?(accessor)
-
end
-
end
-
end
-
-
2
def format(attr)
-
4334
clean_attr = clean_attr_name(attr)
-
4334
val = send(clean_attr)
-
4334
if FORMAT_TYPES.include?(parameters[attr])
-
4090
type = parameters[attr]
-
else
-
# The type is based on the value of another attribute
-
244
name = clean_attr_name(parameters[attr])
-
244
if respond_to?(name)
-
95
type = send(name)
-
149
elsif respond_to?(name.sub(/b$/, ''))
-
95
type = inverse_of(send(name.sub(/b$/, '')))
-
54
elsif parameters[attr].is_a?(Hash) || parameters[attr.to_sym].is_a?(Hash)
-
54
type = :hash
-
else
-
fail "Unknown attribute type: #{parameters[attr]}"
-
end
-
end
-
4334
if val.nil? && !tester.print_all_params
-
nil
-
else
-
4334
handle_val_type(val, type, attr)
-
end
-
end
-
-
2
def handle_val_type(val, type, attr)
-
4393
return val if val == '' && !tester.smt8?
-
4373
case type
-
when :current, 'CURR'
-
96
"#{val}[A]"
-
when :voltage, 'VOLT'
-
383
"#{val}[V]"
-
when :time
-
98
"#{val}[s]"
-
when :frequency
-
1
"#{val}[Hz]"
-
when :string
-
3680
val.to_s
-
when :integer
-
28
val.to_i
-
when :double
-
16
val.to_f
-
when :boolean
-
# Check for valid values
-
1
if [0, 1, true, false, 'true', 'false'].include?(val)
-
# Use true/false for smt8 and 0/1 for smt7
-
1
if [1, true, 'true'].include?(val)
-
1
tester.smt8? ? true : 1
-
else
-
tester.smt8? ? false : 0
-
end
-
else
-
fail "Unknown boolean value for attribute #{attr}: #{val}"
-
end
-
when :hash, :class
-
54
val
-
when :list_strings
-
8
unless val.is_a?(Array)
-
fail "#{val} is not an Array. List_strings must have Array values"
-
end
-
8
"##{val}"
-
when :list_classes
-
8
unless val.is_a?(Array)
-
fail "#{val} is not an Array. List_classes must have Array values"
-
end
-
8
"##{val.to_s.gsub('"', '')}"
-
else
-
fail "Unknown type for attribute #{attr}: #{type}"
-
end
-
end
-
-
2
def klass
-
2128
@abs_class_name ||
-
"#{library.klass}.#{@class_name || type.to_s.camelize}"
-
end
-
-
2
def finalize
-
1521
@finalize
-
end
-
-
2
def method_missing(method, *args, &block)
-
250
if limits && limits.respond_to?(method)
-
250
limits.send(method, *args, &block)
-
else
-
super
-
end
-
end
-
-
2
def respond_to?(method)
-
245313
(limits && limits.respond_to?(method)) || super
-
end
-
-
2
def sorted_parameters
-
1494
@parameters.sort_by do |name|
-
4295
if name.is_a?(String)
-
name
-
else
-
4295
if name.to_s[0] == '_'
-
name.to_s.camelize(:upper)
-
else
-
4295
name.to_s.camelize(:lower)
-
end
-
end
-
end
-
end
-
-
2
def remove_parameter(name)
-
3
@parameters.delete(name)
-
end
-
-
2
private
-
-
2
def inverse_of(type)
-
95
case type
-
when :current, 'CURR'
-
:voltage
-
when :voltage, 'VOLT'
-
95
:current
-
else
-
fail "Don't know the inverse of type: #{type}"
-
end
-
end
-
-
2
def clean_attr_name(name)
-
9005
name.to_s.gsub(/\.|-|\s+/, '_')
-
end
-
-
2
def id=(val)
-
1511
@id = val
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class Base
-
2
class TestMethods
-
# Origen::Tester::Generator not included since test methods do not have their
-
# own top-level sheet, they will be incorporated within the flow sheet
-
-
2
require 'origen_testers/smartest_based_tester/base/test_methods/base_tml'
-
2
require 'origen_testers/smartest_based_tester/base/test_methods/limits'
-
2
autoload :AcTml, 'origen_testers/smartest_based_tester/base/test_methods/ac_tml'
-
2
autoload :DcTml, 'origen_testers/smartest_based_tester/base/test_methods/dc_tml'
-
2
autoload :CustomTml, 'origen_testers/smartest_based_tester/base/test_methods/custom_tml'
-
-
2
attr_accessor :flow, :collection
-
-
2
def initialize(flow)
-
136
@flow = flow
-
136
@collection = []
-
136
@ix = 0
-
end
-
-
2
def filename
-
1
flow.filename
-
end
-
-
2
def add(test_method, options = {})
-
1511
collection << test_method
-
1511
test_method.send 'id=', "tm_#{collection.size}"
-
1511
test_method
-
end
-
-
2
def [](ix)
-
collection[ix]
-
end
-
-
# Returns the AC test method library
-
2
def ac_tml
-
1379
@ac_tml ||= AcTml.new(self)
-
end
-
-
# Returns the DC test method library
-
2
def dc_tml
-
95
@dc_tml ||= DcTml.new(self)
-
end
-
-
# Creates an accessor for custom test method libraries the first time they are called
-
2
def method_missing(method, *args, &block)
-
13
custom_tmls = Origen.interface.send(:custom_tmls)
-
13
if custom_tmls[method]
-
13
tml = CustomTml.new(self, custom_tmls[method])
-
13
instance_variable_set "@#{method}", tml
-
13
define_singleton_method method do
-
37
instance_variable_get("@#{method}")
-
end
-
13
send(method)
-
else
-
super
-
end
-
end
-
-
2
def respond_to?(method)
-
!!Origen.interface.send(:custom_tmls)[method] || super
-
end
-
-
2
def finalize
-
84
collection.each do |method|
-
1506
method.finalize.call(method) if method.finalize
-
end
-
end
-
-
2
def sorted_collection
-
2618
@collection.sort_by { |tm| tm.name.to_s }
-
end
-
end
-
end
-
end
-
end
-
1
module OrigenTesters
-
1
module SmartestBasedTester
-
1
class Base
-
1
class TestMethods
-
1
class AcTml < BaseTml
-
TEST_METHODS = {
-
1
frequency_by_digital_capture: {
-
class_name: 'Frequency_byDigitalCapture',
-
vector_variable_name: [:string, ''],
-
algorithm: [:string, 'FFT', %w(FFT LinearFit)],
-
sample_period: [:time, 0],
-
target_frequency: [:frequency, 0],
-
output: [:string, 'None', %w(None ReportUI ShowFailOnly)],
-
test_name: [:string, 'passFrequency_MHz']
-
},
-
functional_test: {
-
test_name: [:string, 'Functional'],
-
output: [:string, 'None', %w(None ReportUI ShowFailOnly)]
-
},
-
spec_search: {
-
max: [:string, nil],
-
method: [:string, nil],
-
min: [:string, nil],
-
output: [:string, 'None', %w(None ReportUI ShowFailOnly)],
-
resolution: [:string, ''],
-
result_pinlist: [:string, ''],
-
setup_pinlist: [:string, ''],
-
spec: [:string, nil],
-
step: [:string, nil],
-
test_name: [:string, 'SpecSearch_Test']
-
}
-
}
-
-
1
def ac_test
-
1379
self
-
end
-
-
1
def klass
-
1977
'ac_tml.AcTest'
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class Base
-
2
class TestMethods
-
# Base class of all test method libraries
-
2
class BaseTml
-
# Returns the test_methods object for the current flow
-
2
attr_reader :test_methods
-
-
2
def initialize(test_methods)
-
91
@test_methods = test_methods
-
end
-
-
2
def method_missing(method, *args, &block)
-
1511
if definitions[method]
-
1511
instantiate_test_method(method, args)
-
else
-
method = method.to_s.underscore.to_sym
-
if definitions[method]
-
instantiate_test_method(method, args)
-
else
-
super
-
end
-
end
-
end
-
-
2
def platform
-
1511
Origen.interface.platform
-
end
-
-
2
def definitions
-
3022
@definitions || self.class::TEST_METHODS
-
end
-
-
2
private
-
-
2
def instantiate_test_method(method, args)
-
1511
m = platform::TestMethod.new methods: definitions[method].dup,
-
1511
attrs: (args.first || {}),
-
type: method,
-
library: self
-
1511
test_methods.add(m)
-
1511
m
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class Base
-
2
class TestMethods
-
2
class CustomTml < BaseTml
-
2
def initialize(test_methods, definitions)
-
13
@definitions = definitions
-
13
@klass = definitions[:class_name]
-
13
super test_methods
-
end
-
-
2
def klass
-
28
@klass || ''
-
end
-
end
-
end
-
end
-
end
-
end
-
1
module OrigenTesters
-
1
module SmartestBasedTester
-
1
class Base
-
1
class TestMethods
-
1
class DcTml < BaseTml
-
TEST_METHODS = {
-
1
continuity: {
-
pinlist: [:string, '@'],
-
test_current: [:current, 10.uA],
-
settling_time: [:time, 1.ms],
-
measurement_mode: [:string, 'PPMUpar', %w(PPMUpar ProgLoad)],
-
polarity: [:string, 'SPOL', %w(SPOL BPOL)],
-
precharge_to_zero_vol: [:string, 'ON', %w(ON OFF)],
-
test_name: [:string, 'passVolt_mv'],
-
output: [:string, 'None', %w(None ReportUI ShowFailOnly)]
-
},
-
dps_connectivity: {
-
dps_pins: [:string, '@'],
-
test_name: [:string, 'DPS_ForceSense'],
-
output: [:string, 'None', %w(None ReportUI ShowFailOnly)]
-
},
-
dps_status: {
-
dps_pins: [:string, '@'],
-
constant_current: [:string, 'OFF', %w(ON OFF)],
-
unregulated: [:string, 'OFF', %w(ON OFF)],
-
over_voltage: [:string, 'OFF', %w(ON OFF)],
-
over_power_temp: [:string, 'OFF', %w(ON OFF)],
-
test_name: [:string, 'DPS_Status'],
-
output: [:string, 'None', %w(None ReportUI ShowFailOnly)]
-
},
-
dvm: {
-
class_name: 'DVM',
-
pinlist: [:string, '@'],
-
settling_time: [:time, 0],
-
measure_mode: [:string, 'PPMUpar', %w(PPMUpar ProgLoad)],
-
test_name: [:string, 'passVoltageLimit_mV'],
-
output: [:string, 'None', %w(None ReportUI ShowFailOnly)]
-
},
-
general_pmu: {
-
class_name: 'GeneralPMU',
-
pinlist: [:string, '@'],
-
force_mode: [:string, 'VOLT', %w(VOLT CURR)],
-
force_value: [:force_mode, 3800.mV],
-
spmu_clamp: [:force_modeb, 0],
-
precharge: [:string, 'OFF', %w(ON OFF)],
-
precharge_voltage: [:voltage, 0],
-
settling_time: [:time, 0],
-
tester_state: [:string, 'CONNECTED', %w(CONNECTED DISCONNECTED UNCHANGED)],
-
termination: [:string, 'OFF', %w(ON OFF)],
-
measure_mode: [:string, 'PPMUpar', %w(PPMUpar PPMUser SPMUser)],
-
relay_switch_mode: [:string, 'DEFAULT(BBM)', ['DEFAULT(BBM)', 'BBM', 'MBB', 'PARALLEL']],
-
ppmu_clamp_low: [:voltage, 0],
-
ppmu_clamp_high: [:voltage, 0],
-
output: [:string, 'None', %w(None ReportUI ShowFailOnly)],
-
test_name: [:string, 'passLimit_uA_mV']
-
},
-
high_z: {
-
pinlist: [:string, '@'],
-
force_voltage: [:voltage, 2500.mV],
-
settling_time: [:time, 0],
-
relay_switch_mode: [:string, 'DEFAULT(BBM)', ['DEFAULT(BBM)', 'BBM', 'MBB', 'PARALLEL']],
-
test_name: [:string, 'passCurrent_uA'],
-
output: [:string, 'None', %w(None ReportUI ShowFailOnly)]
-
},
-
leakage: {
-
pinlist: [:string, '@'],
-
measure: [:string, 'BOTH', %w(BOTH LOW HIGH)],
-
force_voltage_low: [:voltage, 400.mV],
-
force_voltage_high: [:voltage, 3800.mV],
-
spmu_clamp_current_low: [:current, 0],
-
spmu_clamp_current_high: [:current, 0],
-
ppmu_pre_charge: [:string, 'ON', %w(ON OFF)],
-
precharge_voltage_low: [:voltage, 0],
-
precharge_voltage_high: [:voltage, 0],
-
settling_time_low: [:time, 0],
-
settling_time_high: [:time, 0],
-
pre_function: [:string, 'NO', %w(NO ALL ToStopVEC ToStopCYC)],
-
control_test_num_off_functional: [:string, 'NO', %w(NO ALL ToStopVEC ToStopCYC)],
-
stop_cyc_vec_low: [:integer, 0],
-
stop_cyc_vec_high: [:integer, 0],
-
measure_mode: [:string, 'PPMUpar', %w(PPMUpar PPMUser SPMUser)],
-
relay_switch_mode: [:string, 'DEFAULT(BBM)', ['DEFAULT(BBM)', 'BBM', 'MBB', 'PARALLEL']],
-
test_name: [:string, '(passCurrentLow_uA,passCurrentHigh_uA)'],
-
output: [:string, 'None', %w(None ReportUI ShowFailOnly)]
-
},
-
operating_current: {
-
dps_pins: [:string, '@'],
-
samples: [:integer, 4],
-
delay_time: [:time, 0],
-
termination: [:string, 'OFF', %w(ON OFF)],
-
test_name: [:string, 'passCurrLimit_uA'],
-
output: [:string, 'None', %w(None ReportUI ShowFailOnly)]
-
},
-
output_dc: {
-
class_name: 'OutputDC',
-
pinlist: [:string, ''],
-
mode: [:string, 'PROGRAMLOAD', %w(PROGRAMLOAD, PPMU SPMU PPMUTERM SPMUTERM)],
-
measure_level: [:string, 'BOTH', %(BOTH LOW HIGH)],
-
force_current_low: [:current, 0],
-
force_current_high: [:current, 0],
-
max_pass_low: [:voltage, 0],
-
min_pass_low: [:voltage, 0],
-
max_pass_high: [:voltage, 0],
-
min_pass_high: [:voltage, 0],
-
settling_time_low: [:time, 0],
-
settling_time_high: [:time, 0],
-
spmu_clamp_voltage_low: [:voltage, 0],
-
spmu_clamp_voltage_high: [:voltage, 0],
-
vector_range: [:string, ''],
-
test_name: [:string, '(OutputDC_LowLevel[V],OutputDC_HighLevel[V])'],
-
output: [:string, 'None', %w(None ReportUI ShowFailOnly)]
-
},
-
production_iddq: {
-
dps_pins: [:string, 'Vee'],
-
disconnect_pins: [:string, ''],
-
settling_time: [:time, 0],
-
stop_mode: [:string, 'ToStopVEC', %w(ToStopVEC ToStopCYC)],
-
str_stop_vec_cyc_num: [:string, ''],
-
samples: [:integer, 16],
-
check_functional: [:string, 'ON', %w(ON OFF)],
-
control_test_num_of_functional: [:string, 'OFF', %w(ON OFF)],
-
ganged_mode: [:string, 'OFF', %w(ON OFF)],
-
test_name: [:string, 'passCurrLimit_uA'],
-
output: [:string, 'None', %w(None ReportUI ShowFailOnly)]
-
},
-
standby_current: {
-
dps_pins: [:string, '@'],
-
samples: [:integer, 16],
-
termination: [:string, 'OFF', %w(ON OFF)],
-
settling_time: [:time, 0],
-
test_name: [:string, 'passCurrLimit_uA'],
-
output: [:string, 'None', %w(None ReportUI ShowFailOnly)]
-
}
-
}
-
-
1
def dc_test
-
95
self
-
end
-
-
1
def klass
-
123
'dc_tml.DcTest'
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class Base
-
2
class TestMethods
-
2
class Limits
-
2
attr_reader :test_method
-
2
attr_accessor :lo_limit, :hi_limit
-
2
attr_accessor :unit
-
2
attr_accessor :tnum
-
2
attr_accessor :render
-
2
alias_method :lo, :lo_limit
-
2
alias_method :lo=, :lo_limit=
-
2
alias_method :hi, :hi_limit
-
2
alias_method :hi=, :hi_limit=
-
-
2
def initialize(test_method)
-
1511
@test_method = test_method
-
1511
@tnum = ''
-
1511
@render = true
-
end
-
-
2
def unit=(val)
-
case val.to_s.downcase
-
when 'v', 'volts'
-
@unit = 'V'
-
when 'a', 'amps'
-
@unit = 'A'
-
else
-
fail "Limit unit of #{val} not implemented yet!"
-
end
-
end
-
-
2
def to_s
-
851
if !lo_limit && !hi_limit
-
791
if tnum == ''
-
791
"\"#{test_name}\"" + ' = "":"NA":"":"NA":"":"":""'
-
else
-
"\"#{test_name}\"" + " = \"\":\"NA\":\"\":\"NA\":\"\":\"#{tnum}\":\"0\""
-
end
-
60
elsif !lo_limit
-
12
"\"#{test_name}\"" + " = \"\":\"NA\":\"#{hi_limit}\":\"LE\":\"#{unit}\":\"#{tnum}\":\"0\""
-
48
elsif !hi_limit
-
6
"\"#{test_name}\"" + " = \"#{lo_limit}\":\"GE\":\"\":\"NA\":\"#{unit}\":\"#{tnum}\":\"0\""
-
else
-
42
"\"#{test_name}\"" + " = \"#{lo_limit}\":\"GE\":\"#{hi_limit}\":\"LE\":\"#{unit}\":\"#{tnum}\":\"0\""
-
end
-
end
-
-
2
def set_lo_limit(val)
-
self.lo_limit = val
-
end
-
-
2
def set_hi_limit(val)
-
self.hi_limit = val
-
end
-
-
2
def to_atp_attributes
-
1396
r = []
-
1396
if lo_limit
-
78
r << { value: lo_limit, rule: 'LE', units: unit }
-
end
-
1396
if hi_limit
-
84
r << { value: hi_limit, rule: 'GE', units: unit }
-
end
-
1396
r
-
end
-
-
2
def render?
-
852
@render
-
end
-
-
2
private
-
-
2
def test_name
-
851
if test_method.limits_id.nil?
-
851
name = test_method.try(:test_name) || test_method.try(:_test_name) || test_method.try('TestName')
-
851
name || 'Functional'
-
else
-
test_method.limits_id
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class Base
-
2
class TestSuite
-
2
attr_accessor :meta
-
-
2
def initialize(name, attrs = {})
-
1504
@name = name
-
1504
if interface.unique_test_names == :signature
-
854
if interface.flow.sig
-
854
@name = "#{name}_#{interface.flow.sig}"
-
end
-
650
elsif interface.unique_test_names == :flowname || interface.unique_test_names == :flow_name
-
3
@name = "#{name}_#{interface.flow.name.to_s.symbolize}"
-
647
elsif interface.unique_test_names == :preflowname || interface.unique_test_names == :pre_flow_name
-
2
@name = "#{interface.flow.name.to_s.symbolize}_#{name}"
-
645
elsif interface.unique_test_names
-
5
utn_string = interface.unique_test_names.to_s
-
5
if utn_string =~ /^prepend_/
-
2
utn_string = utn_string.gsub(/^prepend_/, '')
-
2
@name = "#{utn_string}_#{name}"
-
else
-
3
utn_string = utn_string.gsub(/^append_/, '')
-
3
@name = "#{name}_#{utn_string}"
-
end
-
end
-
# Set the defaults
-
1504
self.class::DEFAULTS.each do |k, v|
-
6952
send("#{k}=", v)
-
end
-
# Then the values that have been supplied
-
1504
attrs.each do |k, v|
-
4510
send("#{k}=", v) if respond_to?("#{k}=") && k.to_sym != :name
-
end
-
end
-
-
2
def smt8?
-
tester.smt8?
-
end
-
-
2
def pattern=(name)
-
1474
Origen.interface.record_pattern_reference(name) if name
-
1474
@pattern = name
-
end
-
-
2
def inspect
-
1
"<TestSuite: #{name}>"
-
end
-
-
# The name is immutable once the test_suite is created, this will raise an error when called
-
2
def name=(val, options = {})
-
1
fail 'Once assigned the name of a test suite cannot be changed!'
-
end
-
-
2
def method_missing(method, *args, &block)
-
99621
if test_method && test_method.respond_to?(method)
-
99621
test_method.send(method, *args, &block)
-
else
-
super
-
end
-
end
-
-
2
def respond_to?(method)
-
146223
(test_method && test_method.respond_to?(method)) || super
-
end
-
-
2
def interface
-
6458
Origen.interface
-
end
-
-
2
def to_meta
-
5367
m = meta || {}
-
5367
m['Test'] = name
-
5367
m['Test Name'] ||= try(:test_name)
-
5367
m
-
end
-
-
2
def extract_atp_attributes(options)
-
1482
options[:limits] ||= limits.to_atp_attributes
-
end
-
-
2
private
-
-
2
def flags
-
1701
f = []
-
1701
f << 'bypass' if bypass
-
1701
f << 'set_pass' if set_pass
-
1701
f << 'set_fail' if set_fail
-
1701
f << 'hold' if hold
-
1701
f << 'hold_on_fail' if hold_on_fail
-
1701
f << 'output_on_pass' if output_on_pass
-
1701
f << 'output_on_fail' if output_on_fail
-
1701
f << 'value_on_pass' if pass_value
-
1701
f << 'value_on_fail' if fail_value
-
1701
f << 'per_pin_on_pass' if per_pin_on_pass
-
1701
f << 'per_pin_on_fail' if per_pin_on_fail
-
1701
f << 'mx_waves_enable' if log_mixed_signal_waveform
-
1701
f << 'fail_per_label' if fail_per_label
-
1701
f << 'ffc_enable' if ffc_enable
-
1701
f << 'ffv_enable' if ffv_enable
-
1701
f << 'frg_enable' if frg_enable
-
1701
f << 'hw_dsp_disable' if hardware_dsp_disable
-
1701
f << 'force_serial' if force_serial
-
1701
f.empty? ? f : f.join(', ')
-
end
-
-
2
def wrap_if_string(value)
-
4243
if value.is_a?(String)
-
3353
"\"#{value}\""
-
else
-
890
value
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class Base
-
2
class TestSuites
-
# Origen::Tester::Generator not included since test suites do not have their
-
# own top-level sheet, they will be incorporated within the flow sheet
-
-
2
attr_accessor :flow, :collection
-
-
2
def initialize(flow)
-
136
@flow = flow
-
136
@collection = []
-
136
@existing_names = {}
-
# Test names also have to be unique vs. the current flow name
-
136
if tester.smt8?
-
72
@existing_names[flow.filename.sub('.flow', '').to_s] = true
-
end
-
end
-
-
2
def filename
-
1
flow.filename
-
end
-
-
2
def add(name, options = {})
-
1504
symbol = name.is_a?(Symbol)
-
1504
name = make_unique(name)
-
# Ensure names given as a symbol stay as a symbol, this is more for
-
# alignment to existing test cases than anything else
-
1504
name = name.to_sym if symbol
-
1504
suite = platform::TestSuite.new(name, options)
-
1503
@collection << suite
-
# c = Origen.interface.consume_comments
-
# Origen.interface.descriptions.add_for_test_definition(name, c)
-
1503
suite
-
end
-
2
alias_method :run, :add
-
2
alias_method :run_and_branch, :add
-
-
2
def platform
-
1504
Origen.interface.platform
-
end
-
-
2
def finalize
-
# collection.each do |suite|
-
# end
-
end
-
-
2
def sorted_collection
-
2469
@collection.sort_by { |ts| ts.name.to_s }
-
end
-
-
2
private
-
-
2
def make_unique(name)
-
1504
name = name.to_s
-
1504
tempname = name
-
1504
i = 0
-
1504
while @existing_names[tempname]
-
11150
i += 1
-
11150
tempname = "#{name}_#{i}"
-
end
-
1504
@existing_names[tempname] = true
-
1504
tempname
-
end
-
end
-
end
-
end
-
end
-
2
require 'pathname'
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class Base
-
2
class VariablesFile
-
2
include OrigenTesters::Generator
-
-
2
attr_reader :variables
-
2
attr_accessor :filename, :id, :subdirectory
-
-
2
def initialize(options = {})
-
end
-
-
2
def subdirectory
-
62
@subdirectory ||= 'testflow/mfh.testflow.setup'
-
end
-
-
2
def add_variables(vars)
-
12
if @variables
-
2
vars.each do |k, v|
-
8
if k == :empty?
-
2
@variables[:empty?] ||= v
-
else
-
6
v.each do |k2, v2|
-
60
unless v2.empty?
-
8
@variables[k][k2] |= v2
-
end
-
end
-
end
-
end
-
else
-
10
@variables = vars
-
end
-
end
-
-
# What SMT7 calls a flag
-
2
def flags
-
20
if variables
-
20
(variables[:all][:referenced_enables] + variables[:all][:set_enables]).uniq.sort do |x, y|
-
258
x = x[0] if x.is_a?(Array)
-
258
y = y[0] if y.is_a?(Array)
-
# Need to use strings for the comparison as some flags can be a string and some a symbol
-
258
x.to_s <=> y.to_s
-
end
-
end
-
end
-
-
# What SMT7 calls a declaration
-
2
def declarations
-
20
if variables
-
20
(variables[:all][:jobs] + variables[:all][:referenced_flags] + variables[:all][:set_flags] + variables[:all][:unset_flags] + variables[:all][:add_flags]).uniq.sort do |x, y|
-
760
x = x[0] if x.is_a?(Array)
-
760
y = y[0] if y.is_a?(Array)
-
# Need to use strings for the comparison as some declarations can be a string and some a symbol
-
760
x.to_s <=> y.to_s
-
end
-
end
-
end
-
-
2
def to_be_written?
-
10
tester.smt7?
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
def self.suitable_decompiler_for(pattern: nil, tester: nil, **options)
-
7
if pattern && (Pathname(pattern).extname == '.avc')
-
1
OrigenTesters::SmartestBasedTester::Pattern
-
6
elsif tester && tester == 'v93k'
-
OrigenTesters::SmartestBasedTester::Pattern
-
end
-
end
-
2
extend OrigenTesters::Decompiler::API
-
2
register_decompiler(self)
-
-
2
class Pattern < OrigenTesters::Decompiler::Pattern
-
2
require_relative './decompiler/avc'
-
2
extend Avc
-
-
2
@platform = 'v93k'
-
@splitter_config = {
-
2
pinlist_start: /^FORMAT/,
-
-
# The vectors start will be picked up right after the pinlist is parsed.
-
# We'll throw away any whitespace we encounter between the pinlist and
-
# first vector element though.
-
vectors_start: proc do |line:, index:, current_indices:|
-
# The pinlist was encountered. Start the vectors at the next line
-
# that's not just whitespace
-
10
if current_indices[:pinlist_start] && line !~ /^\s/
-
10
next true
-
end
-
false
-
end,
-
-
# V93K doesn't have any endmatter, or vector end delimiter, so just
-
# grab vectors until the end of the file is reached.
-
vectors_end: -1
-
}
-
-
@platform_tokens = {
-
2
comment_start: '#'
-
}
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class Pattern
-
2
require_relative './nodes'
-
-
2
module Avc
-
2
def nodes_namespace
-
13447
OrigenTesters::SmartestBasedTester::Decompiler::Avc
-
end
-
-
2
def parse_frontmatter(raw_frontmatter:, context:)
-
# So far, only seen patterns that have comments and/or whitespace in
-
# the frontmatter. Not sure if anything else is allowed.
-
# For this, every comment will be considered the 'header'
-
10
header = []
-
10
raw_frontmatter.each_with_index do |l, i|
-
178
if !(l =~ Regexp.new('^\s*#')).nil?
-
174
header << l.chomp
-
4
elsif l.strip.empty?
-
# Whitespace. Do nothing.
-
else
-
1
Origen.app!.fail!("Unable to parse pattern frontmatter, at line: #{i}")
-
end
-
end
-
9
OrigenTesters::Decompiler::Nodes::Frontmatter.new(context: context,
-
pattern_header: header,
-
comments: []
-
)
-
end
-
-
2
def parse_pinlist(raw_pinlist:, context:)
-
9
raw_pinlist = raw_pinlist.join('')
-
# The pinlist can be parsed by grabbing everything between the 'format' token and the ';'
-
# character then splitting by whitespace. Whitespace is then stripped to clean
-
# up the names.
-
# E.g.: FORMAT TCLK TDI TDO TMS;
-
9
OrigenTesters::Decompiler::Nodes::Pinlist.new(context: context,
-
pins: raw_pinlist[raw_pinlist.index('FORMAT')..raw_pinlist.index(';') - 1].split(/\s+/)[1..-1].map(&:strip)
-
)
-
end
-
-
2
def parse_vector(raw_vector:, context:, meta:)
-
15554
if raw_vector =~ Regexp.new('^\s*#')
-
# Comment
-
2106
OrigenTesters::Decompiler::Nodes::CommentBlock.new(context: context,
-
comments: raw_vector.split("\n")
-
)
-
13448
elsif raw_vector =~ Regexp.new('^R\d+\s')
-
# Vector
-
12121
elements = raw_vector.split(/\s+/, 2 + context.pinlist.size)
-
12121
elements[-1] = elements[-1].split(/\s/, 2)
-
12121
elements[-1][0] = elements[-1][0].gsub(';', '').chomp
-
12121
elements[-1][1] = elements[-1][1].gsub(';', '').chomp
-
-
12121
nodes_namespace::Vector.new(context: context,
-
repeat: elements[0].gsub('R', '').to_i,
-
timeset: elements[1],
-
12121
pin_states: (elements[2..-2] || []) << elements[-1][0],
-
comment: elements[-1][1]
-
)
-
else
-
# Anything that doesn't start with Rxyz where xyz is some integer
-
# will be considered a sequencer instruction
-
1327
inst_plus_args = raw_vector.split(/\s+/)
-
1327
inst_plus_args.last.gsub!(';', '').strip!
-
-
1326
nodes_namespace::SequencerInstruction.new(context: context,
-
instruction: inst_plus_args[0],
-
arguments: inst_plus_args[1..-1]
-
)
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
module Decompiler
-
2
module Avc
-
2
class SequencerInstruction < OrigenTesters::Decompiler::Nodes::Node
-
2
PLATFORM_NODES = [:instruction, :arguments]
-
-
2
def initialize(instruction:, arguments: [], context:)
-
1326
@execute = false
-
-
1326
@instruction = instruction
-
1326
@arguments = arguments
-
-
1326
super(context: context, type: :sequencer_instruction)
-
end
-
end
-
-
2
class Vector < OrigenTesters::Decompiler::Nodes::Vector
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
module SMT7
-
# This is an internal method use by Origen which returns a fully formatted vector
-
# You can override this if you wish to change the output formatting at vector level
-
2
def format_vector(vec)
-
5953
timeset = vec.timeset ? "#{vec.timeset.name}" : ''
-
5953
pin_vals = vec.pin_vals ? "#{vec.pin_vals} " : ''
-
5953
if vec.repeat # > 1
-
5953
microcode = "R#{vec.repeat}"
-
else
-
microcode = vec.microcode ? vec.microcode : ''
-
end
-
-
5953
if Origen.mode.simulation? || !inline_comments || $_testers_no_inline_comments
-
comment = ''
-
else
-
-
5953
header_comments = []
-
5953
repeat_comment = ''
-
5953
vec.comments.each_with_index do |comment, i|
-
3950
if comment =~ /^#/
-
3925
if comment =~ /^#(R\d+)$/
-
3446
repeat_comment = Regexp.last_match(1) + ' '
-
# Throw away the ############# headers and footers
-
479
elsif comment !~ /^# ####################/
-
321
comment = comment.strip.sub(/^# (## )?/, '')
-
321
if comment == ''
-
# Throw away empty lines at the start/end, but preserve them in the middle
-
unless header_comments.empty? || i == vec.comments.size - 1
-
header_comments << comment
-
end
-
else
-
321
header_comments << comment
-
end
-
end
-
end
-
end
-
-
5953
if vec.pin_vals && ($_testers_enable_vector_comments || vector_comments)
-
comment = "#{vec.number}:#{vec.cycle}"
-
comment += ': ' if !header_comments.empty? || !vec.inline_comment.empty?
-
else
-
5953
comment = ''
-
end
-
5953
comment += header_comments.join("\cm") unless header_comments.empty?
-
5953
unless vec.inline_comment.empty?
-
205
comment += "\cm" unless header_comments.empty?
-
205
comment += "(#{vec.inline_comment})"
-
end
-
5953
comment = "#{repeat_comment}#{comment}"
-
end
-
-
# Max comment length 250 at the end
-
5953
"#{microcode.ljust(25)}#{timeset.ljust(27)}#{pin_vals}# #{comment[0, 247]};"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
module SMT8
-
# This currently defines what subdirectory of the pattern output directory that
-
# patterns will be output to
-
2
def subdirectory
-
20
File.join(package_namespace, 'patterns')
-
end
-
-
# An internal method called by Origen to create the pattern header
-
2
def pattern_header(options = {})
-
15
options = {
-
}.merge(options)
-
15
@program_lines = []
-
15
@program_action_lines = []
-
15
if zip_patterns
-
@program_lines << '<?xml version="1.0" encoding="UTF-8"?>'
-
@program_lines << '<Program xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Program.xsd">'
-
end
-
15
@program_lines << ' <Assignment id="memory" value="SM"/>'
-
15
pin_list = ordered_pins.map do |p|
-
72
if Origen.app.pin_pattern_order.include?(p.id)
-
# specified name overrides pin name
-
if (p.is_a?(Origen::Pins::PinCollection)) || p.id != p.name
-
p.id.to_s # groups or aliases can be lower case
-
else
-
p.id.to_s.upcase # pins must be uppercase
-
end
-
else
-
72
if (p.is_a?(Origen::Pins::PinCollection)) || p.id != p.name
-
14
p.name.to_s # groups or aliases can be lower case
-
else
-
58
p.name.to_s.upcase # pins must be uppercase
-
end
-
end
-
end.join(',')
-
15
@program_lines << " <Instrument id=\"#{pin_list}\">"
-
end
-
-
# An internal method called by Origen to generate the pattern footer
-
2
def pattern_footer(options = {})
-
options = {
-
15
end_in_ka: false
-
}.merge(options)
-
15
if options[:end_in_ka]
-
1
Origen.log.warning '93K keep alive not yet implemented!'
-
1
ss 'WARNING: 93K keep alive not yet implemented!'
-
end
-
15
@program_footer_lines = []
-
15
@program_footer_lines << '</Program>' if zip_patterns
-
end
-
-
# @api private
-
2
def open_and_write_pattern(filename)
-
15
pat_name = Pathname.new(filename).basename.to_s
-
-
15
@gen_vec = 0
-
15
@vector_number = 0
-
15
@vector_lines = []
-
15
@comment_lines = []
-
# @program_lines was already created with the pattern_header
-
-
15
yield
-
-
15
write_gen_vec
-
15
@program_lines << ' </Instrument>'
-
-
15
if zip_patterns
-
tmp_dir = filename.gsub('.', '_')
-
FileUtils.mkdir_p(tmp_dir)
-
program_file = File.join(tmp_dir, 'Program.sprg')
-
vector_file = File.join(tmp_dir, 'Vectors.vec')
-
comments_file = File.join(tmp_dir, 'Comments.cmt')
-
-
File.open(program_file, 'w') do |f|
-
(@program_lines + @program_action_lines + @program_footer_lines).each do |line|
-
f.puts line
-
end
-
end
-
-
File.open(vector_file, 'w') { |f| @vector_lines.each { |l| f.puts l } }
-
File.open(comments_file, 'w') { |f| @comment_lines.each { |l| f.puts l } }
-
-
Dir.chdir tmp_dir do
-
`zip #{pat_name} Program.sprg Vectors.vec Comments.cmt`
-
FileUtils.mv pat_name, filename
-
end
-
else
-
15
File.open filename, 'w' do |f|
-
15
f.puts '<Pattern>'
-
15
f.puts ' <Program>'
-
15
(@program_lines + @program_action_lines + @program_footer_lines).each do |line|
-
286
f.puts ' ' + line
-
end
-
15
f.puts ' </Program>'
-
15
f.puts ' <Vector>'
-
5968
@vector_lines.each { |l| f.puts ' ' + l }
-
15
f.puts ' </Vector>'
-
15
f.puts ' <Comment>'
-
3730
@comment_lines.each { |l| f.puts ' ' + l }
-
15
f.puts ' </Comment>'
-
15
f.puts '</Pattern>'
-
end
-
end
-
ensure
-
15
FileUtils.rm_rf(tmp_dir) if zip_patterns && File.exist?(tmp_dir)
-
end
-
-
# @api private
-
#
-
# The SMT8 microcode is implemented as a post conversion of the SMT7 microcode, rather than
-
# generating SMT8 microcode originally.
-
# This is generally an easier implementation and since they both run on the same h/ware there
-
# should always be a 1:1 feature mapping between the 2 systems.
-
2
def track_and_format_comment(comment)
-
888
if comment =~ /^SQPG/
-
26
if comment =~ /^SQPG PADDING/
-
# A gen vec should not be used for MRPT vectors, the padding instruction marks the end of them
-
2
@gen_vec = 0
-
else
-
24
write_gen_vec
-
24
if comment =~ /^SQPG JSUB ([^;]+);/
-
12
@program_lines << " <Instruction id=\"patternCall\" value=\"#{tester.package_namespace}.patterns.#{Regexp.last_match(1)}\"/>"
-
12
elsif comment =~ /^SQPG MACT (\d+);/
-
2
@program_lines << " <Instruction id=\"match\" value=\"#{Regexp.last_match(1)}\"/>"
-
10
elsif comment =~ /^SQPG MRPT (\d+);/
-
2
@program_lines << " <Instruction id=\"matchRepeat\" value=\"#{Regexp.last_match(1)}\"/>"
-
8
elsif comment =~ /^SQPG LBGN (\d+);/
-
3
@program_lines << " <Instruction id=\"loop\" value=\"#{Regexp.last_match(1)}\"/>"
-
5
elsif comment =~ /^SQPG LEND;/
-
3
@program_lines << " <Instruction id=\"loopEnd\"/>"
-
2
elsif comment =~ /^SQPG RETC (\d) (\d);/
-
2
@program_lines << " <Instruction id=\"returnConditional\">"
-
2
@program_lines << " <Assignment id=\"onFail\" value=\"#{Regexp.last_match(1) == '0' ? 'false' : 'true'}\"/>"
-
2
@program_lines << " <Assignment id=\"resetFail\" value=\"#{Regexp.last_match(2) == '0' ? 'false' : 'true'}\"/>"
-
2
@program_lines << ' </Instruction>'
-
else
-
Origen.log.warning "This SMT7 microcode was not converted to SMT8: #{comment}"
-
end
-
end
-
end
-
end
-
-
# This is an internal method use by Origen which returns a fully formatted vector
-
# You can override this if you wish to change the output formatting at vector level
-
2
def format_vector(vec)
-
5953
has_microcode = vec.microcode && !vec.microcode.empty?
-
5953
has_repeat = vec.repeat && vec.repeat > 1
-
5953
if has_microcode || has_repeat
-
# Close out current gen_vec group
-
52
write_gen_vec
-
52
if has_repeat
-
52
@program_lines << " <Instruction id=\"genVec\" value=\"1\">"
-
52
@program_lines << " <Assignment id=\"repeat\" value=\"#{vec.repeat}\"/>"
-
52
@program_lines << ' </Instruction>'
-
52
@gen_vec -= 1
-
end
-
52
if has_microcode
-
puts vec.microcode
-
end
-
end
-
-
5953
unless Origen.mode.simulation? || !inline_comments || $_testers_no_inline_comments
-
5953
header_comments = []
-
5953
repeat_comment = ''
-
5953
vec.comments.each_with_index do |comment, i|
-
3950
if comment =~ /^#/
-
3925
if comment =~ /^#(R\d+)$/
-
3446
repeat_comment = Regexp.last_match(1) + ' '
-
# Throw away the ############# headers and footers
-
479
elsif comment !~ /^# ####################/
-
321
comment = comment.strip.sub(/^# (## )?/, '')
-
321
if comment == ''
-
# Throw away empty lines at the start/end, but preserve them in the middle
-
unless header_comments.empty? || i == vec.comments.size - 1
-
header_comments << comment
-
end
-
else
-
321
header_comments << comment
-
end
-
end
-
end
-
end
-
-
5953
if vec.pin_vals && ($_testers_enable_vector_comments || vector_comments)
-
comment = "#{vec.number}:#{vec.cycle}"
-
comment += ': ' if !header_comments.empty? || !vec.inline_comment.empty?
-
else
-
5953
comment = ''
-
end
-
# comment += header_comments.join("\cm") unless header_comments.empty?
-
# Seems that SMT8 does not support the above newline char, so identify split lines with something else
-
5953
comment += header_comments.join('----') unless header_comments.empty?
-
5953
unless vec.inline_comment.empty?
-
205
comment += "\cm" unless header_comments.empty?
-
205
comment += "(#{vec.inline_comment})"
-
end
-
5953
c = "#{repeat_comment}#{comment}"
-
5953
@comment_lines << "#{@vector_number} #{c}"[0, 3000] unless c.empty?
-
end
-
-
5953
if vec.pin_vals
-
5953
@vector_lines << vec.pin_vals.gsub(' ', '')
-
5953
@vector_number += 1
-
5953
@gen_vec += 1
-
end
-
end
-
-
# @api private
-
2
def write_gen_vec
-
91
if @gen_vec > 0
-
55
@program_lines << " <Instruction id=\"genVec\" value=\"#{@gen_vec}\"/>"
-
55
@gen_vec = 0
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K < Base
-
2
require 'origen_testers/smartest_based_tester/v93k/generator.rb'
-
end
-
end
-
2
V93K = SmartestBasedTester::V93K
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K
-
# Responsible for building V93K test programs from a collection of sub-programs
-
2
class Builder
-
2
require 'yaml'
-
-
2
autoload :Flow, 'origen_testers/smartest_based_tester/v93k/builder/flow'
-
2
autoload :PatternMaster, 'origen_testers/smartest_based_tester/v93k/builder/pattern_master'
-
-
2
attr_reader :manifest
-
-
2
def build(manifest, options = {})
-
@manifest_dir = Pathname.new(manifest).dirname.to_s
-
@manifest = YAML.load_file(manifest).with_indifferent_access
-
parse_sub_programs
-
render(options)
-
end
-
-
2
private
-
-
2
def render(options)
-
manifest[:flows].each do |name, flow|
-
flow_file = nil
-
pm_file = nil
-
-
flow.each do |sub_program|
-
unless flows[sub_program]
-
puts "Flow #{name} includes sub-program #{sub_program}, but it has not been defined!"
-
exit 1
-
end
-
flow_file ||= Flow.new
-
flow_file.add_sub_flow(flows[sub_program])
-
if pattern_masters[sub_program]
-
pm_file ||= PatternMaster.new
-
pm_file.add_sub_file(pattern_masters[sub_program])
-
end
-
end
-
-
compile_options = {
-
action: :compile,
-
files: "#{Origen.root!}/lib/origen_testers/smartest_based_tester/v93k/templates/template.flow.erb",
-
output_file_name: "#{name}.flow",
-
output_sub_dir: 'testflow',
-
options: { program: flow_file }
-
}.merge(options)
-
-
Origen.app.runner.launch(compile_options)
-
-
if pm_file
-
compile_options = {
-
action: :compile,
-
files: "#{Origen.root!}/lib/origen_testers/smartest_based_tester/v93k/templates/template.pmfl.erb",
-
output_file_name: "#{name}.pmfl",
-
output_sub_dir: 'vectors',
-
options: { program: pm_file }
-
}.merge(options)
-
end
-
Origen.app.runner.launch(compile_options)
-
end
-
end
-
-
2
def parse_sub_programs
-
manifest[:sub_programs].each do |sub_program|
-
name = sub_program[:name]
-
if sub_program[:flow]
-
flows[name] = Flow.new(find_file(sub_program[:flow]))
-
end
-
if sub_program[:pattern_master]
-
pattern_masters[name] = PatternMaster.new(find_file(sub_program[:pattern_master]))
-
end
-
end
-
end
-
-
2
def find_file(file)
-
Origen.file_handler.clean_path_to(file, default_dir: @manifest_dir)
-
end
-
-
2
def flows
-
@flows ||= {}
-
end
-
-
2
def pattern_masters
-
@pattern_masters ||= {}
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K
-
2
class Builder
-
# Responsible for modelling/building the contents of a V93K flow file
-
2
class Flow
-
2
attr_reader :information, :declarations, :flags, :testmethodparameters,
-
:testmethodlimits, :testmethods, :test_suites, :test_flow, :binning,
-
:hardware_bin_descriptions, :file
-
-
2
def initialize(file = nil)
-
@information = {}
-
@declarations = {}
-
@flags = {}
-
@testmethodparameters = {}
-
@testmethodlimits = {}
-
@testmethods = {}
-
@test_suites = {}
-
@test_flow = []
-
@binning = []
-
@hardware_bin_descriptions = {}
-
@groups = {}
-
@file = file
-
parse_file if file
-
end
-
-
2
def add_sub_flow(flow)
-
combine(flow, :information, exclude: 'test_revision')
-
combine(flow, :declarations)
-
combine(flow, :flags)
-
add_test_methods(flow)
-
add_test_suites(flow)
-
add_flow(flow)
-
(binning << flow.binning).flatten!.uniq!
-
combine(flow, :hardware_bin_descriptions)
-
end
-
-
2
private
-
-
2
def parse_file
-
current_section = nil
-
current = nil
-
File.open(file) do |f|
-
f.each_line do |line|
-
if current_section
-
if line =~ /^\s*end\s*$/
-
current_section = nil
-
current = nil
-
else
-
case current_section
-
when :information, :declarations, :flags, :hardware_bin_descriptions
-
if line =~ /^\s*(.*)\s*=\s*(.*)\s*$/
-
send(current_section)[Regexp.last_match(1).strip] = Regexp.last_match(2).strip
-
end
-
when :testmethodparameters, :testmethodlimits, :testmethods, :test_suites
-
if line =~ /^\s*(.*):\s*$/
-
current = Regexp.last_match(1)
-
send(current_section)[current] = {}
-
elsif current
-
if line =~ /^\s*(.*)\s*=\s*(.*)\s*$/
-
send(current_section)[current][Regexp.last_match(1).strip] = Regexp.last_match(2).strip
-
end
-
end
-
when :binning
-
binning << line.strip
-
when :test_flow
-
add_flow_line(line)
-
end
-
end
-
else
-
if line =~ /^\s*(information|declarations|flags|testmethodparameters|testmethodlimits|testmethods|test_suites|test_flow|binning|hardware_bin_descriptions)\s*$/
-
current_section = Regexp.last_match(1).to_sym
-
current = nil
-
end
-
end
-
end
-
end
-
end
-
-
2
def groups
-
@groups
-
end
-
-
2
def add_flow(flow)
-
flow.test_flow.each { |l| add_flow_line(l) }
-
end
-
-
2
def add_flow_line(line)
-
line.strip!
-
# Make group names unique as required
-
if line =~ /\s*},\s*open\s*,\s*("|')(.*)("|'),.*/
-
group = Regexp.last_match(2).strip
-
if groups[group]
-
line = line.sub(group, "#{group} #{groups[group]}")
-
groups[group] += 1
-
else
-
groups[group] = 1
-
end
-
end
-
test_flow << line
-
end
-
-
2
def combine(flow, attribute, options = {})
-
exclude = [options[:exclude]].flatten.compact
-
flow.send(attribute).each do |key, val|
-
unless exclude.include?(key)
-
if send(attribute)[key]
-
if send(attribute)[key] != val
-
puts "#{flow} assigns #{attribute} attribute #{key} to #{val}, however it is already assigned to #{send(attribute)[key]}"
-
exit 1
-
end
-
else
-
send(attribute)[key] = val
-
end
-
end
-
end
-
end
-
-
# Add the test methods from the given flow to this flow
-
2
def add_test_methods(flow)
-
flow.testmethods.each do |id, tm|
-
# If this flow already contains a test method with the current ID
-
if testmethods[id]
-
nid = "tm_#{tm_ix}"
-
testmethods[nid] = tm
-
testmethodparameters[nid] = flow.testmethodparameters[id]
-
testmethodlimits[nid] = flow.testmethodlimits[id]
-
flow.test_suites.each do |tsid, ts|
-
if ts['override_testf'] == "#{id};" && !ts[:new_id]
-
ts['override_testf'] = "#{nid};"
-
ts[:new_id] = true
-
end
-
end
-
else
-
testmethods[id] = tm
-
testmethodparameters[id] = flow.testmethodparameters[id]
-
testmethodlimits[id] = flow.testmethodlimits[id]
-
end
-
end
-
# Remove this temporary flag to prevent it rendering to the output file
-
flow.test_suites.each do |tsid, ts|
-
ts.delete(:new_id)
-
end
-
end
-
-
2
def add_test_suites(flow)
-
flow.test_suites.each do |id, ts|
-
# If this flow already contains a test suite with the current ID
-
if test_suites[id]
-
i = 1
-
nid = id
-
while test_suites[nid]
-
nid = "#{id}_#{i}"
-
i += 1
-
end
-
test_suites[nid] = ts
-
flow.test_flow.map! do |line|
-
if line =~ /(run|run_and_branch)\(#{id}\)/ && line !~ /--NEW_ID--/
-
line = line.sub(id, nid)
-
line += '--NEW_ID--'
-
else
-
line
-
end
-
end
-
else
-
test_suites[id] = ts
-
end
-
end
-
flow.test_flow.map! do |line|
-
line.sub('--NEW_ID--', '')
-
end
-
end
-
-
2
def tm_ix
-
testmethods.size + 1
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K
-
2
class Builder
-
# Responsible for modelling/building the contents of a V93K pattern master file
-
2
class PatternMaster
-
2
attr_reader :file, :paths
-
-
2
def initialize(file = nil)
-
@file = file
-
@paths = {}
-
parse_file if file
-
end
-
-
2
def add_sub_file(pm)
-
pm.paths.each do |path, files|
-
if paths[path]
-
paths[path] += files
-
paths[path].uniq!
-
else
-
paths[path] = files
-
end
-
end
-
end
-
-
2
private
-
-
2
def parse_file
-
File.open(file) do |f|
-
capture = nil
-
current_path = nil
-
f.each_line do |line|
-
line = line.strip
-
if line =~ /^\s*path:\s*$/
-
capture = :path
-
elsif capture == :path
-
paths[line] ||= []
-
current_path = paths[line]
-
capture = nil
-
elsif line =~ /^\s*files:\s*$/
-
capture = :file
-
elsif capture == :file
-
unless line.empty?
-
current_path << line
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K
-
2
require 'origen_testers/smartest_based_tester/base/flow'
-
2
class Flow < Base::Flow
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/smartest_based_tester/v93k/templates/template.tf.erb"
-
-
2
def flow_header
-
16
h = [' {']
-
16
if add_flow_enable
-
6
h << " if @#{flow_enable_var_name} == 1 then"
-
6
h << ' {'
-
6
i = ' '
-
else
-
10
i = ''
-
end
-
16
if set_runtime_variables.size > 0
-
8
h << i + ' {'
-
8
set_runtime_variables.each do |var|
-
117
h << i + " @#{generate_flag_name(var.to_s)} = -1;"
-
end
-
8
h << i + ' }, open,"Init Flow Control Vars", ""'
-
end
-
16
h
-
end
-
-
2
def flow_footer
-
16
f = []
-
16
if add_flow_enable
-
6
f << ' }'
-
6
f << ' else'
-
6
f << ' {'
-
6
f << ' }'
-
end
-
16
f << ''
-
16
f << " }, open,\"#{flow_name}\",\"#{flow_description}\""
-
16
f
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K
-
# Include this module in an interface class to make it a V93K interface and to give
-
# access to the V93K program generator API
-
2
module Generator
-
2
extend ActiveSupport::Concern
-
-
2
require_all "#{Origen.root!}/lib/origen_testers/smartest_based_tester/v93k"
-
2
require 'origen_testers/smartest_based_tester/base/generator'
-
-
2
included do
-
90
include Base::Generator
-
90
PLATFORM = V93K
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K
-
2
require 'origen_testers/smartest_based_tester/base/limits_file'
-
2
class LimitsFile < Base::LimitsFile
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/smartest_based_tester/v93k/templates/limits.csv.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K
-
2
require 'origen_testers/smartest_based_tester/base/pattern_compiler'
-
2
class PatternCompiler < Base::PatternCompiler
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/smartest_based_tester/v93k/templates/template.aiv.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K
-
2
require 'origen_testers/smartest_based_tester/base/pattern_master'
-
2
class PatternMaster < Base::PatternMaster
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/smartest_based_tester/v93k/templates/template.pmfl.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K
-
2
require 'origen_testers/smartest_based_tester/base/test_method'
-
2
class TestMethod < Base::TestMethod
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K
-
2
require 'origen_testers/smartest_based_tester/base/test_methods'
-
2
class TestMethods < Base::TestMethods
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K
-
2
require 'origen_testers/smartest_based_tester/base/test_suite'
-
2
class TestSuite < Base::TestSuite
-
ATTRS =
-
2
%w(name
-
comment
-
-
timing_equation timing_spec timing_set
-
level_equation level_spec level_set
-
analog_set
-
pattern
-
context
-
test_type
-
test_method
-
-
test_number
-
test_level
-
-
bypass
-
set_pass
-
set_fail
-
hold
-
hold_on_fail
-
output_on_pass
-
output_on_fail
-
pass_value
-
fail_value
-
per_pin_on_pass
-
per_pin_on_fail
-
log_mixed_signal_waveform
-
fail_per_label
-
ffc_enable
-
log_first
-
ffv_enable
-
frg_enable
-
hardware_dsp_disable
-
site_control
-
site_match
-
force_serial
-
)
-
-
ALIASES = {
-
2
tim_equ_set: :timing_equation,
-
tim_spec_set: :timing_spec,
-
timset: :timing_set,
-
timeset: :timing_set,
-
time_set: :timing_set,
-
lev_equ_set: :level_equation,
-
lev_spec_set: :level_spec,
-
levset: :level_set,
-
levels: :level_set,
-
pin_levels: :level_set,
-
anaset: :analog_set,
-
test_num: :test_number,
-
test_function: :test_method,
-
value_on_pass: :pass_value,
-
value_on_fail: :fail_value,
-
seqlbl: :pattern,
-
mx_waves_enable: :log_mixed_signal_waveform,
-
hw_dsp_disable: :hardware_dsp_disable,
-
ffc_on_fail: :log_first
-
}
-
-
DEFAULTS = {
-
2
output_on_pass: true,
-
output_on_fail: true,
-
pass_value: true,
-
fail_value: true,
-
per_pin_on_pass: true,
-
per_pin_on_fail: true,
-
site_control: 'parallel:',
-
site_match: 2
-
}
-
-
# Generate accessors for all attributes and their aliases
-
2
ATTRS.each do |attr|
-
72
if attr == 'name' || attr == 'pattern'
-
4
attr_reader attr.to_sym
-
else
-
68
attr_accessor attr.to_sym
-
end
-
end
-
-
# Define the aliases
-
2
ALIASES.each do |_alias, val|
-
38
define_method("#{_alias}=") do |v|
-
32
send("#{val}=", v)
-
end
-
38
define_method("#{_alias}") do
-
send(val)
-
end
-
end
-
-
2
def lines
-
853
if pattern
-
848
burst = $tester.multiport ? "#{$tester.multiport_name(pattern)}" : "#{pattern}"
-
end
-
853
l = []
-
853
l << " comment = \"#{comment}\";" if comment
-
853
l << " ffc_on_fail = #{wrap_if_string(log_first)};" if log_first
-
853
l << " local_flags = #{flags};" unless flags.empty?
-
853
l << ' override = 1;'
-
853
l << " override_anaset = #{wrap_if_string(analog_set)};" if analog_set
-
853
l << " override_lev_equ_set = #{wrap_if_string(level_equation)};" if level_equation
-
853
l << " override_lev_spec_set = #{wrap_if_string(level_spec)};" if level_spec
-
853
l << " override_levset = #{wrap_if_string(level_set)};" if level_set
-
853
l << " override_seqlbl = #{wrap_if_string(burst)};" if pattern
-
853
l << " override_test_number = #{test_number};" if test_number
-
853
l << " override_testf = #{test_method.id};" if test_method
-
853
l << " override_tim_equ_set = #{wrap_if_string(timing_equation)};" if timing_equation
-
853
l << " override_tim_spec_set = #{wrap_if_string(timing_spec)};" if timing_spec
-
853
l << " override_timset = #{wrap_if_string(timing_set)};" if timing_set
-
853
l << " site_control = #{wrap_if_string(site_control)};" if site_control
-
853
l << " site_match = #{wrap_if_string(site_match)};" if site_match
-
853
l << " test_level = #{test_level};" if test_level
-
853
l
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K
-
2
require 'origen_testers/smartest_based_tester/base/test_suites'
-
2
class TestSuites < Base::TestSuites
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K
-
2
require 'origen_testers/smartest_based_tester/base/variables_file'
-
2
class VariablesFile < Base::VariablesFile
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/smartest_based_tester/v93k/templates/vars.tf.erb"
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K_SMT8 < Base
-
2
require 'origen_testers/smartest_based_tester/v93k_smt8/generator.rb'
-
end
-
end
-
2
V93K_SMT8 = SmartestBasedTester::V93K_SMT8
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K_SMT8
-
2
require 'origen_testers/smartest_based_tester/base/flow'
-
2
class Flow < Base::Flow
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/smartest_based_tester/v93k_smt8/templates/template.flow.erb"
-
2
IN_IDENTIFIER = '_AUTOIN'
-
-
2
def on_test(node)
-
722
test_suite = node.find(:object).to_a[0]
-
722
if test_suite.is_a?(String)
-
100
name = test_suite
-
622
elsif test_suite.is_a?(ShmooTest)
-
10
name = test_suite.name
-
else
-
612
name = test_suite.name
-
612
test_method = test_suite.test_method
-
612
if test_method.respond_to?(:test_name) && test_method.test_name == '' &&
-
n = node.find(:name)
-
test_method.test_name = n.value
-
end
-
end
-
-
3670
if node.children.any? { |n| t = n.try(:type); t == :on_fail || t == :on_pass } ||
-
!stack[:on_pass].empty? || !stack[:on_fail].empty?
-
226
line "#{name}.execute();"
-
226
@open_test_names << name
-
226
@post_test_lines << []
-
1374
process_all(node.to_a.reject { |n| t = n.try(:type); t == :on_fail || t == :on_pass })
-
226
on_pass = node.find(:on_pass)
-
226
on_fail = node.find(:on_fail)
-
-
226
if on_fail && on_fail.find(:continue) && tester.force_pass_on_continue
-
if test_method.respond_to?(:force_pass)
-
test_method.force_pass = 1
-
else
-
Origen.log.error 'Force pass on continue has been enabled, but the test method does not have a force_pass attribute!'
-
Origen.log.error " #{node.source}"
-
exit 1
-
end
-
@open_test_methods << test_method
-
else
-
226
if test_method.respond_to?(:force_pass)
-
test_method.force_pass = 0
-
end
-
226
@open_test_methods << nil
-
end
-
-
226
pass_lines = capture_lines do
-
226
@indent += 1
-
226
pass_branch do
-
226
process_all(on_pass) if on_pass
-
226
stack[:on_pass].each { |n| process_all(n) }
-
end
-
226
@indent -= 1
-
end
-
-
226
fail_lines = capture_lines do
-
226
@indent += 1
-
226
fail_branch do
-
226
process_all(on_fail) if on_fail
-
226
stack[:on_fail].each { |n| process_all(n) }
-
end
-
226
@indent -= 1
-
end
-
-
226
if !pass_lines.empty? && fail_lines.empty?
-
28
line "if (#{name}.pass) {"
-
72
pass_lines.each { |l| line l, already_indented: true }
-
28
line '}'
-
-
198
elsif pass_lines.empty? && !fail_lines.empty?
-
100
line "if (!#{name}.pass) {"
-
280
fail_lines.each { |l| line l, already_indented: true }
-
100
line '}'
-
-
98
elsif !pass_lines.empty? && !fail_lines.empty?
-
8
line "if (#{name}.pass) {"
-
16
pass_lines.each { |l| line l, already_indented: true }
-
8
line '} else {'
-
16
fail_lines.each { |l| line l, already_indented: true }
-
8
line '}'
-
-
end
-
-
226
@open_test_methods.pop
-
226
@open_test_names.pop
-
226
@post_test_lines.pop.each { |l| line(l) }
-
else
-
496
line "#{name}.execute();"
-
end
-
end
-
-
2
def on_sub_flow(node)
-
54
sub_flow = sub_flow_from(node)
-
54
@sub_flows ||= {}
-
54
path = Pathname.new(node.find(:path).value)
-
54
name = path.basename('.*').to_s
-
54
path = Origen.interface.sub_flow_path_overwrite(path) if Origen.interface.respond_to? :sub_flow_path_overwrite
-
54
@sub_flows[name] = "#{path.dirname}.#{name}".gsub(/(\/|\\)/, '.')
-
# Pass down all input variables before executing
-
54
if sub_flow.input_variables.size > 0 && tester.flow_variable_grouping
-
5
line "// #{name} sub-flow input variables"
-
5
line '{'
-
5
@indent += 1
-
end
-
54
sub_flow.input_variables.each do |var|
-
# Handle the inout variables
-
# Get the main value into the temporary input variable
-
22
if sub_flow.inout_variables.keys.include?(var)
-
var = var[0] if var.is_a?(Array)
-
line "#{name}.#{var} = #{sub_flow.inout_variables[var]};"
-
else
-
22
var = var[0] if var.is_a?(Array)
-
22
line "#{name}.#{var} = #{var};"
-
end
-
end
-
54
if sub_flow.input_variables.size > 0 && tester.flow_variable_grouping
-
5
@indent -= 1
-
5
line '}'
-
end
-
54
line "#{name}.execute();"
-
# And then retrieve all common output variables
-
54
if (output_variables & sub_flow.output_variables).size > 0 && tester.flow_variable_grouping
-
7
line "// #{name} sub-flow output variables"
-
7
line '{'
-
7
@indent += 1
-
end
-
54
(output_variables & sub_flow.output_variables).sort.each do |var|
-
16
var = var[0] if var.is_a?(Array)
-
16
line "#{var} = #{name}.#{var};"
-
end
-
54
if (output_variables & sub_flow.output_variables).size > 0 && tester.flow_variable_grouping
-
7
@indent -= 1
-
7
line '}'
-
end
-
54
if on_pass = node.find(:on_pass)
-
pass_lines = capture_lines do
-
@indent += 1
-
pass_branch do
-
process_all(on_pass) if on_pass
-
end
-
@indent -= 1
-
end
-
on_pass = nil if pass_lines.empty?
-
end
-
-
54
if on_fail = node.find(:on_fail)
-
8
fail_lines = capture_lines do
-
8
@indent += 1
-
8
fail_branch do
-
8
process_all(on_fail) if on_fail
-
end
-
8
@indent -= 1
-
end
-
8
on_fail = nil if fail_lines.empty?
-
end
-
-
54
if on_pass && !on_fail
-
line "if (#{name}.pass) {"
-
pass_lines.each { |l| line l, already_indented: true }
-
line '}'
-
-
54
elsif !on_pass && on_fail
-
8
line "if (!#{name}.pass) {"
-
31
fail_lines.each { |l| line l, already_indented: true }
-
8
line '}'
-
-
46
elsif on_pass && on_fail
-
line "if (#{name}.pass) {"
-
pass_lines.each { |l| line l, already_indented: true }
-
line '} else {'
-
fail_lines.each { |l| line l, already_indented: true }
-
line '}'
-
end
-
end
-
-
2
def on_auxiliary_flow(node)
-
2
@auxiliary_flows ||= {}
-
2
path = node.find(:path).value
-
2
name = node.find(:name).value
-
2
@auxiliary_flows[name] = "#{path}"
-
2
line "#{name}.execute();"
-
end
-
-
2
def sub_flows
-
72
@sub_flows || {}
-
end
-
-
2
def shmoo_tests
-
146
@shmoo_tests ||= platform::ShmooTests.new(self)
-
end
-
-
2
def auxiliary_flows
-
68
@auxiliary_flows || {}
-
end
-
-
2
def inout_variables
-
90
@inout_variables || {}
-
end
-
-
# Variables which should be defined as an input to the current flow
-
2
def input_variables
-
230
vars = flow_variables
-
# Jobs and enables flow into a sub-flow
-
230
in_var_array = (vars[:all][:jobs] + vars[:all][:referenced_enables] + vars[:all][:set_enables] +
-
# As do any flags which are referenced by it but which are not set within it
-
230
(vars[:all][:referenced_flags] - vars[:all][:set_flags] - vars[:all][:unset_flags])).uniq
-
386
identified_inout_variables = in_var_array.select { |e| output_variables.include?(e) }
-
386
result = in_var_array.reject { |e| output_variables.include?(e) }
-
230
@inout_variables = {}
-
# create inout variables with unique ids to reduce user conflicts
-
230
identified_inout_variables.each do |var|
-
2
unique_id = 0
-
36
var.each_byte { |n| unique_id += n }
-
2
identifier = IN_IDENTIFIER + "_#{unique_id.to_s[0..4]}"
-
2
@inout_variables[:"#{var}#{identifier}"] = var
-
end
-
230
result += @inout_variables.keys
-
230
result.uniq.sort do |x, y|
-
278
x = x[0] if x.is_a?(Array)
-
278
y = y[0] if y.is_a?(Array)
-
278
x.to_s <=> y.to_s
-
end
-
end
-
-
# Variables which should be defined as an output of the current flow
-
2
def output_variables
-
704
vars = flow_variables
-
# Flags that are set by this flow flow out of it
-
704
(vars[:this_flow][:set_flags] +
-
# As do any flags set by its children which are marked as external
-
vars[:all][:set_flags_extern] +
-
# Other test methods are setting the flags
-
vars[:this_flow][:add_flags] +
-
# Other test methods are set in the children
-
vars[:all][:add_flags_extern] +
-
# And any flags which are set by a child and referenced in this flow
-
(vars[:this_flow][:referenced_flags] & vars[:sub_flows][:set_flags]) +
-
# And also intermediate flags, those are flags which are set by a child and referenced
-
# by a parent of the current flow
-
intermediate_variables).uniq.sort do |x, y|
-
20592
x = x[0] if x.is_a?(Array)
-
20592
y = y[0] if y.is_a?(Array)
-
20592
x <=> y
-
end
-
end
-
-
# Output variables which are not directly referenced by this flow, but which are referenced by a parent
-
# flow and set by the given child flow and therefore must pass through the current flow.
-
# By calling this method with no argument it will consider variables set by any child flow, alternatively
-
# pass in the variables for the child flow in question and only that will be considered.
-
2
def intermediate_variables(*sub_flows)
-
704
set_flags = []
-
5398
all_sub_flows.each { |f| set_flags += f.flow_variables[:all][:set_flags] }
-
704
if set_flags.empty?
-
292
[]
-
else
-
412
upstream_referenced_flags = []
-
412
p = parent
-
412
while p
-
242
upstream_referenced_flags += p.flow_variables[:this_flow][:referenced_flags]
-
242
p = p.parent
-
end
-
412
upstream_referenced_flags.uniq
-
412
set_flags & upstream_referenced_flags
-
end
-
end
-
-
2
def flow_header
-
68
h = []
-
68
if add_flow_enable && top_level?
-
2
h << " if (#{flow_enable_var_name} == 1) {"
-
2
i = ' '
-
else
-
66
i = ' '
-
end
-
68
flow_variables[:this_flow][:set_flags].each do |var|
-
102
if var.is_a?(Array)
-
h << i + "#{var[0]} = #{var[1].is_a?(String) || var[1].is_a?(Symbol) ? '"' + var[1].to_s + '"' : var[1]};"
-
else
-
102
h << i + "#{var} = -1;"
-
end
-
end
-
# Handle the inout variables
-
# Use the original variable name and get the value out of the temporary input variable
-
68
inout_variables.each do |inout_var, orig_var|
-
2
h << i + "#{orig_var} = #{inout_var};"
-
end
-
68
h << '' unless flow_variables[:this_flow][:set_flags].empty?
-
68
h
-
end
-
-
2
def flow_footer
-
68
f = []
-
68
if add_flow_enable && top_level?
-
2
f << ' }'
-
end
-
68
f
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K_SMT8
-
# Include this module in an interface class to make it a V93K interface and to give
-
# access to the V93K SMT8 program generator API
-
2
module Generator
-
2
extend ActiveSupport::Concern
-
-
2
require_all "#{Origen.root!}/lib/origen_testers/smartest_based_tester/v93k_smt8"
-
2
require 'origen_testers/smartest_based_tester/base/generator'
-
-
2
included do
-
22
include Base::Generator
-
22
PLATFORM = V93K_SMT8
-
end
-
-
# Sub flows are generated in a forked process for SMT8, however any updates made to interface
-
# instance variables by the sub-flow will be applied to the interface of the master process.
-
# This is what the user would expect to happen and keeps them largely unaware of the fact that
-
# the sub-flow is actually being generated by a forked process.
-
# However, to do this it is necessary to marshal the value of the instance variables and
-
# some (rich) Ruby objects cannot be marshaled. This parameter allows applications to selectively
-
# mark such variables as not to be returned from the forked process, skipping the marshal
-
# operation but also meaning that any changes made to the variable by the sub-flow will not
-
# be visible to the top-level flow.
-
#
-
# If the application actually needs updates to that variable made during a sub-flow to
-
# be available to the top-level flow, then they will need to work around it in another
-
# way on a case by case basis.
-
#
-
# # In the application's interface
-
# sub_flow_no_return_vars << :@my_problem_var
-
2
def sub_flow_no_return_vars
-
@sub_flow_no_return_vars ||= []
-
end
-
-
# See sub_flow_no_return_vars
-
2
def sub_flow_no_return_vars=(val)
-
@sub_flow_no_return_vars = val
-
end
-
-
2
def limits_workbook
-
208
@@limits_workbook ||= LimitsWorkbook.new(manually_register: true)
-
end
-
-
2
def shmoo_tests
-
10
flow.shmoo_tests
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K_SMT8
-
2
require 'origen_testers/smartest_based_tester/base/limits_file'
-
2
class LimitsFile < Base::LimitsFile
-
2
TEMPLATE = "#{Origen.root!}/lib/origen_testers/smartest_based_tester/v93k_smt8/templates/limits.csv.erb"
-
-
2
def fully_formatted_filename
-
224
"Main.#{@filename}_Tests.csv"
-
end
-
end
-
end
-
end
-
end
-
2
require 'rodf'
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K_SMT8
-
# Responsible for creating a limits workbook for each program generation run
-
# Each limits file will generate a sheet within this workbook
-
2
class LimitsWorkbook
-
2
include OrigenTesters::Generator
-
-
2
def initialize(options = {})
-
2
@softbins = {}
-
2
@bins = {}
-
end
-
-
2
def add_softbin(number, options = {})
-
options = {
-
28
name: nil,
-
bin: nil,
-
result: 'FAIL',
-
color: 'RED',
-
priority: 2
-
}.merge(options)
-
28
attrs = @softbins[number] || {}
-
-
28
attrs[:name] = options[:name] if options[:name]
-
28
attrs[:bin] = options[:bin] if options[:bin]
-
28
if !attrs[:result] || (options[:result] && options[:result] != 'FAIL')
-
3
attrs[:result] = options[:result]
-
end
-
28
if !attrs[:color] || (options[:color] && options[:color] != 'RED')
-
3
attrs[:color] = options[:color]
-
end
-
28
if !attrs[:priority] || (options[:priority] && options[:priority] != 2)
-
28
attrs[:priority] = options[:priority]
-
end
-
-
28
@softbins[number] = attrs
-
end
-
-
2
def add_bin(number, options = {})
-
options = {
-
96
name: nil,
-
result: 'FAIL'
-
}.merge(options)
-
-
96
attrs = @bins[number] || {}
-
-
96
attrs[:name] = options[:name] if options[:name]
-
96
if !attrs[:result] || (options[:result] && options[:result] != 'FAIL')
-
8
attrs[:result] = options[:result]
-
end
-
-
96
@bins[number] = attrs
-
end
-
-
2
def fully_formatted_filename
-
160
'limits.ods'
-
end
-
-
2
def subdirectory
-
4
"#{tester.package_namespace}/common"
-
end
-
-
2
def write_to_file(options = {})
-
2
Origen.log.info "Writing... #{output_file}"
-
2
spreadsheet = RODF::Spreadsheet.new
-
2
Origen.interface.flow_sheets.each do |name, flow|
-
68
if tester.create_limits_file
-
68
if flow.limits_file
-
14
limits_name = flow.limits_file.filename.sub('.csv', '')
-
14
table = spreadsheet.table limits_name
-
14
flow.limits_file.output_file.readlines.each_with_index do |line, i|
-
# Need to fix the first row, SMT8 won't allow the Low/High limits cells not to be merged
-
750
if i == 0
-
14
row = table.row
-
14
x = nil
-
14
line.chomp.split(',').each do |word|
-
112
if word == 'Low Limit'
-
14
x = 0
-
98
elsif word == 'High Limit'
-
14
row.cell 'Low Limit', span: x + 1
-
14
x = 0
-
84
elsif word == 'Unit'
-
14
row.cell 'High Limit', span: x + 1
-
14
row.cell word
-
14
x = nil
-
70
elsif x
-
x += 1
-
else
-
70
row.cell word
-
end
-
end
-
else
-
736
row = table.row
-
736
line.chomp.split(',').each do |word|
-
4472
row.cell word
-
end
-
end
-
end
-
end
-
end
-
end
-
2
if tester.separate_bins_file
-
bins_file = output_file.sub('.ods', '_bins.ods')
-
Origen.log.info "Writing... #{bins_file}"
-
bins_ss = RODF::Spreadsheet.new
-
add_bin_sheets(bins_ss)
-
bins_ss.write_to(bins_file)
-
else
-
2
add_bin_sheets(spreadsheet)
-
end
-
2
spreadsheet.write_to(output_file)
-
end
-
-
2
def add_bin_sheets(spreadsheet)
-
2
table = spreadsheet.table 'Software_Bins'
-
2
row = table.row
-
2
row.cell 'Software Bin Name'
-
2
row.cell 'Software Bin'
-
2
row.cell 'Hardware Bin'
-
2
row.cell 'Result'
-
2
row.cell 'Color'
-
2
row.cell 'Priority'
-
2
@softbins.each do |sbin, attrs|
-
6
row = table.row
-
6
row.cell attrs[:name]
-
6
row.cell sbin
-
6
row.cell attrs[:bin]
-
6
row.cell attrs[:result]
-
6
row.cell attrs[:color]
-
6
row.cell attrs[:priority]
-
end
-
-
# Write out the bin table
-
2
table = spreadsheet.table 'Hardware_Bins'
-
2
row = table.row
-
2
row.cell 'Hardware Bin Name'
-
2
row.cell 'Hardware Bin'
-
2
row.cell 'Result'
-
2
@bins.each do |bin, attrs|
-
16
row = table.row
-
16
row.cell attrs[:name]
-
16
row.cell bin
-
16
row.cell attrs[:result]
-
end
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K_SMT8
-
2
class ShmooTest
-
ATTRS =
-
%w(
-
2
name
-
-
bypass
-
target
-
result_title
-
result_type
-
result_signal
-
execution_order
-
ffc_error_count
-
axis
-
)
-
-
ALIASES = {
-
2
targets: :target,
-
title: :result_title,
-
type: :result_type,
-
signal: :result_signal
-
}
-
-
2
DEFAULTS = {
-
}
-
-
2
NO_STRING_TYPES = [:list_strings, :list_classes, :class]
-
# Generate accessors for all attributes and their aliases
-
2
ATTRS.each do |attr|
-
18
if attr == 'name'
-
2
attr_reader attr.to_sym
-
else
-
16
attr_accessor attr.to_sym
-
end
-
end
-
-
# Define the aliases
-
2
ALIASES.each do |_alias, val|
-
8
define_method("#{_alias}=") do |v|
-
18
send("#{val}=", v)
-
end
-
8
define_method("#{_alias}") do
-
644
send(val)
-
end
-
end
-
2
attr_accessor :meta
-
-
2
def initialize(name, attrs = {})
-
10
@name = name
-
10
if interface.unique_test_names == :signature
-
if interface.flow.sig
-
@name = "#{name}_#{interface.flow.sig}"
-
end
-
10
elsif interface.unique_test_names == :flowname || interface.unique_test_names == :flow_name
-
@name = "#{name}_#{interface.flow.name.to_s.symbolize}"
-
10
elsif interface.unique_test_names == :preflowname || interface.unique_test_names == :pre_flow_name
-
@name = "#{interface.flow.name.to_s.symbolize}_#{name}"
-
10
elsif interface.unique_test_names
-
utn_string = interface.unique_test_names.to_s
-
if utn_string =~ /^prepend_/
-
utn_string = utn_string.gsub(/^prepend_/, '')
-
@name = "#{utn_string}_#{name}"
-
else
-
utn_string = utn_string.gsub(/^append_/, '')
-
@name = "#{name}_#{utn_string}"
-
end
-
end
-
-
# handle axis
-
10
if axis = attrs.delete(:axis)
-
10
axis = [axis] unless axis.is_a?(Array)
-
10
axis.each_with_index do |a, i|
-
14
aname = a.delete(:name) || "axis#{i + 1}"
-
14
if axes_names.include?(aname.to_sym)
-
fail "Axis name #{aname} is already used in shmoo test '#{@name}'"
-
end
-
14
axes << ShmooTestAxis.new(aname.to_sym, a)
-
end
-
else
-
fail 'ShmooTest must have at least one axis'
-
end
-
-
# Set the defaults
-
10
self.class::DEFAULTS.each do |k, v|
-
send("#{k}=", v)
-
end
-
# Then the values that have been supplied
-
10
attrs.each do |k, v|
-
24
send("#{k}=", v) if respond_to?("#{k}=") && k.to_sym != :name
-
end
-
end
-
-
2
def smt8?
-
tester.smt8?
-
end
-
-
2
def inspect
-
"<ShmooTest: #{name}>"
-
end
-
-
# The name is immutable once the shmoo test is created, this will raise an error when called
-
2
def name=(val, options = {})
-
fail 'Once assigned the name of a shmoo test cannot be changed!'
-
end
-
-
2
def interface
-
60
Origen.interface
-
end
-
-
2
def axes
-
38
@axes ||= []
-
end
-
-
2
def axes_names
-
14
axes.map(&:name)
-
end
-
-
2
def lines
-
10
l = []
-
10
l << "shmoo #{name} {"
-
10
if target.length > 1
-
2
l << " target = \#[#{target.map(&:to_s).join(',')}];"
-
else
-
8
l << " target = #{target[0]};"
-
end
-
10
l << " resultTitle = \"#{result_title}\";" if result_title
-
10
l << " resultType = \"#{result_type}\";" if result_type
-
10
l << " resultSignal = \"#{result_signal}\";" if result_signal
-
10
l << " executionOrder = #{execution_order};" if execution_order
-
10
l << " bypass = \"#{bypass}\";" if bypass
-
10
l << " ffcErrorCount = #{ffc_error_count};" if ffc_error_count
-
10
l << ''
-
-
10
axes.each do |a|
-
14
a.lines.each do |al|
-
112
l << al
-
end
-
end
-
-
10
l << '}'
-
10
l
-
end
-
end
-
-
2
class ShmooTestAxis
-
ATTRS =
-
%w(
-
2
name
-
-
resource_type
-
resource_name
-
setup_signal
-
-
range_resolution
-
range_steps
-
range_fast_steps
-
range_scale
-
range_list
-
range_start
-
range_stop
-
range_relative_percentage_start
-
range_relative_percentage_stop
-
range_relative_value_start
-
range_relative_value_stop
-
tracking
-
)
-
-
ALIASES = {
-
2
resolution: :range_resolution,
-
steps: :range_steps,
-
fast_steps: :range_fast_steps
-
}
-
-
# Generate accessors for all attributes and their aliases
-
2
ATTRS.each do |attr|
-
32
if attr == 'name'
-
2
attr_reader attr.to_sym
-
else
-
30
attr_accessor attr.to_sym
-
end
-
end
-
-
2
def initialize(name, attrs = {})
-
14
@name = name
-
-
14
@resource_type = attrs.delete(:resource_type)
-
14
@resource_name = attrs.delete(:resource_name)
-
14
@setup_signal = attrs.delete(:setup_signal)
-
-
14
if range_list = attrs.delete(:range_list)
-
@range_list = range_list
-
14
elsif attrs[:range] && attrs[:range].is_a?(Array)
-
@range_list = attrs.delete(:range)
-
else
-
14
if range = attrs.delete(:range)
-
10
if range.is_a?(Range)
-
6
@range_start = range.begin
-
6
@range_stop = range.end
-
6
@range_steps = attrs.delete(:range_steps) || attrs.delete(:steps)
-
6
@range_resolution = attrs.delete(:range_resolution) || attrs.delete(:resolution)
-
6
@range_fast_steps = attrs.delete(:range_fast_steps) || attrs.delete(:fast_steps)
-
4
elsif range.is_a?(Hash)
-
4
@range_start = range[:start]
-
4
@range_stop = range[:stop]
-
4
@range_steps = range[:steps]
-
4
@range_resolution = range[:resolution]
-
4
@range_fast_steps = range[:fast_steps]
-
end
-
4
elsif range_relative_percentage = attrs.delete(:range_relative_percentage)
-
4
if range_relative_percentage.is_a?(Range)
-
4
@range_relative_percentage_start = range_relative_percentage.begin
-
4
@range_relative_percentage_stop = range_relative_percentage.end
-
4
@range_steps = attrs.delete(:range_steps) || attrs.delete(:steps)
-
4
@range_resolution = attrs.delete(:range_resolution) || attrs.delete(:resolution)
-
4
@range_fast_steps = attrs.delete(:range_fast_steps) || attrs.delete(:fast_steps)
-
elsif range_relative_percentage.is_a?(Hash)
-
@range_relative_percentage_start = range_relative_percentage[:start]
-
@range_relative_percentage_stop = range_relative_percentage[:stop]
-
@range_steps = range_relative_percentage[:steps]
-
@range_resolution = range_relative_percentage[:resolution]
-
@range_fast_steps = range_relative_percentage[:fast_steps]
-
end
-
elsif range_relative_value = attrs.delete(:range_relative_value)
-
if range_relative_value.is_a?(Range)
-
@range_relative_value_start = range_relative_value.begin
-
@range_relative_value_stop = range_relative_value.end
-
@range_steps = attrs.delete(:range_steps) || attrs.delete(:steps)
-
@range_resolution = attrs.delete(:range_resolution) || attrs.delete(:resolution)
-
@range_fast_steps = attrs.delete(:range_fast_steps) || attrs.delete(:fast_steps)
-
elsif range_relative_value.is_a?(Hash)
-
@range_relative_value_start = range_relative_value[:start]
-
@range_relative_value_stop = range_relative_value[:stop]
-
@range_steps = range_relative_value[:steps]
-
@range_resolution = range_relative_value[:resolution]
-
@range_fast_steps = range_relative_value[:fast_steps]
-
end
-
else
-
attrs.each do |k, v|
-
send("#{k}=", v) if respond_to?("#{k}=") && k.to_sym != :name
-
end
-
end
-
end
-
-
14
if tracking = attrs.delete(:tracking)
-
2
tracking = [tracking] unless tracking.is_a?(Array)
-
2
tracking.each_with_index do |t, i|
-
2
tname = t.delete(:name) || "tracking#{i + 1}"
-
2
if trackings_names.include?(tname.to_sym)
-
fail "Tracking name #{tname} is already used in shmoo test axis '#{@name}'"
-
end
-
2
trackings << ShmooTestTracking.new(tname.to_sym, t)
-
end
-
end
-
-
14
attrs.each do |k, v|
-
send("#{k}=", v) if respond_to?("#{k}=") && k.to_sym != :name
-
end
-
end
-
-
2
def lines
-
14
l = []
-
14
l << " axis [#{name}] = {"
-
14
if resource_type
-
14
l << " resourceType = #{resource_type};"
-
else
-
fail 'Shmoo Axis must have a resource type'
-
end
-
14
if resource_name
-
14
l << " resourceName = \"#{resource_name}\";"
-
else
-
fail 'Shmoo Axis must have a resource name'
-
end
-
14
l << " setup_signal = \"#{setup_signal}\";" if setup_signal
-
14
if range_list
-
l << " range.list = \#[#{range_list.map(&:to_s).join(',')}];"
-
14
elsif range_start && range_stop
-
10
l << " range.start = #{range_start};"
-
10
l << " range.stop = #{range_stop};"
-
4
elsif range_relative_percentage_start && range_relative_percentage_stop
-
4
l << " range.relativePercentage.start = #{range_relative_percentage_start};"
-
4
l << " range.relativePercentage.stop = #{range_relative_percentage_stop};"
-
elsif range_relative_value_start && range_relative_value_stop
-
l << " range.relativeValue.start = #{range_relative_value_start};"
-
l << " range.relativeValue.stop = #{range_relative_value_stop};"
-
else
-
fail 'Shmoo Axis must have a range (start & stop) or range list'
-
end
-
14
if range_resolution && range_steps.nil?
-
l << " range.resolution = #{range_resolution};"
-
if range_fast_steps
-
fail 'Shmoo Axis cannot have range fast steps with range resolution'
-
end
-
14
elsif range_steps && range_resolution.nil?
-
14
l << " range.steps = #{range_steps};"
-
14
if range_fast_steps
-
l << " range.fastSteps = #{range_fast_steps};"
-
end
-
elsif range_resolution.nil? && range_steps.nil?
-
fail 'Shmoo Axis must define either range resolution or range steps'
-
else
-
fail 'Shmoo Axis must define either range resolution or range steps, but not both'
-
end
-
14
l << '' if trackings.length > 0
-
14
trackings.each do |t|
-
2
t.lines.each do |tl|
-
12
l << tl
-
end
-
end
-
-
14
l << ' };'
-
14
l
-
end
-
-
2
def trackings
-
32
@trackings ||= []
-
end
-
-
2
def trackings_names
-
2
trackings.map(&:name)
-
end
-
end
-
-
2
class ShmooTestTracking
-
ATTRS =
-
%w(
-
2
name
-
-
resource_type
-
resource_name
-
setup_signal
-
-
range_list
-
range_start
-
range_stop
-
range_relative_percentage_start
-
range_relative_percentage_stop
-
range_relative_value_start
-
range_relative_value_stop
-
)
-
-
# Generate accessors for all attributes and their aliases
-
2
ATTRS.each do |attr|
-
22
if attr == 'name'
-
2
attr_reader attr.to_sym
-
else
-
20
attr_accessor attr.to_sym
-
end
-
end
-
-
2
def initialize(name, attrs = {})
-
2
@name = name
-
-
2
@resource_type = attrs.delete(:resource_type)
-
2
@resource_name = attrs.delete(:resource_name)
-
2
@setup_signal = attrs.delete(:setup_signal)
-
-
2
if range = attrs.delete(:range)
-
if range.is_a?(Range)
-
@range_start = range.begin
-
@range_stop = range.end
-
elsif range.is_a?(Hash)
-
@range_start = range[:start]
-
@range_stop = range[:stop]
-
elsif range.is_a?(Array)
-
@range_list = range
-
end
-
2
elsif range_relative_percentage = attrs.delete(:range_relative_percentage)
-
if range_relative_percentage.is_a?(Range)
-
@range_relative_percentage_start = range_relative_percentage.begin
-
@range_relative_percentage_stop = range_relative_percentage.end
-
elsif range_relative_percentage.is_a?(Hash)
-
@range_relative_percentage_start = range_relative_percentage[:start]
-
@range_relative_percentage_stop = range_relative_percentage[:stop]
-
end
-
2
elsif range_relative_value = attrs.delete(:range_relative_value)
-
2
if range_relative_value.is_a?(Range)
-
2
@range_relative_value_start = range_relative_value.begin
-
2
@range_relative_value_stop = range_relative_value.end
-
elsif range_relative_value.is_a?(Hash)
-
@range_relative_value_start = range_relative_value[:start]
-
@range_relative_value_stop = range_relative_value[:stop]
-
end
-
else
-
attrs.each do |k, v|
-
send("#{k}=", v) if respond_to?("#{k}=") && k.to_sym != :name
-
end
-
end
-
end
-
-
2
def lines
-
2
l = []
-
2
l << " tracking [#{name}] = {"
-
2
if resource_type
-
2
l << " resourceType = #{resource_type};"
-
else
-
fail 'Shmoo Tracking must have a resource type'
-
end
-
2
if resource_name
-
2
l << " resourceName = \"#{resource_name}\";"
-
else
-
fail 'Shmoo Tracking must have a resource name'
-
end
-
2
l << " setup_signal = \"#{setup_signal}\";" if setup_signal
-
2
if range_list
-
l << " range.list = \#[#{range_list.map(&:to_s).join(',')}];"
-
2
elsif range_start && range_stop
-
l << " range.start = #{range_start};"
-
l << " range.stop = #{range_stop};"
-
2
elsif range_relative_percentage_start && range_relative_percentage_stop
-
l << " range.relativePercentage.start = #{range_relative_percentage_start};"
-
l << " range.relativePercentage.stop = #{range_relative_percentage_stop};"
-
2
elsif range_relative_value_start && range_relative_value_stop
-
2
l << " range.relativeValue.start = #{range_relative_value_start};"
-
2
l << " range.relativeValue.stop = #{range_relative_value_stop};"
-
else
-
fail 'Shmoo Tracking must have a range (start & stop) or range list'
-
end
-
2
l << ' };'
-
2
l
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class Base
-
2
class ShmooTests
-
# Origen::Tester::Generator not included since test suites do not have their
-
# own top-level sheet, they will be incorporated within the flow sheet
-
-
2
attr_accessor :flow, :collection
-
-
2
def initialize(flow)
-
68
@flow = flow
-
68
@collection = []
-
68
@existing_names = {}
-
# Test names also have to be unique vs. the current flow name
-
68
if tester.smt8?
-
68
@existing_names[flow.filename.sub('.flow', '').to_s] = true
-
end
-
end
-
-
2
def filename
-
flow.filename
-
end
-
-
2
def add(name, options = {})
-
10
symbol = name.is_a?(Symbol)
-
10
name = make_unique(name)
-
# Ensure names given as a symbol stay as a symbol, this is more for
-
# alignment to existing test cases than anything else
-
10
name = name.to_sym if symbol
-
10
shmoo = platform::ShmooTest.new(name, options)
-
10
@collection << shmoo
-
10
shmoo
-
end
-
2
alias_method :run, :add
-
2
alias_method :run_and_branch, :add
-
-
2
def platform
-
10
Origen.interface.platform
-
end
-
-
2
def finalize
-
# match any formatting difference between test suite shmoo and test flow shmoo
-
68
@collection.each do |shmoo_test|
-
10
shmoo_test.targets.each_with_index do |target, i|
-
12
target_is_a_test_suite = false
-
12
flow.test_suites.sorted_collection.each do |suite|
-
490
if suite.name.to_s == target.to_s
-
8
target_is_a_test_suite = true
-
8
break
-
end
-
end
-
-
12
unless target_is_a_test_suite
-
4
target_is_a_test_flow = false
-
4
flow.sub_flows.each do |name, path|
-
20
target_name = target.to_s.gsub(' ', '_')
-
20
if name.to_s.downcase == target_name.to_s.downcase
-
4
target_is_a_test_flow = true
-
4
shmoo_test.targets[i] = name
-
4
break
-
end
-
end
-
-
4
unless target_is_a_test_flow
-
fail "Shmoo test target '#{target}' for shmoo test '#{shmoo_test.name}' not found in test suites or sub_flows"
-
end
-
end
-
end
-
end
-
end
-
-
2
def sorted_collection
-
78
@collection.sort_by { |st| st.name.to_s }
-
end
-
-
2
private
-
-
2
def make_unique(name)
-
10
name = name.to_s
-
10
tempname = name
-
10
i = 0
-
10
while @existing_names[tempname]
-
i += 1
-
tempname = "#{name}_#{i}"
-
end
-
10
@existing_names[tempname] = true
-
10
tempname
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module SmartestBasedTester
-
2
class V93K_SMT8
-
2
require 'origen_testers/smartest_based_tester/base/test_suite'
-
2
class TestSuite < Base::TestSuite
-
ATTRS =
-
%w(
-
2
name
-
comment
-
bypass
-
-
test_method
-
-
pattern
-
specification
-
seq
-
burst
-
-
spec_namespace
-
spec_path
-
seq_namespace
-
seq_path
-
)
-
-
ALIASES = {
-
2
spec: :specification,
-
test_function: :test_method
-
}
-
-
2
DEFAULTS = {
-
}
-
-
2
NO_STRING_TYPES = [:list_strings, :list_classes, :class]
-
# Generate accessors for all attributes and their aliases
-
2
ATTRS.each do |attr|
-
24
if attr == 'name' || attr == 'pattern'
-
4
attr_reader attr.to_sym
-
else
-
20
attr_accessor attr.to_sym
-
end
-
end
-
-
# Define the aliases
-
2
ALIASES.each do |_alias, val|
-
4
define_method("#{_alias}=") do |v|
-
622
send("#{val}=", v)
-
end
-
4
define_method("#{_alias}") do
-
622
send(val)
-
end
-
end
-
-
2
def lines
-
# Initialize path setting
-
# prefix = test method library prefix expectations
-
# self.spec_namespace = instance override from the tester specification namespace
-
# self.seq_namespace = instance override from the tester sequence namespace
-
# self.spec_path = instance override from the tester specification path
-
# self.seq_path = instance override from the tester sequence path
-
634
if Origen.interface.respond_to? :custom_smt8_prefix
-
prefix = Origen.interface.custom_smt8_prefix
-
else
-
634
prefix = 'measurement.'
-
end
-
634
spec_namespace = self.spec_namespace || tester.package_namespace
-
634
spec_path = self.spec_path || tester.spec_path
-
634
seq_namespace = self.seq_namespace || tester.package_namespace
-
634
seq_path = self.seq_path || tester.seq_path
-
634
l = []
-
634
l << "suite #{name} calls #{test_method.klass[0].downcase + test_method.klass[1..-1]} {"
-
634
if pattern && !pattern.to_s.empty?
-
626
l << " #{prefix}pattern = setupRef(#{seq_namespace}.patterns.#{pattern});"
-
end
-
634
if seq && !seq.to_s.empty?
-
l << " #{prefix}operatingSequence = setupRef(#{seq_namespace}.#{seq_path}.#{seq});"
-
end
-
634
if burst && !burst.to_s.empty?
-
2
l << " #{prefix}operatingSequence = setupRef(#{seq_namespace}.#{seq_path}.#{burst});"
-
end
-
634
if specification && !specification.to_s.empty?
-
622
l << " #{prefix}specification = setupRef(#{spec_namespace}.#{spec_path}.#{specification});"
-
end
-
634
if bypass
-
2
l << ' bypass = true;'
-
end
-
634
test_method.sorted_parameters.each do |param|
-
1651
name = param[0]
-
1651
unless name.is_a?(String)
-
1651
name = name.to_s[0] == '_' ? name.to_s.camelize(:upper) : name.to_s.camelize(:lower)
-
end
-
1651
if param.last.is_a? Hash
-
12
if !test_method.format(name).nil? && !test_method.format(name).is_a?(Hash)
-
fail "#{name} parameter structure requires a Hash but value provided is #{test_method.format(name).class}"
-
12
elsif test_method.format(name).nil? && tester.print_all_params
-
2
l = add_nested_params(l, name, 'param0', {}, param.last, 1)
-
10
elsif test_method.format(name).nil?
-
# Do nothing
-
else
-
10
test_method.format(name).each do |key, meta_hash|
-
12
l = add_nested_params(l, name, key, meta_hash, param.last, 1)
-
end
-
end
-
1639
elsif NO_STRING_TYPES.include?(param.last) && test_method.format(param[0]).is_a?(String) && !test_method.format(param[0]).empty?
-
l << " #{name} = #{test_method.format(param[0])};"
-
else
-
1639
l << " #{name} = #{wrap_if_string(test_method.format(param[0]))};"
-
end
-
end
-
631
l << '}'
-
631
l
-
end
-
-
# rubocop:disable Metrics/ParameterLists: Avoid parameter lists longer than 5 parameters.
-
2
def add_nested_params(l, name, key, value_hash, nested_params, nested_loop_count)
-
24
nested_params_accepted_keys = []
-
24
skip_keys = []
-
24
unless value_hash.nil?
-
24
unless value_hash.is_a?(Hash)
-
1
fail "Provided value to nested params was not a Hash. Instead the value was #{value_hash.class}"
-
end
-
23
dynamic_spacing = ' ' * (4 * nested_loop_count)
-
23
l << "#{dynamic_spacing}#{name}[#{key}] = {" unless name.nil?
-
23
nested_params.each do |nested_param|
-
# Guarentee hash is using all symbol keys
-
# Since we cannot guarentee ruby version is greater than 2.5, we have to use an older syntax to
-
172
value_hash = value_hash.inject({}) { |memo, (k, v)| memo[k.to_sym] = v; memo }
-
66
nested_key = nested_param.first.to_s.gsub('.', '_').to_sym
-
66
nested_key_underscore = nested_key.to_s.underscore.to_sym
-
66
nested_params_accepted_keys << nested_key
-
66
nested_params_accepted_keys << nested_key_underscore
-
# We cannot create nested member functions with aliases
-
# Requirement for hash parameter passing is to pass one of the key types and not both
-
66
if value_hash.keys.include?(nested_key) &&
-
value_hash.keys.include?(nested_key_underscore) && nested_key != nested_key_underscore
-
1
fail 'You are using a hash based test method and provided both the parameter name and alias name.'
-
end
-
65
nested_key = nested_key_underscore if value_hash.keys.include?(nested_key_underscore)
-
65
if nested_param.last.first.is_a?(Hash) && value_hash[nested_key].is_a?(Hash)
-
2
value_hash[nested_key].each do |inner_key, inner_meta_hash|
-
6
l = add_nested_params(l, nested_param.first, inner_key, value_hash.dig(nested_key, inner_key), nested_param.last.first, nested_loop_count + 1)
-
6
skip_keys << nested_key
-
end
-
63
elsif nested_param.last.first.is_a?(Hash) && tester.print_all_params
-
4
l = add_nested_params(l, nested_param.first, 'param0', {}, nested_param.last.first, nested_loop_count + 1)
-
end
-
65
type = nested_param.last.first
-
65
if NO_STRING_TYPES.include?(nested_param.last.first) && value_hash[nested_key] && !skip_keys.include?(nested_key)
-
l << " #{dynamic_spacing}#{nested_param.first} = #{test_method.handle_val_type(value_hash[nested_key], type, nested_param.first)};"
-
65
elsif value_hash[nested_key] && !skip_keys.include?(nested_key)
-
21
l << " #{dynamic_spacing}#{nested_param.first} = #{wrap_if_string(test_method.handle_val_type(value_hash[nested_key], type, nested_param.first))};"
-
44
elsif NO_STRING_TYPES.include?(nested_param.last.first) && !nested_param.last.last.is_a?(Hash) && tester.print_all_params && !skip_keys.include?(nested_key)
-
16
l << " #{dynamic_spacing}#{nested_param.first} = #{test_method.handle_val_type(nested_param.last.last, type, nested_param.first)};"
-
28
elsif !nested_param.last.last.is_a?(Hash) && tester.print_all_params && !skip_keys.include?(nested_key)
-
22
l << " #{dynamic_spacing}#{nested_param.first} = #{wrap_if_string(test_method.handle_val_type(nested_param.last.last, type, nested_param.first))};"
-
end
-
end
-
22
l << "#{dynamic_spacing}};" unless name.nil?
-
# Sanity check there are not overpassed parameters
-
22
value_hash.keys.each do |nested_key|
-
24
unless nested_params_accepted_keys.include?(nested_key.to_sym)
-
1
fail "You provided a parameter \'#{nested_key}\' that was not an accepted parameter to the hash parameter \'#{name}\'"
-
end
-
end
-
end
-
21
l
-
end
-
# rubocop:enable Metrics/ParameterLists: Avoid parameter lists longer than 5 parameters.
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module StilBasedTester
-
2
autoload :Base, 'origen_testers/stil_based_tester/base.rb'
-
2
autoload :D10, 'origen_testers/stil_based_tester/d10.rb'
-
2
autoload :STIL, 'origen_testers/stil_based_tester/stil.rb'
-
end
-
# Convenience/Legacy names without the IGXLBasedTester namespace
-
2
autoload :D10, 'origen_testers/stil_based_tester/d10.rb'
-
2
autoload :STIL, 'origen_testers/stil_based_tester/stil.rb'
-
end
-
1
module OrigenTesters
-
1
module StilBasedTester
-
1
class Base
-
1
include VectorBasedTester
-
-
# When set to true generated patterns will only contain Pattern blocks, i.e. only vectors
-
1
attr_accessor :pattern_only
-
-
# Returns a new J750 instance, normally there would only ever be one of these
-
# assigned to the global variable such as $tester by your target:
-
# $tester = J750.new
-
1
def initialize(options = {})
-
24
self.pattern_only = options.delete(:pattern_only)
-
24
@max_repeat_loop = 65_535
-
24
@min_repeat_loop = 2
-
24
@pat_extension = 'stil'
-
24
@compress = true
-
24
@use_timing_equations = options[:use_timing_equations]
-
-
# @support_repeat_previous = true
-
24
@match_entries = 10
-
24
@name = 'stil'
-
24
@comment_char = '//'
-
24
@level_period = true
-
24
@inline_comments = true
-
24
@header_done = false
-
24
@footer_done = false
-
end
-
-
1
def stil_based?
-
true
-
end
-
-
# returns the orderd pins with groups decomposed into individual pins
-
1
def flattened_ordered_pins
-
75
if @flattened_ordered_pins.nil?
-
21
@flattened_ordered_pins = []
-
21
ordered_pins.each do |p|
-
93
if p.is_a?(Origen::Pins::PinCollection)
-
18
p.each { |ip| @flattened_ordered_pins << ip }
-
else
-
91
@flattened_ordered_pins << p
-
end
-
end
-
end
-
75
@flattened_ordered_pins
-
end
-
-
1
def output_group_definition(grp, grp_name)
-
23
line = "\"#{grp_name}\" = '"
-
23
grp.each_with_index do |pin, i|
-
123
unless i == 0
-
100
line << '+'
-
end
-
123
line << pin.name.to_s
-
end
-
23
microcode " #{line}';"
-
end
-
-
# An internal method called by Origen to create the pattern header
-
1
def pattern_header(options = {})
-
22
options = {
-
}.merge(options)
-
-
22
@pattern_name = options[:pattern]
-
-
22
unless pattern_only
-
21
microcode 'STIL 1.0;'
-
-
21
microcode ''
-
21
microcode 'Signals {'
-
21
flattened_ordered_pins.each do |pin|
-
107
line = ''
-
107
line << "#{pin.name} "
-
107
if pin.direction == :input
-
line << 'In;'
-
107
elsif pin.direction == :output
-
line << 'Out;'
-
else
-
107
line << 'InOut;'
-
end
-
107
microcode " #{line}"
-
end
-
21
microcode '}'
-
-
21
microcode ''
-
21
microcode 'SignalGroups {'
-
# output pin group definitions used in this pattern
-
21
ordered_pins.each do |p|
-
93
output_group_definition(p, p.name.to_s) if p.is_a?(Origen::Pins::PinCollection)
-
end
-
-
# output the all pin group
-
21
output_group_definition(flattened_ordered_pins, "#{ordered_pins_name || 'ALL'}")
-
21
microcode '}'
-
-
# output the period category specs
-
21
if @use_timing_equations
-
10
microcode ''
-
10
microcode 'Spec {'
-
10
microcode " Category c_#{@pattern_name} {"
-
10
(@wavesets || []).each_with_index do |w, i|
-
16
microcode " period_#{w[:name]} = '#{w[:period]}ns';"
-
end
-
10
microcode ' }'
-
10
microcode '}'
-
end
-
-
21
microcode ''
-
21
microcode "Timing t_#{@pattern_name} {"
-
21
(@wavesets || []).each_with_index do |w, i|
-
33
microcode '' if i != 0
-
33
microcode " WaveformTable Waveset#{i + 1} {"
-
33
period_var = "period_#{w[:name]}"
-
33
if @use_timing_equations
-
16
microcode " Period '#{period_var}';"
-
else
-
17
microcode " Period '#{w[:period]}ns';"
-
end
-
33
microcode ' Waveforms {'
-
33
w[:lines].each do |line|
-
310
microcode " #{line}"
-
end
-
33
microcode ' }'
-
33
microcode ' }'
-
end
-
21
microcode '}'
-
-
21
microcode ''
-
21
microcode "PatternBurst b_#{@pattern_name} {"
-
21
microcode " PatList { #{@pattern_name}; }"
-
21
microcode '}'
-
-
21
microcode ''
-
21
microcode "PatternExec e_#{@pattern_name} {"
-
21
microcode " Category c_#{@pattern_name};" if @use_timing_equations
-
21
microcode " Timing t_#{@pattern_name};"
-
21
microcode " PatternBurst b_#{@pattern_name};"
-
21
microcode '}'
-
21
microcode ''
-
end
-
-
22
microcode "Pattern \"#{@pattern_name}\" {"
-
22
microcode "#{@pattern_name}:"
-
22
@header_done = true
-
-
22
if tester.ordered_pins_name.nil? && pattern_only
-
1
Origen.log.warn "WARN: SigName must be defined for STIL format. Use pin_pattern_order(*pins, name: <sigName>). Defaulting to use 'ALL'"
-
end
-
end
-
-
1
def set_timeset(t, period_in_ns = nil)
-
# check for period size override from the app if performing convert command
-
46
if Origen.current_command == 'convert'
-
listeners = Origen.listeners_for(:convert_command_set_period_in_ns)
-
if listeners.empty?
-
unless @call_back_message_displayed
-
Origen.log.warn 'STIL output is generated using "origen convert" with no timeset period callback method defined. Default period size will be used.'
-
Origen.log.info 'stil tester implements a callback for setting the timeset period size when converting a pattern to stil format'
-
Origen.log.info 'to use the callback feature add the following define to your app in config/application.rb'
-
Origen.log.info ' def convert_command_set_period_in_ns(timeset_name)'
-
Origen.log.info ' return 25 if timeset_name == "timeset0"'
-
Origen.log.info ' return 30 if timeset_name == "timeset1"'
-
Origen.log.info ' 40'
-
Origen.log.info ' end'
-
@call_back_message_displayed = true
-
end
-
else
-
listeners.each do |listener|
-
period_in_ns = listener.convert_command_set_period_in_ns(t)
-
end
-
end
-
end
-
46
super
-
46
if pattern_only
-
# Why does D10 not include this?
-
# microcode "W #{t};"
-
else
-
45
@wavesets ||= []
-
45
wave_number = nil
-
45
@wavesets.each_with_index do |w, i|
-
36
if w[:name] == timeset.name && w[:period] = timeset.period_in_ns
-
12
wave_number = i + 1 # bug fix wave numbers are 1 more than their index #
-
end
-
end
-
45
unless wave_number
-
33
lines = []
-
33
period_var = "period_#{timeset.name}"
-
33
flattened_ordered_pins.each do |pin|
-
155
if pin.direction == :input || pin.direction == :io
-
155
line = "#{pin.name} { 01 { "
-
155
wave = pin.drive_wave if tester.timeset.dut_timeset
-
155
if wave
-
32
(@use_timing_equations ? wave.events : wave.evaluated_events).each do |t, v|
-
32
if @use_timing_equations
-
16
line << "'#{t.to_s.gsub('period', period_var)}' "
-
else
-
16
line << "'#{t}ns' "
-
end
-
32
if v == 0
-
line << 'D'
-
32
elsif v == 1
-
line << 'U'
-
else
-
32
line << 'D/U'
-
end
-
32
line << '; '
-
end
-
end
-
155
line << '}}'
-
155
lines << line
-
end
-
155
if pin.direction == :output || pin.direction == :io
-
155
line = "#{pin.name} { LHX { "
-
155
wave = pin.compare_wave if tester.timeset.dut_timeset
-
155
if wave
-
32
(@use_timing_equations ? wave.events : wave.evaluated_events).each_with_index do |tv, i|
-
32
t, v = *tv
-
32
if i == 0 && t != 0
-
32
line << "'0ns' X; "
-
end
-
32
if @use_timing_equations
-
16
line << "'#{t.to_s.gsub('period', period_var)}' "
-
else
-
16
line << "'#{t}ns' "
-
end
-
32
if v == 0
-
line << 'L'
-
32
elsif v == 0
-
line << 'H'
-
else
-
32
line << 'L/H/X'
-
end
-
32
line << '; '
-
end
-
end
-
155
line << '}}'
-
155
lines << line
-
end
-
end
-
33
@wavesets << { name: timeset.name, period: timeset.period_in_ns, lines: lines }
-
33
wave_number = @wavesets.size
-
end
-
45
microcode "W Waveset#{wave_number};"
-
end
-
end
-
-
# Capture the pin data from a vector to the tester.
-
#
-
# This method uses the Digital Capture feature (Selective mode) of the V93000 to capture
-
# the data from the given pins on the previous vector.
-
# Note that is does not actually generate a new vector.
-
#
-
# Note also that any drive cycles on the target pins can also be captured, to avoid this
-
# the wavetable should be set up like this to infer a 'D' (Don't Capture) on vectors where
-
# the target pin is being used to drive data:
-
#
-
# PINS nvm_fail
-
# 0 d1:0 r1:D 0
-
# 1 d1:1 r1:D 1
-
# 2 r1:C Capt
-
# 3 r1:D NoCapt
-
#
-
# Sometimes when generating vectors within a loop you may want to apply a capture
-
# retrospectively to a previous vector, passing in an offset option will allow you
-
# to do this.
-
#
-
# ==== Examples
-
# $tester.cycle # This is the vector you want to capture
-
# $tester.store :pin => pin(:fail) # This applys the required opcode to the given pins
-
#
-
# $tester.cycle # This one gets captured
-
# $tester.cycle
-
# $tester.cycle
-
# $tester.store(:pin => pin(:fail), :offset => -2) # Just realized I need to capture that earlier vector
-
#
-
# # Capturing multiple pins:
-
# $tester.cycle
-
# $tester.store :pins => [pin(:fail), pin(:done)]
-
#
-
# Since the STIL store operates on a pin level (rather than vector level as on the J750)
-
# equivalent functionality can also be achieved by setting the store attribute of the pin
-
# itself prior to calling $tester.cycle.
-
# However it is recommended to use the tester API to do the store if cross-compatibility with
-
# other platforms, such as the J750, is required.
-
1
def store(*pins)
-
26
options = pins.last.is_a?(Hash) ? pins.pop : {}
-
26
options = { offset: 0
-
}.merge(options)
-
26
pins = pins.flatten.compact
-
26
if pins.empty?
-
fail 'For the STIL generation you must supply the pins to store/capture'
-
end
-
26
pins.each do |pin|
-
27
pin.restore_state do
-
27
pin.capture
-
27
update_vector_pin_val pin, offset: options[:offset]
-
27
last_vector(options[:offset]).dont_compress = true
-
27
last_vector(options[:offset]).contains_capture = true
-
end
-
end
-
end
-
1
alias_method :capture, :store
-
-
# Same as the store method, except that the capture will be applied to the next
-
# vector to be generated.
-
#
-
# @example
-
# $tester.store_next_cycle
-
# $tester.cycle # This is the vector that will be captured
-
1
def store_next_cycle(*pins)
-
1
options = pins.last.is_a?(Hash) ? pins.pop : {}
-
1
options = {
-
}.merge(options)
-
1
pins = pins.flatten.compact
-
1
if pins.empty?
-
fail 'For STIL generation you must supply the pins to store/capture'
-
end
-
2
pins.each { |pin| pin.save; pin.capture }
-
# Register this clean up function to be run after the next vector
-
# is generated, cool or what!
-
1
preset_next_vector do |vector|
-
1
vector.contains_capture = true
-
1
pins.each(&:restore)
-
end
-
end
-
1
alias_method :store!, :store_next_cycle
-
-
1
def match(pin, state, timeout_in_cycles, options = {})
-
2
Origen.log.warning "Call to match loop on pin #{pin.id} is not supported by the STIL generator and has been ignored"
-
end
-
-
1
def match_block(timeout_in_cycles, options = {}, &block)
-
1
Origen.log.warning 'Call to match loop block is not supported by the STIL generator and has been ignored'
-
end
-
-
# Add a loop to the pattern.
-
#
-
# Pass in the number of times to execute it, all vectors
-
# generated by the given block will be captured in the loop.
-
#
-
# ==== Examples
-
# $tester.loop_vectors 3 do # Do this 3 times...
-
# $tester.cycle
-
# some_other_method_to_generate_vectors
-
# end
-
#
-
# For compatibility with the J750 you can supply a name as the first argument
-
# and that will simply be ignored when generated for the V93K tester...
-
#
-
# $tester.loop_vectors "my_loop", 3 do # Do this 3 times...
-
# $tester.cycle
-
# some_other_method_to_generate_vectors
-
# end
-
1
def loop_vectors(name = nil, number_of_loops = 1, _global = false)
-
# The name argument is present to maych J750 API, sort out the
-
3
unless name.is_a?(String) || name.is_a?(Symbol)
-
1
name, number_of_loops, global = 'loop', name, number_of_loops
-
end
-
3
if number_of_loops > 1
-
2
@loop_counters ||= {}
-
2
if @loop_counters[name]
-
@loop_counters[name] += 1
-
else
-
2
@loop_counters[name] = 0
-
end
-
2
loop_name = @loop_counters[name] == 0 ? name : "#{name}_#{@loop_counters[name]}"
-
2
loop_name = loop_name.symbolize
-
2
microcode "#{loop_name}: Loop #{number_of_loops} {"
-
2
yield
-
2
microcode '}'
-
else
-
1
yield
-
end
-
end
-
1
alias_method :loop_vector, :loop_vectors
-
-
# An internal method called by Origen to generate the pattern footer
-
1
def pattern_footer(options = {})
-
22
cycle dont_compress: true # one extra single vector before stop microcode
-
22
microcode 'Stop;' unless options[:subroutine]
-
22
microcode '}'
-
22
@footer_done = true
-
end
-
-
# Returns an array of subroutines called while generating the current pattern
-
1
def called_subroutines
-
40
@called_subroutines ||= []
-
end
-
-
# Call a subroutine.
-
#
-
# This calls a subroutine immediately following previous vector, it does not
-
# generate a new vector.
-
#
-
# Subroutines should always be called through this method as it ensures a running
-
# log of called subroutines is maintained and which then gets output in the pattern
-
# header to import the right dependencies.
-
#
-
# An offset option is available to make the call on earlier vectors.
-
#
-
# Repeated calls to the same subroutine will automatically be compressed unless
-
# option :suppress_repeated_calls is supplied and set to false. This means that for
-
# the common use case of calling a subroutine to implement an overlay the subroutine
-
# can be called for every bit that has the overlay and the pattern will automatically
-
# generate correctly.
-
#
-
# ==== Examples
-
# $tester.call_subroutine("mysub")
-
# $tester.call_subroutine("my_other_sub", :offset => -1)
-
1
def call_subroutine(name, options = {})
-
options = {
-
20
offset: 0,
-
suppress_repeated_calls: true
-
}.merge(options)
-
20
called_subroutines << name.to_s.chomp unless called_subroutines.include?(name.to_s.chomp) || @inhibit_vectors
-
-
20
code = "Call #{name};"
-
20
if !options[:suppress_repeated_calls] ||
-
last_object != code
-
20
microcode code, offset: (options[:offset] * -1)
-
end
-
end
-
-
1
def push_comment(msg)
-
1539
if @footer_done
-
484
stage.store msg unless @inhibit_comments
-
else
-
1055
stage.store "Ann {*#{msg}*}" unless @inhibit_comments
-
end
-
end
-
-
# This is an internal method use by Origen which returns a fully formatted vector
-
# You can override this if you wish to change the output formatting at vector level
-
1
def format_vector(vec)
-
6957
timeset = vec.timeset ? "#{vec.timeset.name}" : ''
-
6957
pin_vals = vec.pin_vals ? "#{vec.pin_vals};".gsub(' ', '') : ''
-
6957
sig_name = tester.ordered_pins_name || 'ALL'
-
6957
if sig_name.nil?
-
Origen.log.warn "WARN: SigName must be defined for STIL format. Use pin_pattern_order(*pins, name: <sigName>). Default to 'ALL'"
-
sig_name = 'ALL'
-
end
-
6957
if vec.repeat > 1
-
2016
microcode = "Loop #{vec.repeat} {\n"
-
else
-
4941
microcode = vec.microcode ? vec.microcode : ''
-
end
-
6957
if vec.pin_vals && ($_testers_enable_vector_comments || vector_comments)
-
comment = "// V:#{vec.number} C:#{vec.cycle} #{vec.inline_comment}"
-
else
-
6957
comment = vec.inline_comment.empty? ? '' : "Ann {*// #{vec.inline_comment}*}"
-
end
-
-
6957
microcode_post = vec.repeat > 1 ? "\n}" : ''
-
6957
"#{microcode} V { \"#{sig_name}\" = #{pin_vals} }#{comment}#{microcode_post}"
-
end
-
end
-
end
-
end
-
1
module OrigenTesters
-
1
module StilBasedTester
-
1
class D10 < Base
-
1
def initialize(options = {})
-
options = {
-
1
pattern_only: true
-
}.merge(options)
-
1
super(options)
-
1
@name = 'd10'
-
end
-
-
1
def d10?
-
true
-
end
-
end
-
end
-
1
D10 = StilBasedTester::D10
-
end
-
1
module OrigenTesters
-
1
module StilBasedTester
-
1
class STIL < Base
-
end
-
end
-
# Support OrigenTesters::STIL.new
-
1
STIL = StilBasedTester::STIL
-
end
-
2
module OrigenTesters
-
2
module Test
-
# A simple interface designed to test the Testers::BasicTestSetups module
-
2
class BasicInterface
-
2
include OrigenTesters::BasicTestSetups
-
-
2
def functional(name, options = {})
-
# Apply custom defaults before calling
-
options = {
-
7
bin: 3
-
}.merge(options)
-
# Now call the generator
-
7
super
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Test
-
2
class Block
-
2
attr_accessor :id, :selected
-
-
2
def initialize(id, owner)
-
1608
@id = id
-
1608
@selected = false
-
1608
@owner = owner
-
end
-
-
2
def select
-
30
@selected = true
-
end
-
-
2
def owner
-
@owner
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Test
-
2
class ComplexTimingDUT
-
2
include Origen::TopLevel
-
-
2
def initialize(options = {})
-
add_timeset(:complex_timing)
-
timeset(:complex_timing) do |t|
-
t.period_in_ns = 1
-
t.drive_wave(:tclk) do |w|
-
w.drive(0, at: 0)
-
w.drive(:data, at: 'period/2')
-
end
-
end
-
end
-
-
2
def startup
-
tester.set_timeset(:complex_timing)
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Test
-
2
class CustomTestInterface
-
2
include OrigenTesters::ProgramGenerators
-
-
2
def initialize(options = {})
-
6
add_custom_til if tester.try(:igxl_based?)
-
6
add_custom_tml if tester.v93k?
-
end
-
-
2
def custom(name, options = {})
-
18
name = "custom_#{name}".to_sym
-
18
if tester.try(:igxl_based?)
-
9
ti = test_instances.mylib.test_a(name)
-
9
ti.my_arg0 = 'arg0_set'
-
9
ti.my_arg2_alias = 'curr'
-
9
ti.set_my_arg4('arg4_set_from_method')
-
-
9
elsif tester.v93k?
-
9
ti = test_methods.my_tml.test_a
-
9
ti.my_arg0 = 'arg0_set'
-
9
ti.my_arg2_alias = 'CURR'
-
9
ti.set_my_arg4('arg4_set_from_method')
-
-
end
-
end
-
-
2
def custom_b(name, options = {})
-
3
name = "custom_b_#{name}".to_sym
-
3
if tester.v93k?
-
3
ti = test_methods.my_tml.test_b
-
3
ti.my_arg0 = 'arg0_set'
-
end
-
end
-
-
2
def custom_c(name, options = {})
-
6
name = "custom_c_#{name}".to_sym
-
6
if tester.v93k?
-
6
ti = test_methods.my_tml.test_c
-
6
ti.my_arg0 = 'arg0_set'
-
6
if options[:my_arg1]
-
3
ti.my_arg0 = 'arg1_should_render'
-
3
ti.my_arg1 = options[:my_arg1]
-
else
-
3
ti.my_arg0 = 'arg1_should_not_render'
-
end
-
end
-
end
-
-
2
def custom_d(name, options = {})
-
3
name = "custom_d_#{name}".to_sym
-
3
if tester.v93k?
-
3
ti = test_methods.my_tml.test_d
-
end
-
end
-
-
2
def custom_hash(name, options = {})
-
2
name = "custom_hash_#{name}".to_sym
-
2
if tester.v93k? && tester.smt8?
-
2
ti = test_methods.my_tml.test_hash
-
2
ti.my_arg_hash = {
-
my_param_name: {
-
my_arg2: 1
-
}
-
}
-
end
-
end
-
-
2
private
-
-
2
def add_custom_tml
-
3
add_tml :my_tml,
-
test_a: {
-
# Parameters can be defined with an underscored symbol as the name, this can be used
-
# if the C++ implementation follows the standard V93K convention of calling the attribute
-
# the camel cased version, starting with a lower-cased letter, i.e. 'testerState' in this
-
# first example.
-
# The attribute definition has two required parameters, the type and the default value.
-
# The type can be :string, :current, :voltage, :time, :frequency, or :integer
-
# An optional 3rd parameter can be supplied to give an array of allowed values. If supplied,
-
# Origen will raise an error upon an attempt to set it to an unlisted value.
-
tester_state: [:string, 'CONNECTED', %w(CONNECTED UNCHANGED)],
-
test_name: [:string, 'Functional'],
-
my_arg0: [:string, ''],
-
my_arg1: [:string, 'a_default_value'],
-
my_arg2: [:string, 'VOLT', %w(VOLT CURR)],
-
my_arg3: [:string, ''],
-
my_arg4: [:string, ''],
-
# In cases where the C++ library has deviated from standard attribute naming conventions
-
# (camel-cased with lower cased first character), the absolute attribute name can be given
-
# as a string.
-
# The Ruby/Origen accessor for these will be the underscored version, with '.' characters
-
# converted to underscores, e.g. tm.bad_practice, tm.really_bad_practice, etc.
-
'BadPractice' => [:string, 'NO', %w(NO YES)],
-
'Really.BadPractice' => [:string, ''],
-
# Attribute aliases can be defined like this:
-
aliases: {
-
my_arg2_alias: :my_arg2
-
},
-
# Define any methods you want the test method to have
-
methods: {
-
# An optional finalize function can be supplied to do any final test instance configuration, this
-
# function will be called immediately before the test method is finally rendered. The test method
-
# object itself will be passed in as an argument.
-
finalize: lambda do |tm|
-
9
tm.my_arg3 = 'arg3_set_from_finalize'
-
end,
-
# Example of a custom method.
-
# In all cases the test method object will be passed in as the first argument.
-
set_my_arg4: lambda do |tm, val|
-
9
tm.my_arg4 = val
-
end
-
}
-
},
-
test_b: {
-
render_limits_in_tf: false,
-
my_arg0: [:string, ''],
-
my_arg1: [:string, 'b_default_value']
-
},
-
test_c: {
-
tester_state: [:string, 'CONNECTED', %w(CONNECTED UNCHANGED)],
-
test_name: [:string, 'Functional'],
-
my_arg0: [:string, ''],
-
my_arg1: [:string, 'DELETE_ME'],
-
my_arg2: [:string, 'VOLT', %w(VOLT CURR)],
-
-
# Define any methods you want the test method to have
-
methods: {
-
# An optional finalize function can be supplied to do any final test instance configuration, this
-
# function will be called immediately before the test method is finally rendered. The test method
-
# object itself will be passed in as an argument.
-
finalize: lambda do |tm|
-
6
if tm.my_arg1 == 'DELETE_ME'
-
3
tm.remove_parameter(:my_arg1)
-
end
-
end
-
}
-
},
-
test_d: {
-
tester_state: [:string, 'CONNECTED', %w(CONNECTED UNCHANGED)],
-
test_name: [:string, 'Functional'],
-
current_arg: [:current, 1],
-
current_no_default: [:current, ''],
-
voltage_arg: [:voltage, 1.2],
-
voltage_no_default: [:voltage, ''],
-
time_arg: [:time, 10],
-
time_no_default: [:time, ''],
-
frequency_arg: [:frequency, 1_000_000],
-
frequency_no_default: [:frequency, ''],
-
integer_arg: [:integer, 5.22],
-
integer_no_default: [:integer, ''],
-
double_arg: [:double, '5.22'],
-
double_no_default: [:double, ''],
-
boolean_arg: [:boolean, true],
-
boolean_no_default: [:boolean, '']
-
},
-
test_hash: {
-
# Parameters can be defined with an underscored symbol as the name, this can be used
-
# if the C++ implementation follows the standard V93K convention of calling the attribute
-
# the camel cased version, starting with a lower-cased letter, i.e. 'testerState' in this
-
# first example.
-
# The attribute definition has two required parameters, the type and the default value.
-
# The type can be :string, :current, :voltage, :time, :frequency, or :integer
-
# An optional 3rd parameter can be supplied to give an array of allowed values. If supplied,
-
# Origen will raise an error upon an attempt to set it to an unlisted value.
-
tester_state: [:string, 'CONNECTED', %w(CONNECTED UNCHANGED)],
-
test_name: [:string, 'Functional'],
-
my_list_string: [:list_strings, %w(E1 E2)],
-
my_list_class: [:list_classes, %w(E1 E2)],
-
my_arg_hash: [{
-
my_arg0: [:string, ''],
-
my_arg1: [:string, 'a_default_value'],
-
my_arg2: [:integer, 0],
-
my_arg2: [:list_strings, %w(E1 E2)],
-
my_arg3: [:list_classes, %w(E1 E2)]
-
}]
-
# Define any methods you want the test method to have
-
}
-
end
-
-
2
def add_custom_til
-
3
add_til :mylib,
-
test_a: {
-
# Basic arg
-
my_arg0: :arg0,
-
# Basic arg with default value
-
my_arg1: [:arg1, 'a_default_value'],
-
# Basic arg with default value and possible values
-
my_arg2: [:arg2, 'volt', %w(volt curr)],
-
my_arg3: :arg3,
-
my_arg4: :arg4,
-
# Attribute aliases can be defined like this:
-
aliases: {
-
my_arg_alias: :my_arg,
-
my_arg1_alias: :my_arg1,
-
my_arg2_alias: :my_arg2
-
},
-
# Define any methods you want the test method to have
-
methods: {
-
# An optional finalize function can be supplied to do any final test instance configuration, this
-
# function will be called immediately before the test instance is finally rendered. The test instance
-
# object itself will be passed in as an argument.
-
finalize: lambda do |ti|
-
9
ti.my_arg3 = 'arg3_set_from_finalize'
-
end,
-
# Example of a custom method.
-
# In all cases the test method object will be passed in as the first argument.
-
set_my_arg4: lambda do |ti, val|
-
9
ti.my_arg4 = val
-
end
-
}
-
}
-
end
-
end
-
end
-
end
-
1
module OrigenTesters
-
1
module Test
-
1
module Decompiler
-
1
module Dummy
-
1
extend OrigenTesters::Decompiler::API
-
-
1
class DummyTester
-
1
include VectorBasedTester
-
end
-
-
1
class PatternParsersMissing < OrigenTesters::Decompiler::Pattern
-
end
-
-
1
class PatternParseFrontmatterOnly < OrigenTesters::Decompiler::Pattern
-
1
def self.parse_frontmatter(raw_frontmatter:, context:)
-
OrigenTesters::Decompiler::Nodes::Frontmatter.new(context: context, pattern_header: [], comments: [])
-
end
-
end
-
-
1
class PatternParseFrontmatterPinlist < PatternParseFrontmatterOnly
-
1
def self.parse_pinlist(raw_pinlist:, context:)
-
OrigenTesters::Decompiler::Nodes::Pinlist.new(context: context, pattern_header: [], comments: [])
-
end
-
end
-
-
1
class PatternParseFrontmatterPinlistVector < PatternParseFrontmatterPinlist
-
1
def self.parse_vector(raw_vector:, context:)
-
OrigenTesters::Decompiler::Nodes::Vector.new(
-
context: context,
-
repeat: 0,
-
timeset: 'timeset',
-
pin_states: %w(p1 p2),
-
comment: 'Comment'
-
)
-
end
-
end
-
-
1
class Pattern < PatternParseFrontmatterPinlistVector
-
1
@platform = 'dummy'
-
@platform_tokens = {
-
1
comment_start: '#',
-
test_token: '!'
-
}
-
-
@splitter_config = {
-
1
pinlist_start: 0,
-
vectors_start: 0,
-
vectors_end: -1
-
}
-
-
@parser_config = {
-
1
platform_grammar_name: 'OrigenTesters::Decompiler::BaseGrammar::VectorBased',
-
include_base_tokens_grammar: true,
-
include_vector_based_grammar: true
-
}
-
end
-
-
1
class PatternIncomplete < PatternParseFrontmatterPinlistVector
-
1
@platform = 'dummy_incomplete'
-
end
-
-
1
class PatternNoParserConfig < PatternParseFrontmatterPinlistVector
-
1
@platform = 'pattern_no_parser_config'
-
1
@parser_config = nil
-
@splitter_config = {
-
1
pinlist_start: 0,
-
vectors_start: 0,
-
vectors_end: -1
-
}
-
end
-
-
1
class PatternNoSplitterConfig < PatternParseFrontmatterPinlistVector
-
1
@platform = 'pattern_no_splitter_config'
-
1
@parser_config = {}
-
1
@splitter_config = nil
-
end
-
-
1
class PatternIncompleteSplitterConfig < PatternParseFrontmatterPinlistVector
-
1
@platform = 'pattern_incomplete_splitter_config'
-
1
@parser_config = {}
-
@splitter_config = {
-
1
vectors_end: -1
-
}
-
end
-
-
1
class PatternNoVerify < PatternParseFrontmatterPinlistVector
-
1
@platform = 'pattern_no_verify'
-
1
@no_verify = true
-
end
-
end
-
-
1
module DummyWithDecompiler
-
1
def self.suitable_decompiler_for(pattern: nil, tester: nil, **options)
-
1
if pattern && (Pathname(pattern).extname == '.atp')
-
OrigenTesters::IGXLBasedTester
-
1
elsif tester && (tester == 'j750' || tester == 'uflex' || tester == 'ultraflex')
-
OrigenTesters::IGXLBasedTester
-
end
-
end
-
end
-
-
1
module DummyWithDecompilerMissingMethod
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Test
-
2
class DUT
-
# Simple DUT using Nexus interface
-
-
2
attr_accessor :blocks
-
2
attr_accessor :hv_supply_pin
-
2
attr_accessor :lv_supply_pin
-
2
attr_accessor :digsrc_pins
-
2
attr_accessor :digcap_pins
-
2
attr_accessor :digsrc_settings
-
2
attr_accessor :digcap_settings
-
2
attr_accessor :target_load_count
-
-
2
include OrigenARMDebug
-
2
include Origen::TopLevel
-
2
include OrigenJTAG
-
-
2
def initialize(options = {})
-
options = {
-
494
test_generic_overlay_capture: false
-
}.merge(options)
-
-
@test_options = {
-
494
test_generic_overlay_capture: options[:test_generic_overlay_capture]
-
}
-
-
494
@target_load_count = 0
-
-
494
add_pin :tclk
-
494
add_pin :tdi
-
494
add_pin :tdo
-
494
add_pin :tms
-
494
if @test_options[:test_generic_overlay_capture]
-
# approved patts for this test type do not use these
-
13
add_pin :pa0
-
13
add_pin :pa1
-
13
add_pin :pa2
-
13
add_pin_group :pa, :pa2, :pa1, :pa0
-
13
add_pin_alias :tdi_a, :tdi
-
end
-
-
494
if options[:extra_pins]
-
options[:extra_pins].times do |i|
-
add_pin "PIN_#{i}".to_sym
-
end
-
end
-
# Add capitalized equivalent pins
-
494
add_pin_alias :TCLK, :tclk
-
494
add_pin_alias :TDI, :tdi
-
494
add_pin_alias :TDO, :tdo
-
494
add_pin_alias :TMS, :tms
-
-
# add_pin_group :jtag, :tdi, :tdo, :tms
-
494
add_power_pin_group :vdd1
-
494
add_power_pin_group :vdd2
-
494
add_virtual_pin :virtual1, type: :virtual_pin
-
494
add_virtual_pin :virtual2, type: :ate_ch
-
-
494
reg :testme32, 0x007a do |reg|
-
494
reg.bits 31..16, :portB
-
494
reg.bits 15..8, :portA
-
494
reg.bits 1, :done
-
494
reg.bits 0, :enable
-
end
-
494
unless @test_options[:test_generic_overlay_capture]
-
# approved patts for this test type do not use these
-
481
@hv_supply_pin = 'VDDHV'
-
481
@lv_supply_pin = 'VDDLV'
-
481
@digsrc_pins = [:tdi, :tms]
-
481
@digsrc_settings = { digsrc_mode: :parallel, digsrc_bit_order: :msb }
-
481
@digcap_pins = :tdo
-
481
@digcap_settings = { digcap_format: :twos_complement }
-
end
-
494
@blocks = [Block.new(0, self), Block.new(1, self), Block.new(2, self)]
-
-
494
add_timeset 'tp0'
-
end
-
-
2
def on_create
-
494
unless @test_options[:test_generic_overlay_capture]
-
481
if tester && tester.uflex?
-
123
tester.assign_dc_instr_pins([hv_supply_pin, lv_supply_pin])
-
123
tester.assign_digsrc_pins(digsrc_pins)
-
123
tester.apply_digsrc_settings(digsrc_settings)
-
123
tester.assign_digcap_pins(digcap_pins)
-
123
tester.apply_digcap_settings(digcap_settings)
-
123
tester.memory_test_en = true
-
end
-
end
-
end
-
-
2
def on_load_target
-
494
@target_load_count += 1
-
end
-
-
2
def startup(options)
-
55
$tester.set_timeset('tp0', 60)
-
end
-
-
2
def write_register(reg, options = {})
-
44
arm_debug.write_register(reg, options)
-
end
-
-
2
def read_register(reg, options = {})
-
102
arm_debug.write_register(reg, options)
-
end
-
-
2
def execute(options = {})
-
20
options = { define: false, # whether to define subr or call it
-
name: 'executefunc1',
-
onemodsub: false # whether to expects subr to be in single module
-
}.merge(options)
-
-
20
if options[:define]
-
# define subroutine
-
11
$tester.start_subroutine(options[:name], onemodsub: options[:onemodsub])
-
11
$tester.cycle
-
11
$tester.end_subroutine(onemodsub: options[:onemodsub])
-
11
$tester.cycle unless options[:onemodsub]
-
else
-
# call subroutine
-
9
$tester.cycle
-
9
$tester.call_subroutine(options[:name])
-
9
$tester.cycle
-
end
-
end
-
-
# Match loop functionality
-
2
def match(options = {})
-
63
options = { type: :match_pin, # whether to match DONE bit in register or match pin
-
# :match_done
-
# :match_2pins
-
delay_in_us: 5, # match loop delay
-
define: false, # whether to define subr or call it
-
subr_name: false, # default use match type as subr name
-
}.merge(options)
-
-
63
subr_name = options[:subr_name] ? options[:subr_name] : options[:type].to_s
-
-
63
if options[:define]
-
27
$tester.start_subroutine(subr_name)
-
27
$tester.cycle
-
27
if options[:type] == :match_done
-
-
# Match DONE bit in register
-
15
$tester.wait(match: true,
-
time_in_us: options[:delay_in_us],
-
global_loops: true,
-
check_for_fails: true,
-
force_fail_on_timeout: true,
-
clr_fail_post_match: true,
-
manual_stop: true) do
-
# Match on reading done bit
-
30
reg(:testme32).bits(:done).write(1)
-
30
reg(:testme32).bits(:done).read!
-
end
-
12
elsif options[:type] == :match_pin
-
# Match on TDO pin state
-
3
$tester.wait(match: true,
-
pin: pin(:tdo),
-
state: :high,
-
time_in_us: options[:delay_in_us],
-
global_loops: true,
-
check_for_fails: true,
-
force_fail_on_timeout: true,
-
clr_fail_post_match: true,
-
manual_stop: true)
-
9
elsif options[:type] == :match_2pins
-
# Match on TDO pin state
-
3
$tester.wait(match: true,
-
pin: pin(:tdo),
-
state: :high,
-
pin2: pin(:tms),
-
state2: :high,
-
time_in_us: options[:delay_in_us],
-
global_loops: true,
-
check_for_fails: true,
-
force_fail_on_timeout: true,
-
clr_fail_post_match: true,
-
manual_stop: true)
-
6
elsif options[:type] == :match_2pins_custom_jump
-
# Match on TDO pin state
-
3
$tester.wait(match: true,
-
pin: pin(:tdo),
-
state: :high,
-
pin2: pin(:tms),
-
state2: :high,
-
time_in_us: options[:delay_in_us],
-
on_pin_match_goto: { 0 => 'no_fails_found' },
-
on_timeout_goto: 'no_fails_found',
-
global_loops: true,
-
check_for_fails: true,
-
force_fail_on_timeout: true,
-
clr_fail_post_match: true,
-
manual_stop: true)
-
3
$tester.cycle
-
3
$tester.set_code(200)
-
3
$tester.branch('match_done')
-
3
$tester.label('no_fails_found')
-
3
$tester.set_code(201)
-
3
$tester.label('match_done')
-
3
elsif options[:type] == :multiple_entries
-
# Match on TDO pin state, with multiple subr entry points
-
3
$tester.wait(match: true,
-
pin: pin(:tdo),
-
state: :high,
-
time_in_us: options[:delay_in_us],
-
global_loops: true,
-
multiple_entries: true,
-
check_for_fails: true,
-
force_fail_on_timeout: true,
-
clr_fail_post_match: true,
-
manual_stop: true)
-
end
-
27
$tester.cycle
-
27
$tester.end_subroutine
-
27
$tester.cycle
-
else
-
# call subroutine
-
36
$tester.cycle
-
36
$tester.call_subroutine(subr_name)
-
36
$tester.cycle
-
end
-
end
-
-
2
def handshake(options = {})
-
options = {
-
12
define: false, # whether to define subr or call it
-
}.merge(options)
-
-
12
if options[:define]
-
3
$tester.start_subroutine('handshake')
-
3
$tester.handshake(readcode: 100)
-
3
$tester.cycle
-
3
$tester.cycle
-
3
$tester.cycle
-
3
$tester.end_subroutine
-
else
-
9
$tester.cycle
-
9
$tester.call_subroutine('handshake')
-
end
-
end
-
-
2
def keepalive(options = {})
-
options = {
-
1
define: false, # whether to define subr or call it
-
allow_subroutine: false,
-
subroutine_pat: true
-
}.merge(options)
-
-
1
if options[:define]
-
1
$tester.start_subroutine('keep_alive')
-
1
$tester.keep_alive(options)
-
1
$tester.end_subroutine
-
else
-
$tester.cycle
-
$tester.call_subroutine('keep_alive')
-
end
-
end
-
2
alias_method :keep_alive, :keepalive
-
-
2
def digsrc_overlay(options = {})
-
2
options = { define: false, # whether to define subr or call it
-
subr_name: false, # default use match type as subr name
-
digsrc_pins: @digsrc_pins, # defaults to what's defined in $dut
-
overlay_reg: nil, # defaults to testme32 register
-
overlay_cycle_num: 32, # Only needed if overlay_reg is NOT nil, this specificies how many clk cycles to overlay.
-
}.merge(options)
-
2
if options[:define]
-
2
$tester.start_subroutine(options[:subr_name]) # Start subroutine
-
2
digsrc_pins = $tester.assign_digsrc_pins(options[:digsrc_pins])
-
2
$tester.digsrc_start(digsrc_pins, dssc_mode: :single)
-
2
original_pin_states = {}
-
2
digsrc_pins.each do |pin|
-
4
original_pin_states.merge!(pin => pin(pin).data)
-
4
pin(pin).drive_mem
-
end
-
2
if options[:overlay_reg].nil?
-
1
options[:overlay_cycle_num].times do
-
64
$tester.digsrc_send(digsrc_pins)
-
64
$tester.cycle
-
end
-
else
-
1
$tester.dont_compress = true
-
1
options[:overlay_reg].size.times do
-
8
$tester.digsrc_send(digsrc_pins)
-
8
$tester.cycle
-
end
-
end
-
2
original_pin_states.each do |pin, state|
-
4
pin(pin).drive(state)
-
end
-
2
$tester.digsrc_stop(digsrc_pins)
-
2
$tester.cycle
-
2
$tester.end_subroutine # end subroutine
-
else
-
$tester.cycle
-
$tester.call_subroutine(options[:subr_name])
-
end
-
end
-
-
2
def memory_test(options = {})
-
3
options = {
-
}.merge(options)
-
-
3
$tester.memory_test(inc_counter_x: true, gen_vector: true)
-
-
3
$tester.memory_test(inc_counter_y: true, gen_vector: true)
-
-
3
$tester.memory_test(init_counter_x: true)
-
-
3
$tester.memory_test(inc_counter_x: true, init_counter_y: true)
-
-
3
$tester.memory_test(inc_counter_y: true, capture_vector: true)
-
-
3
$tester.memory_test(pin: pin(:tdo), pin_data: :expect)
-
end
-
-
2
def freq_count(options = {})
-
3
options = {
-
}.merge(options)
-
-
3
$tester.freq_count($dut.pin(:tdo), readcode: 73)
-
end
-
-
# dummy flag to check for a particular design bug for this DUT
-
2
def has_margin0_bug?
-
10
false
-
end
-
-
2
def find_block_by_id(id)
-
@blocks.find { |block| block.id == id }
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Test
-
2
class DUT2
-
2
include Origen::TopLevel
-
-
2
def initialize
-
42
add_pin :reset, reset: :drive_hi, name: 'nvm_reset'
-
42
add_pin :clk, reset: :drive_hi, name: 'nvm_clk'
-
42
add_pin :clk_mux, reset: :drive_hi, name: 'nvm_clk_mux'
-
42
add_pin :porta, reset: :drive_lo, size: 8
-
42
add_pin :portb, reset: :drive_lo, size: 8, endian: :little
-
42
add_pin :invoke, reset: :drive_lo, name: 'nvm_invoke'
-
42
add_pin :done, reset: :expect_hi, name: 'nvm_done'
-
42
add_pin :fail, reset: :expect_lo, name: 'nvm_fail'
-
42
add_pin :alvtst, reset: :dont_care, name: 'nvm_alvtst'
-
42
add_pin :ahvtst, reset: :dont_care, name: 'nvm_ahvtst'
-
42
add_pin :dtst, reset: :dont_care, name: 'nvm_dtst'
-
-
42
add_pin :tclk, reset: :drive_lo
-
42
add_pin :trst, reset: :drive_hi
-
-
42
add_pin_alias :extal, :clk
-
42
add_pin_alias :extal_mux, :clk_mux
-
42
add_pin_alias :tms, :done
-
42
add_pin_alias :tdo, :fail
-
42
add_pin_alias :tdi, :invoke
-
42
add_pin_alias :resetb, :ahvtst
-
42
add_pin_alias :nvm_reset, :reset
-
42
add_pin_alias :nvm_clk, :clk
-
42
add_pin_alias :nvm_clk_mux, :clk_mux
-
42
add_pin_alias :nvm_invoke, :invoke
-
42
add_pin_alias :nvm_done, :done
-
42
add_pin_alias :nvm_fail, :fail
-
42
add_pin_alias :nvm_alvtst, :alvtst
-
42
add_pin_alias :nvm_ahvtst, :ahvtst
-
42
add_pin_alias :nvm_dtst, :dtst
-
-
42
add_pin_alias :pa5, :porta, pin: 5
-
42
add_pin_alias :pa_lower, :porta, pins: [3..0]
-
42
add_pin_alias :pa_upper, :porta, pins: [7, 6, 5, 4]
-
42
add_pin_alias :porta_alias, :porta
-
-
42
pins.each do |name, pin|
-
1134
add_pin_alias(name.upcase, name) unless has_pin?(name.upcase)
-
end
-
end
-
-
2
def startup(options)
-
39
if options[:add_additional_pins]
-
1
add_pin :late_added_pin, reset: :drive_hi
-
else
-
# Test that rendering some vectors from a template works...
-
38
if $tester.is_a?(J750)
-
34
$tester.render("#{Origen.root}/pattern/nvm/j750/_mode_entry.atp.erb", hold_cycles: 5)
-
end
-
end
-
39
$tester.set_timeset('nvmbist', 40) if $tester.is_vector_based?
-
end
-
-
2
def has_margin0_bug?
-
false
-
end
-
-
2
def write_register(reg, options = {})
-
reg
-
end
-
-
2
def read_register(reg, options = {})
-
reg
-
end
-
-
2
def base_address(reg, options = {})
-
if reg.owned_by?(:nvm)
-
0x4000_0000
-
else
-
0
-
end
-
end
-
-
2
def origen_dot_root
-
Origen.root
-
end
-
-
2
def origen_dot_root!
-
Origen.root!
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Test
-
2
class EmptyDUT
-
2
include OrigenARMDebug
-
2
include Origen::TopLevel
-
2
include OrigenJTAG
-
-
2
def initialize(options = {})
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Test
-
2
class Interface
-
2
include OrigenTesters::ProgramGenerators
-
2
include OrigenTesters::Charz
-
-
2
attr_accessor :include_additional_prb2_test
-
2
attr_reader :environment
-
-
# Options passed to Flow.create and Library.create will be passed in here, use as
-
# desired to configure your interface
-
2
def initialize(options = {})
-
100
@environment = options[:environment]
-
100
add_charz
-
100
add_my_tml if tester.v93k?
-
end
-
-
2
def add_my_tml
-
77
add_tml :my_hash_tml,
-
class_name: 'MyTmlHashNamespace',
-
-
# Here is a test definition.
-
# The identifier should be lower-cased and underscored, in-keeping with Ruby naming conventions.
-
# By default the class name will be the camel-cased version of this identifier, so 'myTest' in
-
# this case.
-
my_hash_test: {
-
# [OPTIONAL] The C++ test method class name can be overridden from the default like this:
-
class_name: 'MyHashExampleClass',
-
# [OPTIONAL] If the test method does not require a definition in the testmethodlimits section
-
# of the .tf file, you can suppress like this:
-
# render_limits_in_file: false,
-
# Parameters can be defined with an underscored symbol as the name, this can be used
-
# if the C++ implementation follows the standard V93K convention of calling the attribute
-
# the camel cased version, starting with a lower-cased letter, i.e. 'testerState' in this
-
# first example.
-
# The attribute definition has two required parameters, the type and the default value.
-
# The type can be :string, :current, :voltage, :time, :frequency, integer, :double or :boolean
-
pin_list: [:string, ''],
-
samples: [:integer, 1],
-
precharge_voltage: [:voltage, 0],
-
settling_time: [:time, 0],
-
# An optional parameter that sets the limits name in the 'testmethodlimits' section
-
# of the generated .tf file. Defaults to 'Functional' if not provided.
-
test_name: [:string, 'HashExample'],
-
# An optional 3rd parameter can be supplied to provide an array of allowed values. If supplied,
-
# Origen will raise an error upon an attempt to set it to an unlisted value.
-
tester_state: [:string, 'CONNECTED', %w(CONNECTED UNCHANGED DISCONNECTED)],
-
force_mode: [:string, 'VOLT', %w(VOLT CURR)],
-
# The name of another parameter can be supplied as the type argument, meaning that the type
-
# here will be either :current or :voltage depending on the value of :force_mode
-
# force_value: [:force_mode, 3800.mV],
-
# In cases where the C++ library has deviated from standard attribute naming conventions
-
# (camel-cased with lower cased first character), the absolute attribute name can be given
-
# as a string.
-
# The Origen accessor for these will be the underscored version, with '.' characters
-
# converted to underscores e.g. tm.an_unusual_name
-
'hashParameter': [{ param_name0: [:string, 'NO'], param_name1: [:integer, 0] }],
-
'hashParameter2': [{ param_name0: [:string, 'NO'], param_name1: [:integer, 0] }],
-
'nestedHashParameter': [{
-
param_name0: [:string, ''],
-
param_list_strings: [:list_strings, %w(E1 E2)],
-
param_list_classes: [:list_classes, %w(E1 E2)],
-
'param_group.param0': [:string, ''],
-
param_name1: [{
-
param_name_int: [:integer, 0],
-
param_name_double: [:double, 0],
-
param_list_strings: [:list_strings, %w(E1 E2)],
-
param_list_classes: [:list_classes, %w(E1 E2)],
-
'param_group.param1': [:string, '']
-
}]
-
}],
-
'nestedHashParameter2': [{
-
param_name0: [:string, ''],
-
param_name1: [{
-
param_name_int: [:integer, 0]
-
}]
-
}]
-
}
-
77
add_tml :my_type_check,
-
class_name: 'MyTypeCheck',
-
-
# Here is a test definition.
-
# The identifier should be lower-cased and underscored, in-keeping with Ruby naming conventions.
-
# By default the class name will be the camel-cased version of this identifier, so 'myTest' in
-
# this case.
-
my_type_check_test: {
-
# [OPTIONAL] The C++ test method class name can be overridden from the default like this:
-
class_name: 'MyHashExampleClass',
-
int: [:integer, 1],
-
double: [:double, 1.0],
-
int_no_default: [:integer],
-
double_no_default: [:double]
-
}
-
end
-
-
2
def add_charz
-
100
add_charz_routine :routine1 do |routine|
-
100
routine.name = '_cz__rt1'
-
end
-
100
add_charz_routine :routine2 do |routine|
-
100
routine.name = '_cz__rt2'
-
end
-
100
add_charz_routine :routine3 do |routine|
-
100
routine.name = '_cz__rt3'
-
end
-
100
add_charz_routine :routine4 do |routine|
-
100
routine.name = '_cz__rt4'
-
end
-
100
add_charz_routine :routine5 do |routine|
-
100
routine.name = '_cz__rt5'
-
end
-
100
add_charz_routine :routine6 do |routine|
-
100
routine.name = '_cz__rt6'
-
end
-
100
add_charz_profile :cz do |profile|
-
100
profile.routines = [:routine3]
-
end
-
100
add_charz_profile :cz_only do |profile|
-
100
profile.charz_only = true
-
100
profile.routines = [:routine1]
-
end
-
100
add_charz_profile :simple_gates do |profile|
-
100
profile.flags = :my_flag
-
100
profile.enables = :my_enable
-
100
profile.routines = [:routine1]
-
end
-
100
add_charz_profile :complex_gates do |profile|
-
100
profile.flags = { ['$MyFlag1'] => [:routine1, :routine2], ['$MyFlag2'] => [:routine3], '$MyFlag3' => :routine4 }
-
100
profile.enables = { ['$MyEnable1'] => [:routine1], ['$MyEnable2'] => [:routine2, :routine3], '$MyEnable3' => :routine5 }
-
100
profile.routines = [:routine1, :routine2, :routine3, :routine4, :routine5, :routine6]
-
end
-
-
100
add_charz_profile :simple_anded_flags do |profile|
-
100
profile.and_flags = true
-
100
profile.routines = [:routine1]
-
end
-
-
100
add_charz_profile :simple_anded_enables do |profile|
-
100
profile.and_enables = true
-
100
profile.routines = [:routine1]
-
end
-
-
100
add_charz_profile :complex_anded_flags do |profile|
-
100
profile.and_flags = true
-
100
profile.enables = :my_enable
-
100
profile.routines = [:routine1]
-
end
-
-
100
add_charz_profile :complex_anded_enables do |profile|
-
100
profile.and_enables = true
-
100
profile.flags = :my_flag
-
100
profile.routines = [:routine1]
-
end
-
end
-
-
# Test that the block form of flow control methods like this can
-
# be overridden by an interface
-
2
def if_job(*jobs)
-
42
jobs = jobs.flatten
-
42
jobs.delete(:prb9)
-
42
super
-
end
-
2
alias_method :if_jobs, :if_job
-
-
2
def log(msg)
-
711
if tester.j750? || tester.uflex?
-
293
flow.logprint(msg)
-
else
-
418
flow.log(msg)
-
end
-
end
-
-
2
def func(name, options = {})
-
options = {
-
2127
duration: :static
-
}.merge(options)
-
2127
number = options[:number]
-
-
2127
if tester.j750? || tester.uflex?
-
862
block_loop(name, options) do |block, i, group|
-
886
options[:number] = number + i if number && i
-
886
ins = test_instances.functional(name)
-
886
ins.set_wait_flags(:a) if options[:duration] == :dynamic
-
886
ins.pin_levels = options.delete(:pin_levels) if options[:pin_levels]
-
886
if group
-
36
pname = "#{name}_b#{i}_pset"
-
36
patsets.add(pname, [{ pattern: "#{name}_b#{i}.PAT" },
-
{ pattern: 'nvm_global_subs.PAT', start_label: 'subr' }])
-
36
ins.pattern = pname
-
36
flow.test(group, options) if i == 0
-
else
-
850
pname = "#{name}_pset"
-
850
patsets.add(pname, [{ pattern: "#{name}.PAT" },
-
{ pattern: 'nvm_global_subs.PAT', start_label: 'subr' }])
-
850
ins.pattern = pname
-
850
if options[:cz_setup]
-
15
flow.cz(ins, options[:cz_setup], options)
-
else
-
835
flow.test(ins, options)
-
end
-
end
-
end
-
-
1265
elsif tester.v93k?
-
1265
block_loop(name, options) do |block, i|
-
1321
options[:number] = number + i if number && i
-
1321
tm = test_methods.ac_tml.ac_test.functional_test
-
1321
ts = test_suites.run(name, options)
-
1321
ts.test_method = tm
-
1321
if tester.smt8?
-
590
ts.spec = options.delete(:pin_levels) if options[:pin_levels]
-
590
ts.spec ||= 'specs.Nominal'
-
else
-
731
ts.levels = options.delete(:pin_levels) if options[:pin_levels]
-
end
-
1321
if block
-
84
ts.pattern = "#{name}_b#{i}"
-
else
-
1237
ts.pattern = name.to_s
-
# if options[:cz_setup]
-
# flow.cz(ins, options[:cz_setup], options)
-
# else
-
# end
-
end
-
1321
flow.test ts, options
-
end
-
end
-
end
-
-
2
def func_with_charz(name, options = {})
-
options = {
-
47
duration: :static
-
}.merge(options)
-
-
47
if tester.v93k?
-
47
if tester.smt7?
-
47
tm = test_methods.ac_tml.ac_test.functional_test
-
47
ts = test_suites.run(name, options)
-
47
ts.test_method = tm
-
47
ts.pattern = 'charz_example'
-
-
47
test_level_charz = false
-
47
if options[:charz]
-
2
charz_on(*options[:charz])
-
2
test_level_charz = true
-
end
-
-
47
unless charz_only? && !options[:charz_test]
-
46
options[:parent_test_name] = name
-
46
set_conditional_charz_id(options)
-
46
flow.test ts, options
-
end
-
-
47
unless options[:charz_test]
-
16
insert_charz_tests(options.merge(parent_test_name: name, charz_test: true)) do |options|
-
31
charz_name = :"#{name}_#{charz_routines[options[:current_routine]].name}"
-
31
func_with_charz(charz_name, options)
-
end
-
end
-
-
47
charz_off if test_level_charz
-
else
-
fail 'Only SMT7 is Implemented for Charz'
-
end
-
else
-
fail "Tester #{tester.name} Not Yet Implemented for Charz"
-
end
-
end
-
-
2
def func_with_comment(name, options = {})
-
6
if tester.v93k?
-
options = {
-
6
duration: :static
-
}.merge(options)
-
6
number = options[:number]
-
-
6
block_loop(name, options) do |block, i|
-
6
options[:number] = number + i if number && i
-
6
tm = test_methods.ac_tml.ac_test.functional_test
-
6
ts = test_suites.run(name, options)
-
6
ts.test_method = tm
-
6
ts.levels = options.delete(:pin_levels) if options[:pin_levels]
-
6
ts.comment = options.delete(:comment) || flow.active_description
-
6
if block
-
ts.pattern = "#{name}_b#{i}"
-
else
-
6
ts.pattern = name.to_s
-
# if options[:cz_setup]
-
# flow.cz(ins, options[:cz_setup], options)
-
# else
-
# end
-
end
-
6
flow.test ts, options
-
end
-
else
-
func(name, options)
-
end
-
end
-
-
2
def double_int_type_check(name, options = {})
-
10
number = options[:number]
-
10
if tester.v93k?
-
7
block_loop(name, options) do |block, i|
-
7
options[:number] = number + i if number && i
-
7
tm = test_methods.my_type_check.my_type_check_test
-
7
tm.int = '1'
-
7
tm.double = '1.0'
-
7
tm.int_no_default = ''
-
7
tm.double_no_default = ''
-
7
ts = test_suites.run(name, options)
-
7
ts.test_method = tm
-
7
flow.test ts, options
-
end
-
end
-
end
-
-
2
def my_hash_test(name, options = {})
-
2
number = options[:number]
-
-
2
if tester.v93k? && tester.smt8?
-
2
block_loop(name, options) do |block, i|
-
2
options[:number] = number + i if number && i
-
2
tm = test_methods.my_hash_tml.my_hash_test
-
2
tm.hashParameter = {
-
param1: {}
-
}
-
2
tm.nestedHashParameter = {
-
my_param_name0: {
-
param_name0: 'hello',
-
param_group_param0: 'test_group',
-
param_name1: {
-
my_param_name1: {
-
param_name_int: '1',
-
param_name_double: '1.0',
-
param_group_param1: 'test_nested_group'
-
},
-
my_param_name2: {
-
param_name_int: 2,
-
param_name_double: 2.0
-
},
-
my_param_name3: {
-
param_name_int: 3
-
}
-
}
-
}
-
}
-
2
tm.nestedHashParameter2 = {
-
my_param_name4: {
-
param_name0: 'goodbye'
-
},
-
my_param_name5: {
-
param_name0: 'goodbye forever'
-
}
-
}
-
2
tm.samples = '2'
-
2
ts = test_suites.run(name, options)
-
2
ts.test_method = tm
-
2
ts.spec = options.delete(:pin_levels) if options[:pin_levels]
-
2
ts.spec ||= 'specs.Nominal'
-
2
flow.test ts, options
-
end
-
end
-
end
-
-
2
def my_override_spec_test(name, options = {})
-
2
number = options[:number]
-
-
2
if tester.v93k? && tester.smt8?
-
2
tm = test_methods.ac_tml.ac_test.functional_test
-
2
ts = test_suites.run(name, options)
-
2
ts.test_method = tm
-
2
ts.spec = options.delete(:pin_levels) if options[:pin_levels]
-
2
ts.spec ||= 'specs.Nominal'
-
2
ts.pattern = 'pat1'
-
2
ts.burst = 'sequence1'
-
2
ts.spec_path = 'myCustomSpecPath'
-
2
ts.seq_path = 'myCustomSeqPath'
-
2
ts.spec_namespace = 'myCustomSpecNamespace'
-
2
ts.seq_namespace = 'myCustomSeqNamespace'
-
2
flow.test ts, options
-
end
-
end
-
-
2
def block_loop(name, options)
-
2144
if options[:by_block]
-
40
if tester.j750? || tester.uflex?
-
12
test_instances.group do |group|
-
12
group.name = name
-
12
$dut.blocks.each_with_index do |block, i|
-
36
yield block, i, group
-
end
-
end
-
28
elsif tester.v93k?
-
28
flow.group name, options do
-
28
$dut.blocks.each_with_index do |block, i|
-
84
yield block, i
-
end
-
end
-
end
-
else
-
2104
yield
-
end
-
end
-
-
2
def shmoo(name, targets, options = {})
-
10
if tester.v93k? && tester.smt8?
-
10
targets = [targets] unless targets.is_a?(Array)
-
10
st = shmoo_tests.run(name, { targets: targets }.merge(options))
-
10
flow.test st, options
-
end
-
end
-
-
2
def por(options = {})
-
options = {
-
10
instance_not_available: true
-
}.merge(options)
-
10
if tester.j750? || tester.uflex?
-
3
flow.test('por_ins', options)
-
else
-
7
func('por_ins', options)
-
end
-
end
-
-
2
def para(name, options = {})
-
options = {
-
6
high_voltage: false
-
}.merge(options)
-
-
6
if tester.j750?
-
2
if options.delete(:high_voltage)
-
2
ins = test_instances.bpmu(name)
-
else
-
ins = test_instances.ppmu(name)
-
end
-
2
ins.dc_category = 'NVM_PARA'
-
2
flow.test(ins, options)
-
2
patsets.add("#{name}_pset", pattern: "#{name}.PAT")
-
end
-
end
-
-
# OR 2 IDS together into 1 flag
-
2
def or_ids(options = {})
-
flow.or_flags(options[:id1], options[:id2], options)
-
end
-
-
2
def nop(options = {})
-
flow.nop options
-
end
-
-
2
def mto_memory(name, options = {})
-
options = {
-
10
duration: :static
-
}.merge(options)
-
-
10
if tester.j750?
-
2
block_loop(name, options) do |block, i, group|
-
2
ins = test_instances.mto_memory(name)
-
2
ins.set_wait_flags(:a) if options[:duration] == :dynamic
-
2
ins.pin_levels = options.delete(:pin_levels) if options[:pin_levels]
-
2
if group
-
pname = "#{name}_b#{i}_pset"
-
patsets.add(pname, [{ pattern: "#{name}_b#{i}.PAT" },
-
{ pattern: 'nvm_global_subs.PAT', start_label: 'subr' }])
-
ins.pattern = pname
-
flow.test(group, options) if i == 0
-
else
-
2
pname = "#{name}_pset"
-
2
patsets.add(pname, [{ pattern: "#{name}.PAT" },
-
{ pattern: 'nvm_global_subs.PAT', start_label: 'subr' }])
-
2
ins.pattern = pname
-
2
if options[:cz_setup]
-
flow.cz(ins, options[:cz_setup], options)
-
else
-
2
flow.test(ins, options)
-
end
-
end
-
end
-
end
-
end
-
-
2
def meas_multi_limits(name, options = {})
-
options = {
-
4
duration: :static
-
}.merge(options)
-
-
4
name = "measmulti_#{name}" unless name.to_s =~ /measmulti/
-
-
4
if tester.uflex?
-
4
ins = test_instances.functional(name)
-
4
ins.set_wait_flags(:a) if options[:duration] == :dynamic
-
4
ins.pin_levels = options.delete(:pin_levels) if options[:pin_levels]
-
4
ins.defer_limits = options[:defer_limits]
-
-
# some made up sub test limits
-
4
options[:sub_tests] = [sub_test('limit1', lo: 0, hi: 7), sub_test('limit2', lo: 3, hi: 8)]
-
-
4
pname = "#{name}_pset"
-
4
patsets.add(pname, [{ pattern: "#{name}.PAT" },
-
{ pattern: 'nvm_global_subs.PAT', start_label: 'subr' }])
-
4
ins.pattern = pname
-
-
4
flow.test(ins, options)
-
end
-
end
-
-
2
def meas(name, options = {})
-
options = {
-
166
duration: :static
-
}.merge(options)
-
-
166
name = "meas_#{name}" unless name.to_s =~ /meas/
-
-
166
if tester.j750? || tester.uflex?
-
71
if tester.uflex?
-
25
if options[:pins] == :dcvi
-
1
ins = test_instances.dcvi_powersupply(name)
-
1
ins.set_wait_flags(:a) # set wait flag for tester handshake with patterns
-
1
ins.relay_mode = 1 # tlPowered - keep power on
-
else
-
24
ins = test_instances.functional(name)
-
24
ins.set_wait_flags(:a) if options[:duration] == :dynamic
-
24
ins.scale = options[:scale]
-
24
ins.units = options[:units]
-
end
-
25
ins.pin_levels = options.delete(:pin_levels) if options[:pin_levels]
-
25
ins.lo_limit = options[:lo_limit]
-
25
ins.hi_limit = options[:hi_limit]
-
25
ins.defer_limits = options[:defer_limits]
-
else
-
46
if options[:pins] == :hi_v
-
2
ins = test_instances.board_pmu(name)
-
44
elsif options[:pins] == :power
-
2
ins = test_instances.powersupply(name)
-
else
-
42
ins = test_instances.pin_pmu(name)
-
end
-
46
ins.set_wait_flags(:a) if options[:duration] == :dynamic
-
46
ins.pin_levels = options.delete(:pin_levels) if options[:pin_levels]
-
46
ins.lo_limit = options[:lo_limit]
-
46
ins.hi_limit = options[:hi_limit]
-
end
-
-
71
pname = "#{name}_pset"
-
71
patsets.add(pname, [{ pattern: "#{name}.PAT" },
-
{ pattern: 'nvm_global_subs.PAT', start_label: 'subr' }])
-
71
ins.pattern = pname
-
71
if options[:cz_setup]
-
flow.cz(ins, options[:cz_setup], options)
-
else
-
71
flow.test(ins, options)
-
end
-
-
95
elsif tester.v93k?
-
95
tm = test_methods.dc_tml.dc_test.general_pmu
-
95
ts = test_suites.run(name, options)
-
95
ts.test_method = tm
-
95
if tester.smt8?
-
28
ts.spec = options.delete(:pin_levels) if options[:pin_levels]
-
28
ts.spec ||= 'specs.Nominal'
-
else
-
67
ts.levels = options.delete(:pin_levels) if options[:pin_levels]
-
end
-
95
ts.lo_limit = options[:lo_limit] if options[:lo_limit]
-
95
ts.hi_limit = options[:hi_limit] if options[:hi_limit]
-
95
ts.pattern = name.to_s
-
# if options[:cz_setup]
-
# flow.cz(ins, options[:cz_setup], options)
-
# else
-
# use_limit_params = [:lo_limit, :hi_limit, :scale, :units] # define options to strip for flow.test
-
# options_use_limit = options.dup # duplicate, as modifying options directly, even an assigned copy modifies original
-
# flow.test(ins, options.reject! { |k, _| use_limit_params.include? k }) # set up test skipping use-limit options
-
# flow.use_limit(name, options_use_limit) if options_use_limit[:hi_limit] || options_use_limit[:lo_limit] # Only use use-limit if limits present in flow
-
# end
-
95
flow.test ts, options
-
end
-
-
166
def group(name, options = {})
-
88
flow.group name, options do |group|
-
88
yield group
-
end
-
end
-
-
####################################################
-
####### UltraFLEX Pinmap Stuff ####################
-
####################################################
-
-
# Assign relevant pins for pinmap sheet generation
-
166
def pinmap(name, options = {})
-
1
pinmap = pinmaps("#{name}")
-
1
Origen.top_level.add_pin_group :JTAG, :tdi, :tdo, :tms
-
1
Origen.top_level.power_pin_groups.keys.each do |grp_key|
-
2
pinmap.add_power_pin(grp_key, type: 'Power', comment: "# #{grp_key}")
-
end
-
1
Origen.top_level.virtual_pins.keys.each do |util_pin|
-
2
upin = Origen.top_level.virtual_pins(util_pin)
-
2
case upin.type
-
when :virtual_pin
-
1
pinmap.add_utility_pin(upin.name, type: 'Utility', comment: "# #{util_pin}")
-
when :ate_ch
-
1
pinmap.add_utility_pin(upin.name, type: 'I/O', comment: "# #{util_pin}")
-
end
-
end
-
1
Origen.top_level.pin.keys.each do |pkey|
-
4
pinmap.add_pin(Origen.top_level.pin(pkey).name, type: 'I/O', comment: "# #{pkey}")
-
end
-
1
Origen.top_level.pin_groups.keys.sort.each do |gkey|
-
# Do not include pins that are aliased to themselves
-
1
Origen.top_level.pin(gkey).each do |pin|
-
3
pinmap.add_group_pin(gkey, Origen.top_level.pin(pin.id).name, type: 'I/O', comment: "# #{gkey}")
-
end
-
end
-
end
-
-
# Assign relevant edges in preparation for edgeset/timeset sheet generation
-
166
def edge(category, pin, options = {})
-
options = {
-
4
d_src: 'PAT', # source of the channel drive data (e.g. pattern, drive_hi, drive_lo, etc.)
-
d_fmt: 'NR', # drive data format (NR, RL, RH, etc.)
-
d0_edge: '', # time at which the input drive is turned on
-
d1_edge: '', # time of the initial data drive edge
-
d2_edge: '', # time of the return format data drive edge
-
d3_edge: '', # time at which the input drive is turned off
-
c_mode: 'Edge', # output compare mode
-
c1_edge: '', # time of the initial output compare edge
-
c2_edge: '', # time of the final output compare edge (window compare)
-
t_res: 'Machine', # timing resolution (possibly ATE-specific)
-
clk_per: '' # clock period equation - for use with MCG
-
}.merge(options)
-
-
4
@edge_collection = edges
-
4
@edge_collection.add(category, pin, options)
-
end
-
-
166
def edge_collection
-
@edge_collection
-
end
-
-
166
def edgeset(sheet_name, options = {})
-
options = {
-
16
edgeset: :es_default,
-
period: 'cycle', # tester cycle period
-
t_mode: 'Machine' # edgeset timing mode (possibly ATE-specific)
-
}.merge(options)
-
16
edgeset = options.delete(:edgeset)
-
16
pin = options.delete(:pin)
-
16
edge = options.delete(:edge)
-
-
16
@edgeset = edgesets(sheet_name, options)
-
16
@edgeset.add(edgeset, pin, edge, options)
-
16
collect_ac_specs(@edgeset.es[edgeset].spec_sheet, edge)
-
end
-
-
166
def timeset(sheet_name, options = {})
-
options = {
-
16
timeset: :default,
-
master_ts: :default
-
}.merge(options)
-
16
timeset = options.delete(:timeset)
-
16
pin = options.delete(:pin)
-
16
eset = options.delete(:eset)
-
-
16
@timeset = timesets(sheet_name, options)
-
16
@timeset.add(timeset, pin, eset, options)
-
end
-
-
166
def ac_specset(sheet_name, expression, options = {})
-
options = {
-
4
specset: :default,
-
nom: { typ: nil }
-
}.merge(options)
-
-
4
ss = ac_specsets(sheet_name)
-
4
add_ac_specs(ss, expression, options)
-
end
-
-
# Collects AC Spec object(s) from the given expression and adds them to the given Specset
-
166
def collect_ac_specs(ssname, edge, options = {})
-
options = {
-
16
nom: { typ: nil }
-
}.merge(options)
-
-
# Create a Specsets object from the UFlex program generator API
-
16
ss = ac_specsets(ssname.to_sym)
-
16
add_ac_specs(ss, edge.clk_per, options)
-
16
add_ac_specs(ss, edge.d0_edge, options)
-
16
add_ac_specs(ss, edge.d1_edge, options)
-
16
add_ac_specs(ss, edge.d2_edge, options)
-
16
add_ac_specs(ss, edge.d3_edge, options)
-
16
add_ac_specs(ss, edge.c1_edge, options)
-
16
add_ac_specs(ss, edge.c2_edge, options)
-
end
-
-
# Adds new AC Spec object(s) to the given Specset
-
166
def add_ac_specs(ss, expression, options = {})
-
options = {
-
116
specset: :default
-
}.merge(options)
-
-
116
return unless expression.is_a? String
-
# collect all variable names within the expression
-
116
vars = expression.scan(/[a-zA-Z][\w]+/).map(&:to_sym)
-
116
vars.each do |var|
-
74
next if var =~ /^(d0_edge|d1_edge|d2_edge|d3_edge|c1_edge|c2_edge)$/
-
# The substitutions below are used for backward compatibility
-
58
next if var =~ /^(d_on|d_data|d_ret|d_off|c_open|c_close)$/
-
58
next if var =~ /^(nS|uS|mS|S)$/i
-
58
next if ss.ac_specsets.key?(options[:specset]) && ss.ac_specsets[options[:specset]].include?(var)
-
-
9
ss.add(var, options)
-
end
-
end
-
-
# Assign relevant power supply levels in preparation for levelset sheet generation
-
166
def pwr_level(category, options = {})
-
options = {
-
1
vmain: 1.8, # Main supply voltage
-
valt: 1.8, # Alternate supply voltage
-
ifold: 1, # Supply clamp current
-
delay: 0 # Supply power-up delay
-
}.merge(options)
-
-
1
@level_collection = levels
-
1
@level_collection.add_power_level(category, options)
-
end
-
-
# Assign relevant single-ended pin levels in preparation for levelset sheet generation
-
166
def pin_level_se(category, options = {})
-
options = {
-
2
vil: 0, # Input drive low
-
vih: 1.8, # Input drive high
-
vol: 1.0, # Output compare low
-
voh: 0.8, # Output compare high
-
vcl: -1, # Voltage clamp low
-
vch: 2.5, # Voltage clamp high
-
vt: 0.9, # Termination voltage
-
voutlotyp: 0, #
-
vouthityp: 0, #
-
dmode: 'Largeswing-VT' # Driver mode
-
}.merge(options)
-
-
2
@level_collection = levels
-
2
@level_collection.add_se_pin_level(category, options)
-
end
-
-
166
def level_collection
-
@level_collection
-
end
-
-
166
def levelset(sheet_name, options = {})
-
6
pin = options.delete(:pin)
-
6
level = options.delete(:level)
-
-
6
@levelset = levelsets(sheet_name)
-
6
@levelset.add(sheet_name, pin, level, options)
-
6
collect_dc_specs(@levelset.spec_sheet, level)
-
end
-
-
166
def dc_specset(sheet_name, expression, options = {})
-
options = {
-
4
min: { min: nil },
-
nom: { typ: nil },
-
max: { max: nil }
-
}.merge(options)
-
-
4
ss = dc_specsets(sheet_name.to_sym)
-
4
add_dc_specs(ss, expression, options)
-
end
-
-
# Collects DC Spec object(s) from the given expression and adds them to the given Specset
-
166
def collect_dc_specs(ssname, level, options = {})
-
options = {
-
6
nom: { typ: nil },
-
min: { min: nil },
-
max: { max: nil }
-
}.merge(options)
-
-
# Create a Specsets object from the UFlex program generator API
-
6
ss = dc_specsets(ssname.to_sym)
-
6
if level.respond_to?(:vmain)
-
2
add_dc_specs(ss, level.vmain, options)
-
2
add_dc_specs(ss, level.valt, options)
-
2
add_dc_specs(ss, level.ifold, options)
-
4
elsif level.respond_to?(:vil)
-
4
add_dc_specs(ss, level.vil, options)
-
4
add_dc_specs(ss, level.vih, options)
-
4
add_dc_specs(ss, level.vol, options)
-
4
add_dc_specs(ss, level.voh, options)
-
4
add_dc_specs(ss, level.vcl, options)
-
4
add_dc_specs(ss, level.vch, options)
-
4
add_dc_specs(ss, level.vt, options)
-
4
add_dc_specs(ss, level.voutlotyp, options)
-
4
add_dc_specs(ss, level.vouthityp, options)
-
end
-
end
-
-
# Adds new DC Spec object(s) to the given Specset
-
166
def add_dc_specs(ss, expression, options = {})
-
options = {
-
46
specset: :default
-
}.merge(options)
-
-
46
return unless expression.is_a? String
-
46
vars = expression.scan(/[a-zA-Z][\w]+/).map(&:to_sym)
-
46
vars.each do |var|
-
38
next if var =~ /^(nA|uA|mA|A|nV|uV|mV|V)$/i
-
-
38
ss.add(var, options)
-
end
-
end
-
-
166
def global_spec(var, options = {})
-
options = {
-
4
job: nil,
-
value: nil,
-
comment: nil
-
}.merge(options)
-
-
4
global_specs('SpecsGlobal').add(var, job: options[:job], value: options[:value], comment: options[:comment])
-
end
-
-
166
def job_def(jname, options = {})
-
options = {
-
4
pinmap: pinmap_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
-
8
instances: test_instance_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
-
16
flows: flow_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
-
2
ac_specs: ac_specset_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
-
2
dc_specs: dc_specset_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
-
8
patsets: patset_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
-
patgroups: patgroup_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
-
bintables: [],
-
cz: [],
-
test_procs: [],
-
mix_sig_timing: [],
-
wave_defs: [],
-
psets: [],
-
sigs_port_map: [],
-
fract_bus: [],
-
comment: nil
-
}.merge(options)
-
-
2
program_jobs('Jobs').add(jname, options)
-
end
-
-
166
def reference(reference, options = {})
-
options = {
-
2
comment: nil
-
}.merge(options)
-
-
2
references('Refs').add(reference, options)
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Test
-
2
class NVM
-
2
attr_accessor :blocks
-
-
2
include Origen::Pins
-
2
include Origen::Registers
-
-
2
def initialize
-
42
add_reg :mclkdiv, 0x03, 16, osch: { pos: 15 },
-
asel: { pos: 14 },
-
failctl: { pos: 13 },
-
parsel: { pos: 12 },
-
eccen: { pos: 11 },
-
cmdloc: { pos: 8, bits: 3, res: 0b001 },
-
clkdiv: { pos: 0, bits: 8, res: 0x18 }
-
-
42
add_reg :data, 0x4, 16, d: { pos: 0, bits: 16 }
-
-
42
@blocks = [Block.new(0, self), Block.new(1, self), Block.new(2, self)]
-
end
-
-
2
def find_block_by_id(id)
-
90
@blocks.find { |block| block.id == id }
-
end
-
-
2
def reg_owner_alias
-
%w(flash fmu)
-
end
-
-
2
def override_method
-
:overridden
-
end
-
-
2
def added_method
-
:added
-
end
-
-
2
def add_proth_reg
-
reg :proth, 0x0024, size: 32 do
-
bits 31..24, :fprot7, reset: 0xFF
-
bits 23..16, :fprot6, reset: 0xEE
-
bits 15..8, :fprot5, reset: 0xDD
-
bits 7..0, :fprot4, reset: 0x11
-
end
-
end
-
end
-
-
2
class NVMSub < NVM
-
2
def redefine_data_reg
-
add_reg :data, 0x40, 16, d: { pos: 0, bits: 16 }
-
end
-
-
# Tests that the block format for defining registers works
-
2
def add_reg_with_block_format
-
# ** Data Register 3 **
-
# This is dreg
-
add_reg :dreg, 0x1000, size: 16 do
-
# This is dreg bit 15
-
bit 15, :bit15, reset: 1
-
# **Bit 14** - This does something cool
-
#
-
# 0 | Coolness is disabled
-
# 1 | Coolness is enabled
-
bits 14, :bit14
-
# This is dreg bit upper
-
bits 13..8, :upper
-
# This is dreg bit lower
-
# This is dreg bit lower line 2
-
bit 7..0, :lower, writable: false, reset: 0x55
-
end
-
-
# This is dreg2
-
reg :dreg2, 0x1000, size: 16 do
-
# This is dreg2 bit 15
-
bit 15, :bit15, reset: 1
-
# This is dreg2 bit upper
-
bits 14..8, :upper
-
# This is dreg2 bit lower
-
# This is dreg2 bit lower line 2
-
bit 7..0, :lower, writable: false, reset: 0x55
-
end
-
-
# Finally a test that descriptions can be supplied via the API
-
reg :dreg3, 0x1000, size: 16, description: "** Data Register 3 **\nThis is dreg3" do
-
bit 15, :bit15, reset: 1, description: 'This is dreg3 bit 15'
-
bit 14, :bit14, description: "**Bit 14** - This does something cool\n\n0 | Coolness is disabled\n1 | Coolness is enabled"
-
bits 13..8, :upper, description: 'This is dreg3 bit upper'
-
bit 7..0, :lower, writable: false, reset: 0x55, description: "This is dreg3 bit lower\nThis is dreg3 bit lower line 2"
-
end
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Timing
-
2
require 'origen_testers/timing/timeset'
-
2
require 'origen_testers/timing/timing_api'
-
-
2
extend ActiveSupport::Concern
-
2
include TimingAPI
-
-
# Each time the toplevel is instantiated, we'll reset the timing, preserving
-
# the behavior when the timesets were stored on the tester object directly.
-
2
class TopLevelWatcher
-
2
include Origen::PersistentCallbacks
-
-
2
def before_load_target
-
632
OrigenTesters::Timing.reset!
-
end
-
end
-
2
@top_level_watcher = TopLevelWatcher.new
-
-
2
included do
-
# When set to true all pattern vectors will be converted to use the same period (the
-
# shortest period used in the pattern).
-
#
-
# @example
-
# $tester.set_timeset("fast", 40)
-
# 2.cycles # fast 1 0 0 1 0
-
# # fast 1 0 0 1 0
-
#
-
# $tester.level_period = false # Without levelling enabled
-
# $tester.set_timeset("slow", 80)
-
# 2.cycles # slow 1 0 0 1 0
-
# # slow 1 0 0 1 0
-
#
-
# $tester.level_period = true # With levelling enabled
-
# $tester.set_timeset("slow", 80)
-
# 2.cycles # fast 1 0 0 1 0
-
# # fast 1 0 0 1 0
-
# # fast 1 0 0 1 0
-
# # fast 1 0 0 1 0
-
#
-
# @see Timing#timing_toggled_pins
-
8
attr_accessor :level_period
-
8
alias_method :level_period?, :level_period
-
8
attr_writer :timing_toggled_pins
-
end
-
-
2
def self.timesets!
-
632
@timesets = {}.with_indifferent_access
-
end
-
-
2
def self.reset!
-
632
timesets!
-
632
@timeset = nil
-
632
@_last_timeset_change = nil
-
632
@min_period_timeset = nil
-
end
-
-
2
def self.set_timeset(timeset, period_in_ns = nil)
-
275
def self._set_timeset_(timeset, period_in_ns = nil)
-
# If the period_in_ns was given, use that.
-
# Alternatively, the period_in_ns may have been set on the Timeset object
-
# already.
-
# If not, then complain that we need a period_in_ns before proceeding.
-
281
if period_in_ns
-
265
timeset._period_in_ns_ = period_in_ns
-
# elsif !timeset.period_in_ns?
-
# fail 'You must supply a period_in_ns argument to set_timeset'
-
end
-
-
280
if @timeset
-
116
timeset_changed(timeset)
-
else
-
164
@timeset = timeset
-
end
-
280
timeset.called = true
-
280
@timeset = timeset
-
280
timeset
-
end
-
-
275
if timeset.is_a?(Array)
-
2
timeset, period_in_ns = timeset[0], timeset[1]
-
end
-
275
timeset ||= @timeset
-
275
if timeset.is_a?(Origen::Pins::Timing::Timeset) || timeset.is_a?(OrigenTesters::Timing::Timeset)
-
4
timeset = timeset.id.to_sym
-
end
-
275
timeset = (timesets[timeset] || lookup_or_register_timeset(timeset.to_s.chomp, period_in_ns: period_in_ns))
-
-
275
if block_given?
-
6
original = @timeset
-
6
_set_timeset_(timeset, period_in_ns)
-
6
yield
-
6
timeset = original
-
6
period_in_ns = timeset.period_in_ns
-
end
-
275
_set_timeset_(timeset, period_in_ns)
-
-
274
if @min_period_timeset && period_in_ns
-
105
@min_period_timeset = timeset if timeset.shorter_period_than?(@min_period_timeset)
-
else
-
169
@min_period_timeset = timeset
-
end
-
274
timeset
-
end
-
2
singleton_class.send(:alias_method, :with_timeset, :set_timeset)
-
-
2
def self.min_period_timeset
-
27080
@min_period_timeset
-
end
-
-
2
def self.timesets
-
1044
@timesets || timesets!
-
end
-
-
# Given a timeset name or object, either returns it, if it exists, or creates it, and returns
-
# the newly created timeset.
-
2
def self.lookup_or_register_timeset(t, period_in_ns: nil)
-
665
if t.is_a?(Origen::Pins::Timing::Timeset)
-
520
timesets[t.id] ||= Timeset.new(name: t.id, period_in_ns: period_in_ns)
-
else
-
145
timesets[t] ||= Timeset.new(name: t, period_in_ns: period_in_ns)
-
end
-
end
-
-
# Returns true if the current timeset is defined. False otherwise.
-
2
def self.timeset?(t)
-
if t.respond_to?(:name)
-
timesets.key?(t.name)
-
else
-
timesets.key?(t)
-
end
-
end
-
-
2
def self.timeset
-
3498
@timeset
-
end
-
-
2
def self.current_timeset
-
156477
@timeset
-
end
-
-
2
def self.period_in_ns
-
if timeset
-
timeset.period_in_ns
-
end
-
end
-
-
2
def self.timeset_changed(timeset)
-
116
if tester && tester.last_vector && tester.last_vector.timeset != timeset
-
110
change = { old: tester.last_vector.timeset, new: timeset }
-
# Suppress any duplicate calls
-
110
if !@_last_timeset_change ||
-
(@_last_timeset_change[:new] != change[:new] &&
-
@_last_timeset_change[:old] != change[:old])
-
107
tester.before_timeset_change(change)
-
end
-
110
@_last_timeset_change = change
-
end
-
end
-
-
2
def self.current_period_in_ns
-
1017
if timeset
-
968
timeset.period_in_ns
-
end
-
end
-
2
singleton_class.send(:alias_method, :period, :current_period_in_ns)
-
2
singleton_class.send(:alias_method, :current_period, :current_period_in_ns)
-
2
singleton_class.send(:alias_method, :period_in_ns, :current_period_in_ns)
-
-
2
def self.period_in_secs
-
if timeset
-
timeset.period_in_secs
-
end
-
end
-
2
singleton_class.send(:alias_method, :period_in_seconds, :period_in_secs)
-
-
# Returns any timesets that have been called during this execution.
-
# @return [Array] Array of OrigenTesters::Timing::Timeset objects that have been used so far.
-
2
def self.called_timesets
-
231
timesets.select { |n, t| t.called? }.values
-
end
-
# alias_method :called_timesets_by_instance, :called_timesets
-
-
# Similar to {#called_timesets}, but returns the name of the timesets instead.
-
# @return [Array] Array of names corresponding to the timesets that have been used so far.
-
2
def self.called_timesets_by_name
-
7
timesets.select { |n, t| t.called? }.keys
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Timing
-
2
class InvalidModification < Origen::OrigenError
-
end
-
-
2
class Timeset
-
2
attr_accessor :name, :cycled, :called
-
2
attr_reader :period_in_ns
-
-
2
def initialize(attrs = {})
-
665
@cycled = false
-
665
@locked = false
-
665
@called = false
-
-
665
attrs.each do |name, value|
-
1330
send("#{name}=", value)
-
end
-
-
665
self.period_in_ns = attrs[:period_in_ns]
-
end
-
-
# Returns true if the timeset has a shorter period than the supplied timeset
-
2
def shorter_period_than?(timeset)
-
105
period_in_ns < timeset.period_in_ns
-
end
-
-
# Returns true if <code>tester.cycle</code> has been called while this
-
# timeset was the current timeset.
-
# @return [true, false] <code>true</code> if this timeset has been cycled, <code>false</code> otherwise.
-
2
def cycled?
-
5
@cycled
-
end
-
-
# Returns true if this timeset does not allow changes to its period_in_ns
-
2
def locked?
-
1622
@locked
-
end
-
2
alias_method :period_in_ns_locked?, :locked?
-
2
alias_method :period_locked?, :locked?
-
2
alias_method :locked, :locked?
-
-
# Locks the current value of the timeset's period_in_ns. Attempts to further
-
# adjust the period_in_ns will results in an exception.
-
# @return [true, false] <code>true</code> if the period_in_ns has been locked, <code>false</code> otherwise.
-
2
def lock!
-
3
@locked = true
-
end
-
2
alias_method :lock_period!, :lock!
-
2
alias_method :lock_period_in_ns!, :lock!
-
-
# Sets the period_in_ns of this timeset and issues a callback to the <code>tester's #set_timeset</code>
-
# method, if this timeset is the current timeset, keeping the tester in
-
# sync with the changes to this timeset.
-
# @raise [InvalidModification] If the timeset is locked.
-
# @raise [InvalidModification] If period_in_ns is changed after the tester has been cycled using this timeset.
-
# @return [Fixnum] The updated period in ns.
-
2
def period_in_ns=(p)
-
1351
self._period_in_ns_ = p
-
-
# If this is the current timeset, reset the timeset from the tester
-
# side to verify that everything is in sync. Otherwise, the period_in_ns
-
# here may not match what the tester/DUT has.
-
1349
if current_timeset?
-
2
OrigenTesters::Timing.set_timeset(name, p)
-
end
-
-
# Return the period
-
1349
p
-
end
-
-
# Indicates whether a period_in_ns has been defined for this timeset.
-
# @return [true, false] <code>true</code> if the period_in_ns has been set, <code>false</code> otherwise.
-
2
def period_in_ns?
-
51882
!@period_in_ns.nil?
-
end
-
-
# Returns the current timeset in seconds
-
# @return [Float] Current period in seconds
-
2
def period_in_secs
-
if period_in_ns
-
period_in_ns * (10**-9)
-
end
-
end
-
2
alias_method :period_in_seconds, :period_in_secs
-
-
# Indicates whether this timeset is the current timeset.
-
# @return [true, false] <code>true</code> if this timeset is the current timeset, <code>false</code> otherwise.
-
2
def current_timeset?
-
1356
OrigenTesters::Timing.timeset == self
-
end
-
-
# Indicates whether this timeset is or has been set as the current timeset.
-
# @return [true, false] <code>true</code> if this timeset is or has beent he current timeset, <code>false</code> otherwise.
-
2
def called?
-
145
@called
-
end
-
-
# Alias for the {#name} attr_reader.
-
2
def id
-
697
name.to_sym
-
end
-
-
2
def dut_timeset
-
566
dut.timesets[id]
-
end
-
-
2
def method_missing(m, *args, &block)
-
64
if dut_timeset && (dut_timeset.methods.include?(m) || dut_timeset.private_methods.include?(m))
-
64
dut_timeset.send(m, *args, &block)
-
else
-
super
-
end
-
end
-
-
# @api private
-
2
def _period_in_ns_=(p)
-
1616
if locked?
-
3
Origen.app.fail(
-
exception_class: InvalidModification,
-
message: "Timeset :#{@name}'s period_in_ns is locked to #{@period_in_ns} ns!"
-
)
-
end
-
-
# Adding this causes examples in Origen (not OrigenTesters) to fail.
-
# Needs further discussion and potentially an Origen examples change.
-
# if cycled? && p != period_in_ns
-
# Origen.app!.fail(
-
# exception_class: InvalidModification,
-
# message: [
-
# "Timeset :#{name}'s period_in_ns cannot be changed after a cycle has occurred using this timeset!",
-
# " period_in_ns change occurred at #{caller[0]}",
-
# " Attempted to change period from #{@period_in_ns} to #{p}"
-
# ].join("\n")
-
# )
-
# end
-
1613
@period_in_ns = p
-
1613
@period_in_ns
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
2
module Timing
-
2
module TimingAPI
-
# @see Timing#level_period
-
#
-
# When period levelling is enabled, vectors will be expanded like this:
-
# $tester.set_timeset("fast", 40)
-
# 2.cycles # fast 1 0 0 1 0
-
# # fast 1 0 0 1 0
-
# # Without levelling enabled
-
# $tester.set_timeset("slow", 80)
-
# 2.cycles # slow 1 0 0 1 0
-
# # slow 1 0 0 1 0
-
# # With levelling enabled
-
# $tester.set_timeset("slow", 80)
-
# 2.cycles # fast 1 0 0 1 0
-
# # fast 1 0 0 1 0
-
# # fast 1 0 0 1 0
-
# # fast 1 0 0 1 0
-
#
-
# The overall time of the levelled/expanded vectors matches that of the unlevelled
-
# case. i.e. 4 cycles at fast speed (4 * 40ns = 160ns) is equivalent to 2 cycles
-
# at slow speed (2 * 80ns = 160ns).
-
#
-
# However, what if pin 1 in the example above was a clk pin where the 1 -> 0 transition
-
# was handled by the timing setup for that pin.
-
# In that case the levelled code is no longer functionally correct since it contains
-
# 4 clock pulses while the unlevelled code only has 2.
-
#
-
# Such pins can be specified via this attribute and the levelling logic will then
-
# automatically adjust the drive state to keep the number of pulses correct.
-
# It would automatically adjust to the alternative logic state where 0 means 'on'
-
# and 1 means 'off' if applicable.
-
#
-
# $tester.timing_toggled_pins << $dut.pin(:tclk) # This is pin 1
-
#
-
# $tester.set_timeset("fast", 40)
-
# 2.cycles # fast 1 0 0 1 0
-
# # fast 1 0 0 1 0
-
# # Without levelling enabled
-
# $tester.set_timeset("slow", 80)
-
# 2.cycles # slow 1 0 0 1 0
-
# # slow 1 0 0 1 0
-
# # With levelling enabled
-
# $tester.set_timeset("slow", 80)
-
# 2.cycles # fast 1 0 0 1 0
-
# # fast 0 0 0 1 0
-
# # fast 1 0 0 1 0
-
# # fast 0 0 0 1 0
-
#
-
# Multiple pins an be specified like this:
-
# $tester.timing_toggled_pins = [$dut.pin(:tclk), $dut.pin(:clk)] # Overrides any pins added elsewhere
-
# $tester.timing_toggled_pins << [$dut.pin(:tclk), $dut.pin(:clk)] # In addition to any pins added elsewhere
-
2
def timing_toggled_pins
-
297
@timing_toggled_pins ||= []
-
297
@timing_toggled_pins.flatten!
-
297
@timing_toggled_pins
-
end
-
-
# Set the timeset for the next vectors, this will remain in place until the next
-
# time this is called.
-
#
-
# $tester.set_timeset("bist_25mhz", 40)
-
#
-
# This method also accepts a block in which case the contained vectors will generate
-
# with the supplied timeset and subsequent vectors will return to the previous timeset
-
# automatically.
-
#
-
# $tester.set_timeset("bist_25mhz", 40) do
-
# $tester.cycle
-
# end
-
#
-
# The arguments can also be supplied as a single array, or not at all. In the latter case
-
# the existing timeset will simply be preserved. This is useful if you have timesets that
-
# can be conditionally set based on the target.
-
#
-
# # Target 1
-
# $soc.readout_timeset = ["readout", 120]
-
# # Target 2
-
# $soc.readout_timeset = false
-
#
-
# # This code is compatible with both targets, in the first case the timeset will switch
-
# # over, in the second case the existing timeset will be preserved.
-
# $tester.set_timeset($soc.readout_timeset) do
-
# $tester.cycle
-
# end
-
2
def set_timeset(timeset, period_in_ns = nil, &block)
-
271
OrigenTesters::Timing.set_timeset(timeset, period_in_ns, &block)
-
end
-
2
alias_method :with_timeset, :set_timeset
-
-
2
def timesets
-
9
OrigenTesters::Timing.timesets
-
end
-
-
2
def timeset?(t)
-
OrigenTesters::Timing.timeset?(t)
-
end
-
-
# Returns the timeset (a Timeset object) with the shortest period that has been
-
# encountered so far in the course of generating the current pattern.
-
#
-
# A tester object is re-instantiated at the start of every pattern which will reset
-
# this variable.
-
2
def min_period_timeset
-
27080
OrigenTesters::Timing.min_period_timeset
-
end
-
-
2
def before_timeset_change(options = {})
-
end
-
-
# Returns the current period in ns, or nil, if no timeset has been set.
-
2
def period_in_ns
-
OrigenTesters::Timing.period_in_ns
-
end
-
-
2
def period_in_secs
-
OrigenTesters::Timing.period_in_ns
-
end
-
2
alias_method :period_in_seconds, :period_in_secs
-
-
# Cause the pattern to wait.
-
# The following options are available to help you specify the time to wait:
-
# * :cycles - delays specified in raw cycles, the test model is responsible for translating this into a sequence of valid repeat statements
-
# * :time_in_ns - time specified in nano-seconds
-
# * :time_in_us - time specified in micro-seconds
-
# * :time_in_ms - time specified in milli-seconds
-
# * :time_in_s - time specified in seconds
-
# If more than one option is supplied they will get added together to give a final
-
# delay time expressed in cycles.
-
# ==== Examples
-
# $tester.wait(cycles: 100, time_in_ns: 200) # Wait for 100 cycles + 200ns
-
# This method can also be used to trigger a match loop in which case the supplied time
-
# becomes the time out for the match. See the J750#match method for full details of the
-
# available options.
-
# $tester.wait(match: true, state: :high, pin: $dut.pin(:done), time_in_ms: 500)
-
2
def wait(options = {})
-
options = {
-
171
cycles: 0,
-
time_in_cycles: 0,
-
time_in_us: 0,
-
time_in_ns: 0,
-
time_in_ms: 0,
-
time_in_s: 0,
-
match: false, # Set to true to invoke a match loop where the supplied delay
-
# will become the timeout duration
-
}.merge(options)
-
-
171
cycles = 0
-
171
cycles += options[:cycles] + options[:time_in_cycles]
-
171
cycles += s_to_cycles(options[:time_in_s])
-
171
cycles += ms_to_cycles(options[:time_in_ms])
-
171
cycles += us_to_cycles(options[:time_in_us])
-
171
cycles += ns_to_cycles(options[:time_in_ns])
-
-
171
time = cycles * current_period_in_ns # Total delay in ns
-
case
-
171
when time < 1000 # When less than 1us
-
cc "Wait for #{'a maximum of ' if options[:match]}#{time}ns"
-
when time < 1_000_000 # When less than 1ms
-
56
cc "Wait for #{'a maximum of ' if options[:match]}#{(time.to_f / 1000).round(1)}us" # Display delay in us
-
when time < 1_000_000_000 # When less than 1s
-
100
cc "Wait for #{'a maximum of ' if options[:match]}#{(time.to_f / 1_000_000).round(1)}ms"
-
else
-
15
cc "Wait for #{'a maximum of ' if options[:match]}%.2fs" % (time.to_f / 1_000_000_000)
-
end
-
-
171
if cycles > 0 # Allow this function to be called with 0 in which case it will just return
-
171
if options[:match]
-
53
if block_given?
-
52
match_block(cycles, options) { yield }
-
else
-
34
match(options[:pin], options[:state], cycles, options)
-
end
-
else
-
118
delay(cycles)
-
end
-
end
-
end
-
-
# @see Timing#wait
-
# @api private
-
# This should not be called directly, call via tester#wait
-
2
def delay(cycles, options = {})
-
1732
(cycles / max_repeat_loop).times do
-
531
if block_given?
-
283
yield options.merge(repeat: max_repeat_loop)
-
else
-
248
cycle(options.merge(repeat: max_repeat_loop))
-
end
-
end
-
1732
if block_given?
-
1607
yield options.merge(repeat: (cycles % max_repeat_loop))
-
else
-
125
cycle(options.merge(repeat: (cycles % max_repeat_loop)))
-
end
-
end
-
-
2
def max_repeat_loop
-
59417
@max_repeat_loop || 65_535
-
end
-
-
2
def min_repeat_loop
-
14183
@min_repeat_loop
-
end
-
-
# Returns any timesets that have been called during this execution.
-
# @return [Array] Array of OrigenTesters::Timing::Timeset objects that have been used so far.
-
2
def called_timesets
-
93
OrigenTesters::Timing.called_timesets
-
end
-
2
alias_method :called_timesets_by_instance, :called_timesets
-
-
# Similar to {#called_timesets}, but returns the name of the timesets instead.
-
# @return [Array] Array of names corresponding to the timesets that have been used so far.
-
2
def called_timesets_by_name
-
2
OrigenTesters::Timing.called_timesets_by_name
-
end
-
-
2
def current_period_in_ns
-
873
OrigenTesters::Timing.current_period_in_ns
-
end
-
2
alias_method :current_period, :current_period_in_ns
-
2
alias_method :period, :current_period_in_ns
-
-
2
def current_timeset
-
156477
OrigenTesters::Timing.current_timeset
-
end
-
2
alias_method :timeset, :current_timeset
-
-
# Convert the supplied number of cycles to a time, based on the SoC defined cycle period
-
2
def cycles_to_time(cycles) # :nodoc:
-
(cycles * current_period_in_ns).to_f / 1_000_000_000
-
end
-
-
# This function can be used to generate a clock or some other repeating function
-
# that spans accross a range of vectors.
-
# The period of each cycle and the duration of the sequence are supplied via the following
-
# options:
-
# * :period_in_cycles
-
# * :period_in_ns
-
# * :period_in_us
-
# * :period_in_ms
-
# * :duration_in_cycles
-
# * :duration_in_ns
-
# * :duration_in_us
-
# * :duration_in_ms
-
# If multiple definitions for either option are supplied then they will be added
-
# together.
-
# ==== Example
-
# # Supply a clock pulse on :pinA for 100ms
-
# $tester.count(:period_in_cycles => 10, :duration_in_ms => 100) do
-
# $top.pin(:pinA).drive!(1)
-
# $top.pin(:pinA).drive!(0)
-
# end
-
2
def count(options = {})
-
1
options = { period_in_cycles: 0, period_in_ms: 0, period_in_us: 0, period_in_ns: 0,
-
duration_in_cycles: 0, duration_in_ms: 0, duration_in_us: 0, duration_in_ns: 0
-
}.merge(options)
-
-
1
period_cycles = options[:period_in_cycles] + ms_to_cycles(options[:period_in_ms]) +
-
us_to_cycles(options[:period_in_us]) + ns_to_cycles(options[:period_in_ns])
-
-
1
duration_cycles = options[:duration_in_cycles] + ms_to_cycles(options[:duration_in_ms]) +
-
us_to_cycles(options[:duration_in_us]) + ns_to_cycles(options[:duration_in_ns])
-
-
1
total = 0
-
1
while total < duration_cycles
-
10
wait(time_in_cycles: period_cycles)
-
10
yield # Return control back to caller
-
10
total += period_cycles
-
end
-
end
-
-
2
private
-
-
2
def s_to_cycles(time) # :nodoc:
-
171
((time.to_f) * 1000 * 1000 * 1000 / current_period_in_ns).to_int
-
end
-
-
2
def ms_to_cycles(time) # :nodoc:
-
173
((time.to_f) * 1000 * 1000 / current_period_in_ns).to_int
-
end
-
-
2
def us_to_cycles(time) # :nodoc:
-
173
((time.to_f * 1000) / current_period_in_ns).to_int
-
end
-
-
2
def ns_to_cycles(time) # :nodoc:
-
173
(time.to_f / current_period_in_ns).to_int
-
end
-
-
2
def cycles_to_us(cycles) # :nodoc:
-
((cycles.to_f * current_period_in_ns) / (1000)).ceil
-
end
-
-
2
def cycles_to_ms(cycles) # :nodoc:
-
((cycles.to_f * current_period_in_ns) / (1000 * 1000)).ceil
-
end
-
-
# Cycles to tenths of a second
-
2
def cycles_to_ts(cycles) # :nodoc:
-
((cycles.to_f * current_period_in_ns) / (1000 * 1000 * 100)).ceil
-
end
-
end
-
end
-
end
-
2
module OrigenTesters
-
# A simple class to model a vector
-
2
class Vector
-
2
attr_accessor :repeat, :microcode, :timeset, :pin_vals,
-
:number, :cycle_number, :dont_compress,
-
:comments, :inline_comment, :cycle, :number, :contains_capture
-
-
2
def initialize(attrs = {})
-
102676
@inline_comment = ''
-
102676
attrs.each do |attribute, value|
-
513406
send("#{attribute}=", value)
-
end
-
end
-
-
2
def comments
-
68665
@comments ||= []
-
end
-
-
2
def update(attrs = {})
-
128
attrs.each do |attribute, value|
-
128
send("#{attribute}=", value)
-
end
-
end
-
-
# Returns the value (a string) that is assigned to the given pin by the
-
# given vector
-
#
-
# vector.pin_vals # => "1 1 XX10 H X1"
-
# vector.pin_value($dut.pins(:jtag)) # => "XX10"
-
2
def pin_value(pin)
-
72
$tester.regex_for_pin(pin).match(pin_vals)
-
72
Regexp.last_match(1)
-
end
-
-
# Replace the current pin value assigned to the given pin with either the state
-
# that it currently has, or with a supplied string value.
-
#
-
# In the case of a string being supplied as the 2nd argument, the caller is
-
# responsible for ensuring that the pin state format/codes matches that used
-
# by the current tester.
-
#
-
# vector.pin_vals # => "1 1 XX10 H X1"
-
# $dut.pins(:jtag).drive(0)
-
# vector.set_pin_value($dut.pins(:jtag))
-
# vector.pin_vals # => "1 1 0000 H X1"
-
# vector.set_pin_value($dut.pins(:jtag), "XXXX")
-
# vector.pin_vals # => "1 1 XXXX H X1"
-
2
def set_pin_value(pin, value = nil)
-
288
regex = $tester.regex_for_pin_sub(pin)
-
288
value ||= pin.to_vector
-
288
if $tester.ordered_pins_cache.first == pin
-
288
self.pin_vals = pin_vals.sub(regex, value + '\2')
-
elsif $tester.ordered_pins_cache.last == pin
-
self.pin_vals = pin_vals.sub(regex, '\1' + value)
-
else
-
self.pin_vals = pin_vals.sub(regex, '\1' + value + '\3')
-
end
-
end
-
-
# Converts the vector to the period specified by the given timeset (instead of the period
-
# for the timeset it was originally created with).
-
#
-
# This may convert the single vector to multiple vectors, in which case the method will
-
# yield as many vectors as required back to the caller.
-
2
def convert_to_timeset(tset)
-
# If no conversion required
-
27080
if tset.period_in_ns == timeset.period_in_ns
-
26828
yield self
-
else
-
252
if tset.period_in_ns > timeset.period_in_ns
-
fail "Cannot convert a vector with timeset #{timeset.name} to timeset #{tset.name}!"
-
end
-
252
if timeset.period_in_ns % tset.period_in_ns != 0
-
fail "The period of timeset #{timeset.name} is not a multiple of the period of timeset #{tset.name}!"
-
end
-
252
if contains_capture
-
48
vector_modification_required = true
-
204
elsif $tester.timing_toggled_pins.empty?
-
192
vector_modification_required = false
-
else
-
# If the timing toggled pins are not driving on this vector, then no
-
# modification will be required
-
12
vector_modification_required = $tester.timing_toggled_pins.any? do |pin|
-
12
value = pin_value(pin)
-
12
value == '1' || value == '0'
-
end
-
end
-
252
number_of_base_vectors = repeat || 1
-
252
vectors_per_period = timeset.period_in_ns / tset.period_in_ns
-
252
self.inline_comment += "Period levelled (#{timeset.name})"
-
252
self.timeset = tset
-
252
if vector_modification_required && vectors_per_period > 1
-
60
pin_values = $tester.timing_toggled_pins.map do |pin|
-
60
on = pin_value(pin)
-
60
if on == '1'
-
60
{ pin: pin, on: '1', off: '0' }
-
elsif on == '0'
-
{ pin: pin, on: '0', off: '1' }
-
end
-
end
-
60
pin_vals_with_compare = nil
-
60
number_of_base_vectors.times do |i|
-
# Drive the 'on' value on the first cycle, this is already setup
-
144
v = dup
-
144
v.repeat = 1
-
144
v.pin_vals = inhibit_compares
-
144
$tester.remove_store_from_vector(v) if v.contains_capture
-
144
yield v
-
# Then drive the pin 'off' value for the remainder
-
144
v = dup
-
144
r = vectors_per_period - 1
-
144
if r > 1
-
144
v = dup
-
144
v.repeat = r - 1
-
288
pin_values.each { |vals| v.set_pin_value(vals[:pin], vals[:off]) if vals }
-
144
$tester.remove_store_from_vector(v) if v.contains_capture
-
144
yield v
-
end
-
144
v = dup
-
144
v.repeat = 1
-
144
v.pin_vals = restore_compares
-
288
pin_values.each { |vals| v.set_pin_value(vals[:pin], vals[:off]) if vals }
-
144
yield v
-
end
-
else
-
192
self.repeat = number_of_base_vectors * vectors_per_period
-
192
yield self
-
end
-
end
-
end
-
-
# Set all active compare data to X.
-
# The original values will be preserved so that they can be restored
-
# vector.pin_vals # => "1 1 LHLL 10001 L 1 XX 0"
-
# vector.inhibit_compares # => "1 1 XXXX 10001 X 1 XX 0"
-
# vector.restore_compares # => "1 1 LHLL 10001 L 1 XX 0"
-
2
def inhibit_compares
-
144
@orig_pin_vals = pin_vals
-
144
@pin_vals = pin_vals.gsub(/H|L/, 'X')
-
end
-
-
# @see Vector#inhibit_compares
-
2
def restore_compares
-
144
@pin_vals = @orig_pin_vals
-
end
-
-
# Updates the pin values to reflect the value currently held by the given pin
-
2
def update_pin_val(pin)
-
72
vals = pin_vals.split(' ')
-
72
if pin.belongs_to_a_pin_group? && !pin.is_a?(Origen::Pins::PinCollection)
-
port = nil
-
pin.groups.each { |i| port = i[1] if port.nil? && Origen.tester.ordered_pins.include?(i[1]) } # see if group is included in ordered pins
-
if port
-
ix = Origen.tester.ordered_pins.index(port) # find index of port
-
i = port.index(pin)
-
else
-
ix = Origen.tester.ordered_pins.index(pin)
-
i = 0
-
end
-
else
-
72
ix = Origen.tester.ordered_pins.index(pin)
-
72
i = 0
-
end
-
-
72
if Origen.pin_bank.pin_groups.keys.include? pin.id
-
27
val = pin.map { |p| Origen.tester.format_pin_state(p) }.join('')
-
3
vals[ix] = val
-
else
-
69
val = Origen.tester.format_pin_state(pin)
-
69
vals[ix][i] = val
-
end
-
-
72
self.pin_vals = vals.join(' ')
-
end
-
-
2
def ordered_pins
-
Origen.app.pin_map.sort_by { |id, pin| pin.order }.map { |id, pin| pin }
-
end
-
-
2
def microcode=(val)
-
105105
if val && has_microcode? && @microcode != val
-
fail "Trying to assign microcode: #{val}, but vector already has microcode: #{@microcode}"
-
else
-
105105
@microcode = val
-
end
-
end
-
-
# Since repeat 0 is non-intuitive every vector implicitly has a repeat of 1
-
2
def repeat
-
388318
@repeat || 1
-
end
-
-
2
def has_microcode?
-
240559
!!(@microcode && !@microcode.empty?)
-
end
-
-
2
def ==(obj)
-
42427
if obj.is_a?(Vector)
-
42387
self.has_microcode? == obj.has_microcode? &&
-
timeset == obj.timeset &&
-
pin_vals == obj.pin_vals
-
else
-
40
super obj
-
end
-
end
-
end
-
end
-
2
require 'active_support/concern'
-
2
module OrigenTesters
-
# Including this module in a class gives it all the basics required
-
# to generator vector-based test patterns
-
2
module VectorBasedTester
-
2
extend ActiveSupport::Concern
-
-
2
require 'origen_testers/vector_generator'
-
2
require 'origen_testers/timing'
-
2
require 'origen_testers/api'
-
-
2
included do
-
8
include VectorGenerator
-
8
include Timing
-
8
include API
-
end
-
-
2
module ClassMethods # :nodoc:
-
# This overrides the new method of any class which includes this
-
# module to force the newly created instance to be registered as
-
# a tester with Origen
-
2
def new(*args, &block) # :nodoc:
-
687
if Origen.app.with_doc_tester?
-
x = OrigenTesters::Doc.allocate
-
if Origen.app.with_html_doc_tester?
-
x.html_mode = true
-
end
-
else
-
687
x = allocate
-
end
-
687
x.send(:initialize, *args, &block)
-
687
x.register_tester
-
687
x
-
end
-
end
-
-
2
def register_tester # :nodoc:
-
687
Origen.app.tester = self
-
end
-
end
-
end
-
2
require 'active_support/concern'
-
2
module OrigenTesters
-
2
module VectorGenerator
-
2
extend ActiveSupport::Concern
-
-
2
require 'erb'
-
2
require 'origen_testers/decompiler'
-
-
2
included do
-
# When set to true vector and cycle number comments will be appended to pattern vectors.
-
# This can also be enabled by running the generate command with the '-v' switch.
-
8
attr_accessor :vector_comments
-
8
attr_accessor :compress
-
8
attr_accessor :expand_repeats
-
end
-
-
2
def vector_group_size
-
35434
@vector_group_size || 1
-
end
-
-
2
def vector_group_size=(number)
-
717
if number > 1 && number.odd?
-
fail 'Only even numbers can be supplied for the vector_group_size!'
-
end
-
# Each pattern should run with its own tester instance, but just in case
-
717
@pipeline = nil
-
717
@vector_group_size = number
-
end
-
-
2
def with_vector_group_size(number)
-
orig = vector_group_size
-
self.vector_group_size = number
-
yield
-
self.vector_group_size = orig
-
end
-
-
# Duplicate the last vector as required until aligned with the start of the
-
# next vector group
-
2
def align
-
stage.store :align
-
end
-
2
alias_method :align_to_first, :align
-
-
# Duplicate the last vector as required until aligned to the last vector of the
-
# current vector group
-
2
def align_to_last
-
84
stage.store :align_last
-
end
-
-
# Returns an array of pin IDs that are currently inhibited (will not
-
# be included when vectors are generated)
-
2
def inhibited_pins
-
11347
@inhibited_pins ||= []
-
end
-
-
# init vector count when first accessed, otherwise return value
-
2
def vec_count
-
141
@vec_count ||= 0
-
end
-
-
# increment vector count
-
2
def inc_vec_count(num = 1)
-
51335
vec_count if @vec_count.nil? # define if not already
-
51335
@vec_count = @vec_count + num
-
end
-
-
# decrement vector count
-
2
def dec_vec_count(num = 1)
-
vec_count if @vec_count.nil? # define if not already
-
@vec_count = @vec_count - num
-
end
-
-
# Returns the current cycle count
-
2
def cycle_count
-
245
@cycle_count ||= 0
-
end
-
-
# Returns the current execution time
-
2
def execution_time_in_ns
-
141
@execution_time_in_ns ||= 0
-
end
-
-
# increment cycle count
-
2
def inc_cycle_count(num = 1, options = {})
-
51386
num, options = 1, num if num.is_a?(Hash)
-
51386
cycle_count if @cycle_count.nil? # define if not already
-
51386
execution_time_in_ns if @execution_time_in_ns.nil? # define if not already
-
51386
@execution_time_in_ns += num * (options[:period_in_ns] || tester.timeset.period_in_ns)
-
51386
@cycle_count = @cycle_count + num
-
end
-
-
# reset_cycle_count
-
2
def reset_cycle_count(num = 0)
-
cycle_count if @cycle_count.nil? # define if not already
-
@execution_time_in_ns = 0
-
@cycle_count = num
-
end
-
-
# Call to prevent the given pins from appearing in the generated vectors.
-
#
-
# This is a convenient way to inhibit something like a J750 mux pin from
-
# appearing in the patterns when generating the pattern for a different
-
# platform.
-
#
-
# When used this
-
# method must be called before the first vector is generated - it will not be retrospectively
-
# applied to existing vectors.
-
2
def inhibit_pin(*pins)
-
pins.each do |pin|
-
pin = $dut.pin(pin) if pin.is_a?(Symbol)
-
inhibited_pins << pin
-
end
-
inhibited_pins.uniq!
-
inhibited_pins.compact!
-
inhibited_pins
-
end
-
2
alias_method :inhibit_pins, :inhibit_pin
-
-
# Render content directly into a pattern, any options will be passed to the template
-
2
def render(template, options = {})
-
# Record the current file, this can be used to resolve any relative path
-
# references in the file about to be compiled
-
34
Origen.file_handler.current_file = template
-
# Ran into crosstalk problems when rendering ERB templates recursively, setting eoutvar based
-
# on the name of the file will causes each template to be rendered into its own 'bank'.
-
# Not sure why the final gsub is needed but seems to fail to parse correctly otherwise.
-
34
eoutvar = Pathname.new(template).basename('.*').basename('.*').to_s.gsub('-', '_')
-
# Make the file name available to the template
-
34
Origen.generator.compiler.options[:file] = template
-
68
options.each { |k, v| Origen.generator.compiler.options[k] = v }
-
34
code = Origen.generator.compiler.insert(ERB.new(File.read(template.to_s), 0, Origen.config.erb_trim_mode, eoutvar).result)
-
34
code.strip!
-
34
push_microcode code
-
end
-
-
# If the tester defines a method named template this method will compile
-
# whatever template file is returned by that method.
-
#
-
# This method is called automatically after the body section of a Pattern.create
-
# operation has completed.
-
2
def render_template
-
142
_render(:template)
-
end
-
-
# Same as the render method, except the template method should be called body_template.
-
2
def render_body
-
142
_render(:body_template)
-
end
-
-
# If the tester defines a method named footer_template this method will compile
-
# whatever template file is returned by that method.
-
#
-
# This method is called automatically during the footer section of a Pattern.create
-
# operation.
-
2
def render_footer
-
142
_render(:footer_template)
-
end
-
-
# If the tester defines a method named header_template this method will compile
-
# whatever template file is returned by that method.
-
#
-
# This method is called automatically during the header section of a Pattern.create
-
# operation.
-
2
def render_header
-
142
_render(:header_template)
-
end
-
-
2
def _render(method) # :nodoc:
-
568
if self.respond_to?(method)
-
template = send(method)
-
# Record the current file, this can be used to resolve any relative path
-
# references in the file about to be compiled
-
Origen.file_handler.current_file = template
-
# Ran into crosstalk problems when rendering ERB templates recursively, setting eoutvar based
-
# on the name of the file will causes each template to be rendered into its own 'bank'.
-
# Not sure why the final gsub is needed but seems to fail to parse correctly otherwise.
-
eoutvar = Pathname.new(template).basename('.*').basename('.*').to_s.gsub('-', '_')
-
# Make the file name available to the template
-
Origen.generator.compiler.options[:file] = template
-
push_microcode Origen.generator.compiler.insert(ERB.new(File.read(template.to_s), 0, Origen.config.erb_trim_mode, eoutvar).result)
-
end
-
end
-
-
2
def stage
-
63796
Origen.generator.stage
-
end
-
-
2
def push_comment(msg)
-
# Comments are stored verbatim for now, can't see much use for a dedicated comment object
-
7483
stage.store msg unless @inhibit_comments
-
end
-
-
2
def microcode(code, options = {})
-
1405
unless @inhibit_vectors
-
1389
if options[:offset] && options[:offset] != 0
-
3
stage.insert_from_end code, options[:offset]
-
else
-
1386
stage.store code
-
end
-
end
-
end
-
2
alias_method :push_microcode, :microcode
-
-
2
def last_vector(offset = 0)
-
583
stage.last_vector(offset)
-
end
-
-
2
def last_object(offset = 0)
-
46
stage.last_object(offset)
-
end
-
-
# Allows the attributes for the next vector to be setup prior
-
# to generating it.
-
#
-
# A block can be optionally supplied to act as a clean up method,
-
# that is the block will be saved and executed after the next
-
# cycle has been generated.
-
#
-
# See the V93K store_next_cycle method for an example of using
-
# this.
-
2
def preset_next_vector(attrs = {}, &block)
-
14
@preset_next_vector = attrs
-
14
@preset_next_vector_cleanup = block
-
end
-
-
# Called by every $tester.cycle command to push a vector to the stage object
-
2
def push_vector(attrs = {})
-
attrs = {
-
51760
dont_compress: @dont_compress
-
}.merge(attrs)
-
51760
unless @inhibit_vectors
-
51335
if @preset_next_vector
-
13
attrs = @preset_next_vector.merge(attrs) do |key, preset, current|
-
6
if preset && current && current != ''
-
fail "Value for #{key} set by preset_next_vector clashed with the next vector!"
-
else
-
6
preset || current
-
end
-
end
-
13
@preset_next_vector = nil
-
end
-
51335
v = Vector.new(attrs)
-
51335
stage.store Vector.new(attrs)
-
51335
inc_vec_count
-
51335
inc_cycle_count(attrs[:repeat] || 1, period_in_ns: v.timeset.period_in_ns)
-
51335
if @preset_next_vector_cleanup
-
13
@preset_next_vector_cleanup.call(v)
-
13
@preset_next_vector_cleanup = nil
-
end
-
end
-
end
-
2
alias_method :vector, :push_vector
-
-
2
def update_vector(attrs = {})
-
132
unless @inhibit_vectors
-
128
offset = (attrs.delete(:offset) || 0).abs
-
128
stage.last_vector(offset).update(attrs)
-
end
-
end
-
-
2
def update_vector_pin_val(pin, options = {})
-
75
unless @inhibit_vectors
-
72
offset = (options.delete(:offset) || 0).abs
-
72
stage.last_vector(offset).update_pin_val(pin)
-
end
-
end
-
-
# Adds the given microcode to the last vector if possible. If not possible (meaning the
-
# vector already contains microcode) then a new cycle will be added with the given
-
# microcode.
-
2
def add_microcode_to_last_or_cycle(code)
-
cycle if !stage.last_vector || stage.last_vector.has_microcode?
-
stage.last_vector.update(microcode: code)
-
end
-
-
# Final pass of a generator vector array which returns lines suitable for writing to the
-
# output file. This gives the tester model a chance to concatenate repeats and any other
-
# last optimization/formatting changes it wishes to make.
-
#
-
# At this point vector array contains a combination of non-vector lines and uncompressed
-
# Vector objects (vector lines)
-
#
-
2
def format(vector_array, section)
-
426
tester_writing_pattern = respond_to?(:open_and_write_pattern)
-
# Go through vector_array and print out both
-
# vectors and non-vectors to pattern (via 'yield line')
-
426
vector_array.each do |vec|
-
# skip here important for the ways delays are currently handled
-
# TODO: This seems like an upstream bug that should be investigated, why is such
-
# a vector even generated?
-
62778
if vec.is_a?(String)
-
11383
if vec.strip[0] == comment_char
-
1827
pipeline.push_comment(vec)
-
else
-
9556
pipeline.push_microcode(vec)
-
end
-
else
-
51395
next if vec.respond_to?(:repeat) && vec.repeat == 0 # skip vectors with repeat of 0!
-
51131
pipeline << vec
-
end
-
62514
pipeline.flush do |vector|
-
35837
expand_vector(vector) do |line|
-
35837
yield line unless tester_writing_pattern
-
end
-
end
-
end
-
# now flush buffer if there is still a vector
-
426
pipeline.empty(min_vectors: section == :footer ? @min_pattern_vectors : nil) do |vector|
-
7836
expand_vector(vector) do |line|
-
7836
yield line unless tester_writing_pattern
-
end
-
end
-
end
-
-
# Tester models can overwrite this if they wish to inject any additional pattern lines
-
# at final pattern dump time
-
2
def before_write_pattern_line(line)
-
[line]
-
end
-
-
2
def pipeline
-
125454
@pipeline ||= VectorPipeline.new(vector_group_size)
-
end
-
-
2
def dont_compress
-
286
if block_given?
-
orig = @dont_compress
-
@dont_compress = true
-
yield
-
@dont_compress = orig
-
else
-
286
@dont_compress
-
end
-
end
-
-
2
def dont_compress=(val)
-
287
@dont_compress = val
-
end
-
-
# expands (un-compresses to pattern) vector if desired or leaves it as is
-
# allows for tracking and formatting of vector
-
# if comment then return without modification
-
2
def expand_vector(vec)
-
43673
if vec.is_a?(Vector)
-
32280
if expand_repeats
-
vec.repeat.times do
-
vec.repeat = 1
-
yield track_and_format_vector(vec)
-
end
-
else
-
32280
yield track_and_format_vector(vec)
-
end
-
else
-
11393
yield track_and_format_comment(vec) # Return comments without modification
-
end
-
end
-
-
2
def track_and_format_comment(comment)
-
10505
comment
-
end
-
-
# Update tracking info (stats object) and allow for
-
# any additional formatting via format_vector
-
# method if overridden
-
2
def track_and_format_vector(vec)
-
32280
unless vec.timeset
-
puts 'No timeset defined!'
-
puts 'Add one to your top level startup method or target like this:'
-
puts '$tester.set_timeset("nvmbist", 40) # Where 40 is the period in ns'
-
exit 1
-
end
-
32280
stats = Origen.app.stats
-
32280
stats.add_vector
-
32280
if vector_group_size > 1 && vec.repeat > 1
-
1476
stats.add_cycle(1)
-
1476
stats.add_cycle((vec.repeat - 1) * vector_group_size)
-
1476
stats.add_time_in_ns(vec.timeset.period_in_ns)
-
1476
stats.add_time_in_ns((vec.repeat - 1) * vector_group_size * vec.timeset.period_in_ns)
-
else
-
30804
stats.add_cycle(vec.repeat)
-
30804
stats.add_time_in_ns(vec.repeat * vec.timeset.period_in_ns)
-
end
-
32280
format_vector(vec)
-
end
-
-
2
def format_vector(vec)
-
end
-
-
2
def pingroup_map
-
Origen.app.pingroup_map
-
end
-
-
# Cache any pin ordering for later use since all vectors should be formatted the same
-
2
def ordered_pins_cache(options = {})
-
52194
@ordered_pins_cache ||= ordered_pins(options)
-
end
-
-
# Retrieve optional 'name' meta passed in with the pin_pattern_order call
-
2
def ordered_pins_name
-
7000
pinorder = Origen.app.pin_pattern_order.dup
-
7000
if Origen.app.pin_pattern_order.last.is_a?(Hash)
-
options = pinorder.pop
-
name = options[:name]
-
end
-
7000
name
-
end
-
-
2
def ordered_pins(options = {})
-
options = {
-
1368
include_inhibited_pins: false,
-
include_pingroups: true
-
}.merge(options)
-
-
1368
result = nil
-
-
1368
Origen.profile 'Working out pin pattern order' do
-
1368
pinorder = Origen.app.pin_pattern_order.dup
-
1368
pinexclude = Origen.app.pin_pattern_exclude.dup
-
-
1368
if Origen.app.pin_pattern_order.last.is_a?(Hash)
-
options.merge!(pinorder.pop)
-
end
-
1368
if Origen.app.pin_pattern_exclude.last.is_a?(Hash)
-
options.merge!(pinexclude.pop)
-
end
-
-
1368
ordered_pins = []
-
-
# Create a copy of all pins and groups to be output, pins/groups will be delete from here as
-
# they are output, so that at the end of the user defined pin order what is left in here can
-
# either be discarded or output at the end
-
1368
pins = Origen.pin_bank.pins.dup
-
1368
pingroups = Origen.pin_bank.pin_groups.dup
-
-
1368
if pinorder && pinorder.size > 0
-
pinorder.each do |id|
-
# If the ID refers to a pin group
-
if group = Origen.pin_bank.pin_groups[id]
-
# If the group has still to be output just do that now
-
if pingroups.include? group.id
-
ordered_pins << group
-
# Now delete the group from the list of groups still to be output and all of its pins
-
# from the list pins still to be output
-
group.each do |pin|
-
pins.delete(pin.id)
-
pin.groups.each do |name, _group|
-
pingroups.delete(name)
-
end
-
end
-
pingroups.delete(group.id)
-
# To get here the some of the pins in the group have already been output which is preventing
-
# output of the complete group at this point, in that case output any of its pins that have
-
# still to go
-
else
-
group.each do |pin|
-
if pins.include? pin.id
-
ordered_pins << pin
-
pin.groups.each do |name, _group|
-
pingroups.delete(name)
-
end
-
end
-
end
-
end
-
# this is a pin
-
else
-
pin = Origen.pin_bank.find(id)
-
fail "Undefined pin (#{id}) added to pin_pattern_order" unless pin
-
ordered_pins << pin
-
pin.groups.each do |name, _group|
-
pingroups.delete(name)
-
end
-
pin.name = id
-
pins.delete(pin.id)
-
end
-
end
-
end
-
-
1368
if pinexclude && pinexclude.size > 0
-
pinexclude.each do |id|
-
if group = Origen.pin_bank.pin_groups[id]
-
# see if group is already in ordered_pins
-
fail "Pin group #{id} is defined both in pin_pattern_order and pin_pattern_exclude" unless pingroups.include? id
-
# this is a pin group, delete all pins in group
-
pingroups.delete(id)
-
group.each do |pin|
-
fail "Pin (#{pin.name}) in group (#{group.id}) is defined both in pin_pattern_order and pin_pattern_exclude" unless pins.include? pin.id
-
pins.delete(pin.id)
-
end
-
else # this is a pin, delete the pin
-
pin = Origen.pin_bank.find(id)
-
fail "Undefined pin (#{id}) added to pin_pattern_exclude" unless pin
-
fail "Pin #{pin.name} is defined both in pin_pattern_order and pin_pattern_exclude" unless pins.include? pin.id
-
pin.name = id
-
pins.delete(pin.id)
-
pin.groups.each do |name, _group|
-
pingroups.delete(name)
-
end
-
end
-
end
-
end
-
-
1368
unless options[:only]
-
# all the rest of the pins to the end of the pattern order
-
1368
pins.each do |_id, pin|
-
# check for port
-
11347
if pin.belongs_to_a_pin_group?
-
# Are any of this pin's groups still waiting to be output? pingroups at this point contains
-
# those groups which have not been rendered yet
-
1369
group = pingroups.find do |_id, group|
-
4020
pin.groups.any? { |_pid, pgroup| group == pgroup }
-
end
-
1369
if group
-
1369
ordered_pins << group[1]
-
11886
group[1].each { |pin| pins.delete(pin.id) }
-
else
-
ordered_pins << pin
-
end
-
else
-
9978
ordered_pins << pin
-
end
-
end
-
end
-
-
1368
result = ordered_pins.map do |pin|
-
11347
if options[:include_inhibited_pins]
-
pin
-
else
-
11347
inhibited_pins.include?(pin) ? nil : pin
-
end
-
end
-
1368
result = result.compact
-
end
-
1368
result
-
end
-
-
2
def current_pin_vals
-
51882
ordered_pins_cache.map(&:to_vector).join(' ')
-
end
-
-
# Returns a regular expression that can be used to get the value
-
# of the given pin within the string returned by current_pin_vals.
-
# str = $tester.current_pin_vals # => "1 1 XX10 H X1"
-
# regex = $tester.regex_for_pin($dut.pins(:jtag)) # => /\w{1} \w{1} (\w{4}) \w{1} \w{2}/
-
# regex.match(str)
-
# Regexp.last_match(1) # => "XX10"
-
#
-
# @see Vector#pin_value
-
2
def regex_for_pin(pin)
-
72
@regex_for_pins ||= {}
-
# Cache this as potentially called many times during pattern generation
-
72
@regex_for_pins[pin] ||= begin
-
12
regex = '/'
-
12
ordered_pins_cache.each do |p|
-
48
if pin == p
-
12
regex += "(\\w{#{p.size}}) "
-
else
-
36
regex += "\\w{#{p.size}} "
-
end
-
end
-
12
eval(regex.strip + '/')
-
end
-
end
-
-
# Returns a regular expression that can be used to change the value
-
# of the given pin within the string returned by current_pin_vals.
-
# str = $tester.current_pin_vals # => "1 1 XX10 H X1"
-
# regex = $tester.regex_for_pin_sub($dut.pins(:jtag)) # => /(\w{1} \w{1} )(\w{4})( \w{1} \w{2})/
-
# str.sub(regex, '\1LLLL\3') # => "1 1 LLLL H X1"
-
#
-
# @see Vector#set_pin_value
-
2
def regex_for_pin_sub(pin)
-
288
@regex_for_pin_subs ||= {}
-
# Cache this as potentially called many times during pattern generation
-
288
@regex_for_pin_subs[pin] ||= begin
-
12
regex = '/'
-
12
first_pin_done = false
-
12
match_pin_done = false
-
12
ordered_pins_cache.each do |p|
-
48
if pin == p
-
12
regex += ')' if first_pin_done
-
12
regex += "(\\w{#{p.size}})( "
-
else
-
36
regex += '(' unless first_pin_done
-
36
regex += "\\w{#{p.size}} "
-
end
-
48
first_pin_done = true
-
end
-
12
regex.strip!
-
12
if regex[-1] == '('
-
regex.chop!
-
else
-
12
regex += ')'
-
end
-
12
eval(regex + '/')
-
end
-
end
-
-
2
def get_pingroup(pin)
-
pingroup_map.each do |id, pins|
-
return id if pins.include? pin
-
end
-
nil
-
end
-
-
2
def update_pin_from_formatted_state(pin, state)
-
296
if state == @repeat_previous || state == '-'
-
26
pin.repeat_previous = true
-
270
elsif state == @drive_very_hi_state || state == '2'
-
8
pin.drive_very_hi
-
262
elsif state == @drive_hi_state || state == '1'
-
70
pin.drive_hi
-
192
elsif state == @drive_lo_state || state == '0'
-
98
pin.drive_lo
-
94
elsif state == @expect_hi_state || state == 'H'
-
24
pin.expect_hi
-
70
elsif state == @expect_lo_state || state == 'L'
-
15
pin.expect_lo
-
55
elsif state == @expect_mid_state || state == 'M'
-
pin.expect_mid
-
55
elsif state == @drive_mem_state || state == 'D'
-
9
pin.drive_mem
-
46
elsif state == @expect_mem_state || state == 'E'
-
9
pin.expect_mem
-
37
elsif state == @capture_state || state == 'C'
-
pin.capture
-
37
elsif state == @dont_care_state || state == 'X'
-
37
pin.dont_care
-
else
-
fail "Unknown pin state: #{state}"
-
end
-
end
-
-
# @see Origen::Pins::Pin#to_vector
-
2
def format_pin_state(pin)
-
80009
if pin.repeat_previous? && @support_repeat_previous
-
108
@repeat_previous || '-'
-
79901
elsif pin.driving?
-
68599
if pin.value == 1
-
22586
if pin.high_voltage?
-
56
@drive_very_hi_state || '2'
-
else
-
22530
@drive_hi_state || '1'
-
end
-
else
-
46013
@drive_lo_state || '0'
-
end
-
11302
elsif pin.comparing_midband?
-
@expect_mid_state || 'M'
-
11302
elsif pin.comparing?
-
484
if pin.value == 1
-
252
@expect_hi_state || 'H'
-
else
-
232
@expect_lo_state || 'L'
-
end
-
10818
elsif pin.driving_mem?
-
76
@drive_mem_state || 'D'
-
10742
elsif pin.comparing_mem?
-
57
@expect_mem_state || 'E'
-
10685
elsif pin.to_be_captured?
-
111
@capture_state || 'C'
-
else
-
10574
@dont_care_state || 'X'
-
end
-
end
-
-
# @api private
-
2
def remove_store_from_vector(vector)
-
96
vector.pin_vals.sub!('C', 'X')
-
end
-
end
-
end
-
# vector_pipeline concept explained [here](https://github.com/Origen-SDK/origen_testers/pull/101#issuecomment-424768720)
-
-
2
module OrigenTesters
-
2
class VectorPipeline
-
2
attr_reader :group_size, :pipeline
-
# Used to keep track of how many vectors since the last reset of the pipeline (i.e.
-
# since pattern start). This is used to implement padding if there is a minimum
-
# vector requirement.
-
2
attr_reader :vector_count
-
2
attr_reader :cycle_count
-
-
2
def initialize(group_size)
-
140
@group_size = group_size
-
140
@pipeline = []
-
# A new pipeline is instantiated per-pattern, so don't need to worry about
-
# clearing this
-
140
@vector_count = 0
-
140
@cycle_count = 0
-
end
-
-
2
def push_comment(comment)
-
1827
comments << comment
-
end
-
-
2
def push_microcode(code)
-
9556
if $tester.v93k? && $tester.smt_version == 7 && code =~ /JSUB/
-
12
@vector_count += 1
-
end
-
9556
comments << code
-
end
-
-
# Add a vector/comment to the pipeline
-
2
def <<(vector)
-
51131
if vector.is_a?(Vector)
-
51047
level_period(vector) do |vector|
-
51419
consume_comments(vector)
-
51419
if vector.repeat > 1
-
1288
add_repeat_vector(vector)
-
else
-
50131
pipeline << vector
-
end
-
end
-
# Keep a persistent record of the last vector so that we know what it
-
# was after the pipeline has been flushed
-
51047
@last_vector = pipeline.last
-
84
elsif vector.is_a?(Symbol)
-
84
case vector
-
when :align
-
duplicate_last_vector until aligned?
-
when :align_last
-
84
duplicate_last_vector until aligned_to_last?
-
else
-
fail "Uknown vector generator instruction: #{vector}"
-
end
-
else
-
comments << vector
-
end
-
end
-
-
# If there are complete groups sitting at the top of the pipeline
-
# then this will yield them back line by line, stopping after the last
-
# complete group and leaving any remaining single vectors in the pipeline
-
#
-
# If there are no complete groups present then it will just return
-
2
def flush(&block)
-
62514
while lead_group_finalized?
-
16752
lead_group.each do |vector|
-
26319
vector.comments.each do |comment|
-
4600
yield comment
-
end
-
26319
yield_vector(vector, &block)
-
26319
@cycle_count += pipeline[@group_size - 1].repeat
-
end
-
16752
pipeline.shift(group_size)
-
end
-
end
-
-
# Call at the end to force a flush out of any remaining vectors
-
2
def empty(options = {}, &block)
-
426
if !pipeline.empty? || !comments.empty?
-
409
if options[:min_vectors]
-
83
comment_written = false
-
83
while @vector_count < options[:min_vectors] - pipeline.size
-
562
unless comment_written
-
10
yield "#{$tester.comment_char} PADDING VECTORS ADDED TO MEET MIN #{options[:min_vectors]} FOR PATTERN"
-
10
comment_written = true
-
end
-
562
yield_vector(@last_vector, &block)
-
562
@cycle_count += @last_vector.repeat
-
end
-
end
-
-
83
duplicate_last_vector until aligned?
-
-
409
group_repeat_index = @group_size - 1
-
409
pipeline.each_index do |index|
-
375
vector = pipeline[index]
-
375
vector.comments.each do |comment|
-
251
yield comment
-
end
-
375
yield_vector(vector, &block)
-
375
if index % @group_size == 0 && index > 0
-
14
group_repeat_index += @group_size
-
end
-
375
@cycle_count += pipeline[group_repeat_index].repeat
-
end
-
-
409
comments.each do |comment|
-
6532
yield comment
-
end
-
409
@pipeline = []
-
409
@comments = []
-
end
-
end
-
-
2
private
-
-
2
def yield_vector(vector, &block)
-
27256
vector.cycle = @cycle_count
-
27256
vector.number = @vector_count
-
27256
r = vector.repeat || 1
-
27256
if $tester.min_repeat_loop && r < $tester.min_repeat_loop
-
21831
vector.repeat = 1
-
21831
if r > 1
-
1868
vector.comments << '#R' + r.to_s
-
end
-
21831
yield vector
-
21831
(r - 1).times do |index|
-
5024
vector.comments = ['#R' + (r - 1 - index).to_s]
-
5024
vector.number += 1
-
5024
vector.cycle += 1
-
5024
yield vector
-
end
-
21831
@vector_count += r
-
# @cycle_count now tracked in the calling methods (flush and empty)
-
else
-
5425
yield vector
-
5425
@vector_count += 1
-
# @cycle_count now tracked in the calling methods (flush and empty)
-
end
-
end
-
-
2
def level_period(vector)
-
51047
if $tester.level_period?
-
27080
vector.convert_to_timeset($tester.min_period_timeset) do |vector|
-
27452
yield vector
-
end
-
else
-
23967
yield vector
-
end
-
end
-
-
# Pushes a duplicate of the given vector with its repeat set to 1
-
#
-
# Also clears any comments associated with the vector with the rationale that we only
-
# want to see them the first time.
-
#
-
# Any microcode is cleared with the rationale that the caller is responsible for aligning
-
# this to the correct vector if required.
-
2
def push_duplicate(vector, options = {})
-
2171
v = vector.dup
-
2171
v.microcode = nil
-
2171
v.repeat = 1
-
2171
pipeline << v
-
2171
if options[:existing_vector]
-
3
v.comments = []
-
else
-
2168
vector.comments = []
-
end
-
end
-
-
2
def duplicate_last_vector
-
68
v = @last_vector.dup
-
68
v.comments = []
-
68
v.timeset = $tester.timeset
-
68
v.repeat = 1
-
68
v.microcode = nil
-
68
pipeline << v
-
end
-
-
2
def add_repeat_vector(vector)
-
1288
count = vector.repeat
-
# Align to the start of a new group by splitting off single vectors
-
# to complete the current group
-
1288
while !aligned? && count > 0
-
320
push_duplicate(vector)
-
320
count -= 1
-
end
-
1288
if count > group_size
-
1064
remainder = count % group_size
-
# Create a group with the required repeat
-
1064
group_size.times do
-
1496
push_duplicate(vector)
-
end
-
1064
pipeline.last.repeat = (count - remainder) / group_size
-
# Then expand out any leftover
-
1064
remainder.times do
-
112
push_duplicate(vector)
-
end
-
# For small repeats that fit within the group just expand them
-
else
-
while count > 0
-
240
push_duplicate(vector)
-
240
count -= 1
-
end
-
end
-
end
-
-
# Returns true of the next vector to be added to the pipeline will
-
# be at the start of a new group
-
2
def aligned?
-
2061
(pipeline.size % group_size) == 0
-
end
-
-
# Returns true if the next vector to be added to the pipeline will
-
# complete the current group
-
2
def aligned_to_last?
-
108
(pipeline.size % group_size) == (group_size - 1)
-
end
-
-
2
def consume_comments(vector)
-
51419
vector.comments = comments
-
51419
@comments = []
-
end
-
-
2
def comments
-
63400
@comments ||= []
-
end
-
-
# When true the lead group is complete and a further repeat of it is not possible
-
# Calling this will compress the 2nd group into the 1st if possible
-
2
def lead_group_finalized?
-
79266
if first_group_present? && second_group_present?
-
35125
if second_group_is_duplicate_of_first_group? && first_group_repeat != $tester.max_repeat_loop &&
-
first_group_can_be_compressed?
-
# Consume the second group by incrementing the first group repeat counter
-
18418
self.first_group_repeat = first_group_repeat + second_group_repeat
-
# Delete the second group
-
44094
group_size.times { pipeline.delete_at(group_size) }
-
-
# Now deal with any overflow of the first group repeat counter
-
18418
if first_group_repeat > $tester.max_repeat_loop
-
3
r = first_group_repeat - $tester.max_repeat_loop
-
3
self.first_group_repeat = $tester.max_repeat_loop
-
6
group_size.times { |i| push_duplicate(pipeline[i], existing_vector: true) }
-
3
self.second_group_repeat = r
-
3
true
-
18415
elsif first_group_repeat == $tester.max_repeat_loop
-
42
true
-
else
-
18373
false
-
end
-
else
-
# Second group has started and is already different from the first group
-
16707
true
-
end
-
end
-
end
-
-
2
def first_group_repeat
-
# This is currently hardcoded to the Teradyne concept of the repeat being applied
-
# to the last vector in the group. May need an abstraction here if other ATEs don't
-
# adhere to that approach.
-
73837
first_group.last.repeat || 1
-
end
-
-
2
def first_group_repeat=(val)
-
18421
first_group.last.repeat = val
-
end
-
-
2
def second_group_repeat
-
18418
second_group.last.repeat || 1
-
end
-
-
2
def second_group_repeat=(val)
-
3
second_group.last.repeat = val
-
end
-
-
2
def first_group_can_be_compressed?
-
18428
first_group.all? do |vector|
-
25686
!vector.dont_compress
-
end
-
end
-
-
2
def second_group_is_duplicate_of_first_group?
-
35125
i = -1
-
35125
second_group.all? do |vector|
-
42387
i += 1
-
42387
(pipeline[i] == vector) && (vector.comments.size == 0) &&
-
# Don't consider vectors with matching microcode duplicates, caller is
-
# responsible for laying out microcode with the correct alignment
-
!pipeline[i].has_microcode? && !vector.has_microcode? &&
-
!vector.dont_compress
-
end
-
end
-
-
2
def first_group_present?
-
79266
lead_group.size == group_size
-
end
-
-
2
def second_group_present?
-
72834
second_group.size == group_size
-
end
-
-
2
def lead_group
-
206704
pipeline[0..group_size - 1]
-
end
-
2
alias_method :first_group, :lead_group
-
-
2
def second_group
-
126380
pipeline[group_size..(group_size * 2) - 1]
-
end
-
end
-
end