origen_testers 0.46.1 → 0.48.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,120 @@
1
+ module OrigenTesters
2
+ module Charz
3
+ # A Charz Profile
4
+ # Used to store characterization routines as well as flow control, conditional execution, and test placement meta data
5
+ class Profile
6
+ # @!attribute id
7
+ # @return [Symbol] the id of the current profile, used as a key in OrigenTesters::Charz#charz_profiles hash
8
+ # @!attribute name
9
+ # @return [Symbol] the value used (if the user decides) to generate the name of the created charz test. defaults to the value of @id
10
+ # @!attribute placement
11
+ # @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
12
+ # @!attribute on_result
13
+ # @return [Symbol] indicates if the resulting charz tests are depending on the point tests result, valid values include :on_fail, and :on_pass
14
+ # @!attribute enables
15
+ # @return [Symbol, String, Array, Hash] enable gates to be wrapped around the resulting charz tests
16
+ # @!attribute flags
17
+ # @return [Symbol, String, Array, Hash] flag gates to be wrapped around the resulting charz tests
18
+ # @!attribute routines
19
+ # @return [Array] list of charz routines to be called under this profile
20
+ # @!attribute charz_only
21
+ # @return [Boolean] indicates if the point tests should or shouldn't be added to the flow
22
+ attr_accessor :id, :name, :placement, :on_result, :enables, :flags, :routines, :charz_only
23
+
24
+ def initialize(id, options, &block)
25
+ @id = id
26
+ @id = @id.symbolize unless id.is_a? Symbol
27
+ options.each { |k, v| instance_variable_set("@#{k}", v) }
28
+ (block.arity < 1 ? (instance_eval(&block)) : block.call(self)) if block_given?
29
+ @name ||= id
30
+ @placement ||= :inline
31
+ @defined_routines = options.delete(:defined_routines)
32
+ attrs_ok?
33
+ end
34
+
35
+ def attrs_ok?
36
+ return if @quality_check == false
37
+
38
+ unknown_routines = @routines - @defined_routines
39
+ unless unknown_routines.empty?
40
+ Origen.log.error "Profile #{id}: unknown routines: #{unknown_routines}"
41
+ fail
42
+ end
43
+
44
+ @valid_placements ||= [:inline, :eof]
45
+ unless @valid_placements.include? @placement
46
+ Origen.log.error "Profile #{id}: invalid placement value, must be one of: #{@valid_placements}"
47
+ fail
48
+ end
49
+
50
+ if @on_result
51
+ @valid_on_results ||= [:on_fail, :fail, :failed, :on_pass, :pass, :passed]
52
+ unless @valid_on_results.include?(@on_result)
53
+ Origen.log.error "Profile #{id}: invalid on_result value, must be one of: #{@valid_on_results}"
54
+ fail
55
+ end
56
+ end
57
+
58
+ if @charz_only && @on_result
59
+ Origen.log.error "Profile #{id}: @charz_only is set, but @on_result (#{@on_result}) requires the parent test to exist in the flow"
60
+ fail
61
+ end
62
+
63
+ unless @gate_checks == false
64
+ gate_check(@enables, :enables) if @enables
65
+ gate_check(@flags, :flags) if @flags
66
+ end
67
+ end
68
+
69
+ def gate_check(gates, gate_type)
70
+ case gates
71
+ when Symbol, String
72
+ return
73
+ when Array
74
+ unknown_gates = gates.reject { |gate| [String, Symbol].include? gate.class }
75
+ if unknown_gates.empty?
76
+ return
77
+ else
78
+ Origen.log.error "Profile #{id}: Unknown #{gate_type} type(s) in #{gate_type} array."
79
+ Origen.log.error "Arrays must contain Strings and/or Symbols, but #{unknown_gates.map(&:class).uniq } were found in #{gates}"
80
+ fail
81
+ end
82
+ when Hash
83
+ gates.each do |gate, gated_routines|
84
+ if gate.is_a? Hash
85
+ Origen.log.error "Profile #{id}: #{gate_type} Hash keys cannot be of type Hash, but only Symbol, String, or Array"
86
+ fail
87
+ end
88
+ gate_check(gate, gate_type)
89
+ gated_routines = [gated_routines] unless gated_routines.is_a? Array
90
+ unknown_routines = gated_routines - @defined_routines
91
+ unless unknown_routines.empty?
92
+ Origen.log.error "Profile #{id}: unknown routines found in @#{gate_type}[#{gate.is_a?(Symbol) ? ':' : ''}#{gate}]: #{unknown_routines}"
93
+ fail
94
+ end
95
+ end
96
+ else
97
+ Origen.log.error "Profile #{id}: Unknown #{gate_type} type: #{gates.class}. #{gate_type} must be of type Symbol, String, Array, or Hash"
98
+ fail
99
+ end
100
+ end
101
+
102
+ def method_missing(m, *args, &block)
103
+ ivar = "@#{m.to_s.gsub('=', '')}"
104
+ ivar_sym = ":#{ivar}"
105
+ if m.to_s =~ /=$/
106
+ define_singleton_method(m) do |val|
107
+ instance_variable_set(ivar, val)
108
+ end
109
+ elsif instance_variables.include? ivar_sym
110
+ instance_variable_get(ivar)
111
+ else
112
+ define_singleton_method(m) do
113
+ instance_variable_get(ivar)
114
+ end
115
+ end
116
+ send(m, *args, &block)
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,38 @@
1
+ module OrigenTesters
2
+ module Charz
3
+ # A Generic charz routine
4
+ # Used to store characterization test specific meta data, values of which are used by the user to determine test parameter values
5
+ class Routine
6
+ # @!attribute id
7
+ # @return [Symbol] charz routine symbol, used as a key in OrigenTesters::Charz#charz_routines
8
+ # @!attribute name
9
+ # @return [Symbol] the value used (if the user decides) to generate the name of the created charz test. defaults to the value of @id
10
+ attr_accessor :id, :name
11
+
12
+ def initialize(id, options = {}, &block)
13
+ @id = id
14
+ @id = @id.symbolize unless id.is_a? Symbol
15
+ options.each { |k, v| instance_variable_set("@#{k}", v) }
16
+ (block.arity < 1 ? (instance_eval(&block)) : block.call(self)) if block_given?
17
+ @name ||= @id
18
+ end
19
+
20
+ def method_missing(m, *args, &block)
21
+ ivar = "@#{m.to_s.gsub('=', '')}"
22
+ ivar_sym = ":#{ivar}"
23
+ if m.to_s =~ /=$/
24
+ define_singleton_method(m) do |val|
25
+ instance_variable_set(ivar, val)
26
+ end
27
+ elsif instance_variables.include? ivar_sym
28
+ instance_variable_get(ivar)
29
+ else
30
+ define_singleton_method(m) do
31
+ instance_variable_get(ivar)
32
+ end
33
+ end
34
+ send(m, *args, &block)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,42 @@
1
+ module OrigenTesters
2
+ module Charz
3
+ # a 1D search routine
4
+ class SearchRoutine < Routine
5
+ # @!attribute start
6
+ # @return [Numeric] search start value
7
+ # @!attribute stop
8
+ # @return [Numeric] search stop value
9
+ # @!attribute res
10
+ # @return [Numeric] search resolution
11
+ # @!attribute spec
12
+ # @return [Numeric] spec parameter to be searched
13
+ attr_accessor :start, :stop, :res, :spec
14
+
15
+ # Runs the same initialization as Routine
16
+ # performs some rudimentary quality checks, which can be disabled by setting @quality_check = false
17
+ def initialize(id, options = {}, &block)
18
+ super
19
+ attrs_ok?
20
+ end
21
+
22
+ def attrs_ok?
23
+ return if @quality_check == false
24
+
25
+ @required_attrs ||= [:start, :stop, :res, :spec]
26
+ attrs = @required_attrs.map { |attr| instance_variable_get("@#{attr}") }
27
+ if attrs.compact.size != @required_attrs.size
28
+ Origen.log.error "SearchRoutine #{@id}: unspecified attributes, each of #{@required_attrs} must have a value"
29
+ fail
30
+ end
31
+
32
+ return if @attr_value_check == false
33
+ if [@start, @stop, @res].all? { |attr| attr.is_a? Numeric }
34
+ unless @res <= (@start - @stop).abs
35
+ Origen.log.error "SearchRoutine #{@id}: Search resolution (#{@res}) is larger than the search range: #{(@start - @stop).abs}"
36
+ fail
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,62 @@
1
+ module OrigenTesters
2
+ module Charz
3
+ # A 2D search or "Shmoo" routine
4
+ class ShmooRoutine < Routine
5
+ # @!attribute x_start
6
+ # @return [Numeric] the starting search value for the x dimension's spec search
7
+ # @!attribute x_stop
8
+ # @return [Numeric] the stopping search value for the x dimension's spec search
9
+ # @!attribute x_res
10
+ # @return the search resolution value for the x dimension's spec search
11
+ # @!attribute x_spec
12
+ # @return [Symbol, String] the spec parameter of interest for the x dimension
13
+ attr_accessor :x_start, :x_stop, :x_res, :x_spec
14
+ # @!attribute y_start
15
+ # @return [Numeric] the starting search value for the x dimension's spec search
16
+ # @!attribute y_stop
17
+ # @return [Numeric] the stopping search value for the x dimension's spec search
18
+ # @!attribute y_res
19
+ # @return the search resolution value for the x dimension's spec search
20
+ # @!attribute y_spec
21
+ # @return [Symbol, String] the spec parameter of interest for the x dimension
22
+ attr_accessor :y_start, :y_stop, :y_res, :y_spec
23
+
24
+ def initialize(id, options = {}, &block)
25
+ super
26
+ attrs_ok?
27
+ end
28
+
29
+ def attrs_ok?
30
+ return if @quality_check == false
31
+
32
+ @required_attrs ||= [:x_start, :x_stop, :x_res, :x_spec, :y_start, :y_stop, :y_res, :y_spec]
33
+ attrs = @required_attrs.map { |attr| instance_variable_get("@#{attr}") }
34
+ if attrs.compact.size != @required_attrs.size
35
+ Origen.log.error "ShmooRoutine #{@id}: unspecified attributes, each of #{@required_attrs} must have a value"
36
+ fail
37
+ end
38
+
39
+ return if @attr_value_check == false
40
+
41
+ # not sure if I want this check, if so need to scope out if step count is common
42
+
43
+ # if [@x_start, @x_stop, @x_res].all? { |attr| attr.is_a? Numeric }
44
+ # unless @x_res <= (@x_start - @x_stop).abs
45
+ # Origen.log.error "ShmooRoutine #{@id}: Search x_resolution (#{@x_res} is larger than the search x_range (#{@x_start - @x_stop).abs})"
46
+ # fail
47
+ # end
48
+ # end
49
+ # if [@y_start, @y_stop, @y_res].all? { |attr| attr.is_a? Numeric }
50
+ # unless @y_res <= (@y_start - @y_stop).abs
51
+ # Origen.log.error "ShmooRoutine #{@id}: Search y_resolution (#{@y_res} is larger than the search y_range (#{@y_start - @y_stop).abs})"
52
+ # fail
53
+ # end
54
+ # end
55
+ unless @x_spec != @y_spec
56
+ Origen.log.error "ShmooRoutine #{@id}: Search x_spec is identical to y_spec"
57
+ fail
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,100 @@
1
+ module OrigenTesters
2
+ module Charz
3
+ # A charz session
4
+ # contains the final combination of charz object (routines/profiles) and user options to determine how and what charz tests should be created
5
+ # the session should be checked in your interface to determine the current status and can be queried to make charz generation decisions
6
+ class Session < Profile
7
+ # @!attribute defaults
8
+ # @return [Hash] list of values to instantiate the inherited attributes from Profile with if not altered by the session update
9
+ attr_accessor :defaults
10
+
11
+ def initialize(options = {})
12
+ @id = :current_charz_session
13
+ @active = false
14
+ @valid = false
15
+ if options[:defaults]
16
+ @defaults = options[:defaults]
17
+ else
18
+ @defaults = {
19
+ placement: :inline,
20
+ on_result: nil,
21
+ enables: nil,
22
+ flags: nil,
23
+ name: 'charz',
24
+ charz_only: false
25
+ }
26
+ end
27
+ end
28
+
29
+ # Pauses the current session's activity while maintaining everthing else about the sessions state
30
+ def pause
31
+ @active = false
32
+ end
33
+
34
+ # Resume activity, if the session is valid
35
+ def resume
36
+ if @valid
37
+ @active = true
38
+ end
39
+ end
40
+
41
+ # Takes a Routine or Profile, and queries it to setup the session's attributes
42
+ # the attributes values can be set from 3 different sources, in order of priority (first is most important):
43
+ # - options
44
+ # - charz object
45
+ # - defaults
46
+ #
47
+ # If the resulting session is invalid, @valid will turn false. Otherwise, the session becomes active
48
+ def update(charz_obj, options)
49
+ @valid = false
50
+ if charz_obj.nil?
51
+ @active = false
52
+ @valid = false
53
+ return @valid
54
+ end
55
+ @defined_routines = options.delete(:defined_routines)
56
+ assign_by_priority(:placement, charz_obj, options)
57
+ assign_by_priority(:on_result, charz_obj, options)
58
+ assign_by_priority(:enables, charz_obj, options)
59
+ assign_by_priority(:flags, charz_obj, options)
60
+ assign_by_priority(:routines, charz_obj, options)
61
+ assign_by_priority(:name, charz_obj, options)
62
+ assign_by_priority(:charz_only, charz_obj, options)
63
+ attrs_ok?
64
+ massage_gates
65
+ @active = true
66
+ @valid = true
67
+ end
68
+
69
+ private
70
+
71
+ # convert hash gates to set convert their routines to type array if not already
72
+ def massage_gates
73
+ if @enables.is_a?(Hash)
74
+ @enables = {}.tap do |new_h|
75
+ @enables.each { |gates, routines| new_h[gates] = [routines].flatten }
76
+ end
77
+ end
78
+ if @flags.is_a?(Hash)
79
+ @flags = {}.tap do |new_h|
80
+ @flags.each { |gates, routines| new_h[gates] = [routines].flatten }
81
+ end
82
+ end
83
+ end
84
+
85
+ # see initialize
86
+ def assign_by_priority(ivar, charz_obj, options)
87
+ if options.keys.include?(ivar)
88
+ instance_variable_set("@#{ivar}", options[ivar])
89
+ elsif charz_obj.send(ivar)
90
+ instance_variable_set("@#{ivar}", charz_obj.send(ivar))
91
+ elsif @defaults.keys.include?(ivar)
92
+ instance_variable_set("@#{ivar}", @defaults[ivar])
93
+ else
94
+ Origen.log.error "Charz Session: No value could be determined for #{ivar}"
95
+ fail
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -430,7 +430,8 @@ module OrigenTesters
430
430
  end
431
431
 
432
432
  def clean_flag(flag)
433
- flag = flag.to_s
433
+ # Added .dup to below line to get an unfrozen copy of the string, corrects a run time error
434
+ flag = flag.to_s.dup
434
435
  if flag[0] == '$'
435
436
  flag[0] = ''
436
437
  end
@@ -10,14 +10,20 @@ module OrigenTesters
10
10
  def on_test(node)
11
11
  super
12
12
  ins = node.find(:object).value
13
- if ins.respond_to?(:lo_limit) && (ins.lo_limit || ins.hi_limit) || ins.respond_to?(:lo) && (ins.lo || ins.hi)
13
+
14
+ # allow defer limits when limits are only given in sub tests
15
+ if ins.respond_to?(:defer_limits)
14
16
  if ins.defer_limits
15
17
  completed_lines.last.opcode = 'Test-defer-limits'
16
18
  end
19
+ end
20
+
21
+ if ins.respond_to?(:lo_limit) && (ins.lo_limit || ins.hi_limit) || ins.respond_to?(:lo) && (ins.lo || ins.hi)
17
22
  limit = completed_lines.last.dup
18
23
  limit.type = :use_limit
19
24
  limit.opcode = 'Use-Limit'
20
25
  limit.parameter = nil
26
+ limit.tnum = nil # Don't duplate test numbers, allow auto-increment by leaving blank
21
27
  if ins.respond_to?(:lo_limit)
22
28
  lo = ins.lo_limit
23
29
  hi = ins.hi_limit
@@ -36,7 +36,7 @@ module OrigenTesters
36
36
  unless options[:subroutine_pat]
37
37
  stage.with_bank(:body) do
38
38
  # find the first vector
39
- stage.bank.delete_at(0) until stage.bank[0].is_a?(OrigenTesters::Vector)
39
+ stage.bank.delete_at(0) until stage.bank[0].is_a?(OrigenTesters::Vector) || stage.bank.empty?
40
40
  end
41
41
  end
42
42
  end
@@ -138,6 +138,7 @@ module Origen
138
138
  end
139
139
  Origen.interface.startup(options) if Origen.interface.respond_to?(:startup)
140
140
  interface.instance_eval(&block)
141
+ Origen.interface.generate_eof_charz_tests if Origen.interface.respond_to?(:generate_eof_charz_tests)
141
142
  Origen.interface.shutdown(options) if Origen.interface.respond_to?(:shutdown)
142
143
  interface.at_flow_end if interface.respond_to?(:at_flow_end)
143
144
  Origen.app.listeners_for(:on_flow_end).each do |listener|
@@ -119,6 +119,7 @@ module OrigenTesters
119
119
  o[:test_name] = extract_test_name(node, o)
120
120
  o[:test_number] = extract_test_number(node, o)
121
121
  o[:limits] = extract_limits(node, o)
122
+ o[:test_text] = node.find(:test_text).try(:value)
122
123
  if on_fail = node.find(:on_fail)
123
124
  if set_result = on_fail.find(:set_result)
124
125
  if bin = set_result.find(:bin)
@@ -252,9 +253,12 @@ module OrigenTesters
252
253
  # "Test Number"
253
254
  l << f(options[:test_number])
254
255
  # "Test Text"
255
- # l << f(options[:bin_s_name] || options[:bin_h_name])
256
- names = ["#{options[:suite_name]}", "#{options[:test_name]}"]
257
- l << f(names.uniq.join('.'))
256
+ if options[:test_text]
257
+ l << f(options[:test_text])
258
+ else
259
+ names = ["#{options[:suite_name]}", "#{options[:test_name]}"]
260
+ l << f(names.uniq.join('.'))
261
+ end
258
262
  if test_modes.empty?
259
263
  # "Low Limit"
260
264
  l << f((options[:limits][nil] || {})[:lsl])
@@ -35,21 +35,25 @@ module OrigenTesters
35
35
 
36
36
  # What SMT7 calls a flag
37
37
  def flags
38
- (variables[:all][:referenced_enables] + variables[:all][:set_enables]).uniq.sort do |x, y|
39
- x = x[0] if x.is_a?(Array)
40
- y = y[0] if y.is_a?(Array)
41
- # Need to use strings for the comparison as some flags can be a string and some a symbol
42
- x.to_s <=> y.to_s
38
+ if variables
39
+ (variables[:all][:referenced_enables] + variables[:all][:set_enables]).uniq.sort do |x, y|
40
+ x = x[0] if x.is_a?(Array)
41
+ y = y[0] if y.is_a?(Array)
42
+ # Need to use strings for the comparison as some flags can be a string and some a symbol
43
+ x.to_s <=> y.to_s
44
+ end
43
45
  end
44
46
  end
45
47
 
46
48
  # What SMT7 calls a declaration
47
49
  def declarations
48
- (variables[:all][:jobs] + variables[:all][:referenced_flags] + variables[:all][:set_flags]).uniq.sort do |x, y|
49
- x = x[0] if x.is_a?(Array)
50
- y = y[0] if y.is_a?(Array)
51
- # Need to use strings for the comparison as some declarations can be a string and some a symbol
52
- x.to_s <=> y.to_s
50
+ if variables
51
+ (variables[:all][:jobs] + variables[:all][:referenced_flags] + variables[:all][:set_flags]).uniq.sort do |x, y|
52
+ x = x[0] if x.is_a?(Array)
53
+ y = y[0] if y.is_a?(Array)
54
+ # Need to use strings for the comparison as some declarations can be a string and some a symbol
55
+ x.to_s <=> y.to_s
56
+ end
53
57
  end
54
58
  end
55
59