origen_testers 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ed6eed4f43211577112670d75be50cd8c5af22d1
4
- data.tar.gz: 44239f70ea1b03d86784cfbaf0dffd91694b0535
3
+ metadata.gz: 112e2af4457169ff2ba79641610c0722d565f1fb
4
+ data.tar.gz: 8833d9bcc8538cb5e5a32f934222e90360957d0d
5
5
  SHA512:
6
- metadata.gz: b1dbc83b631cc269e949a36a9473cfc0935601478adacf5216293db841fc7fce6fdafe88125db77c3ba0d897237858e3aee651d9167b987f0f35f35d0c8535b3
7
- data.tar.gz: 2c2f1b09187a88366d9169d531a41465a997e09c321858babf28c5f2f20dc4eead6665fb946f6de91d630ad79693b753a189c01b89fc115b4dc57490c3ca54b8
6
+ metadata.gz: c28c0d2cba87e54110b23a77a7f4cf4eb6adc54f93daca4531a9168e98bd0915481d1bc7d4eefae082fbdfb648c7bb31f93a4e8dc7f2b12abcc164ede3b2b039
7
+ data.tar.gz: ca63134cf7ac29bb74ece0bd9487251ad16ba4b59c6901ebc34288f471591138ad72a433d84d7490586daaee38722189b9d1b088d780b611164cde7aff7758df
data/config/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module OrigenTesters
2
2
  MAJOR = 0
3
- MINOR = 12
3
+ MINOR = 13
4
4
  BUGFIX = 0
5
5
  DEV = nil
6
6
 
@@ -130,13 +130,13 @@ module OrigenTesters
130
130
  end
131
131
 
132
132
  # @api private
133
- # This fires between target loads
133
+ # This fires between target loads (unless overridden by the ATE specific flow class)
134
134
  def at_run_start
135
135
  @@program = nil
136
136
  end
137
137
 
138
138
  # @api private
139
- # This fires between flows
139
+ # This fires between flows (unless overridden by the ATE specific flow class)
140
140
  def at_flow_start
141
141
  @labels = {}
142
142
  end
@@ -36,6 +36,7 @@ module OrigenTesters
36
36
  end
37
37
 
38
38
  def at_flow_start
39
+ model # Call to ensure the signature gets populated
39
40
  end
40
41
 
41
42
  def at_flow_end
@@ -45,7 +46,7 @@ module OrigenTesters
45
46
  h = ['{']
46
47
  if add_flow_enable
47
48
  var = filename.sub(/\..*/, '').upcase
48
- var = "#{var}_ENABLE"
49
+ var = generate_flag_name("#{var}_ENABLE")
49
50
  if add_flow_enable == :enabled
50
51
  flow_control_variables << [var, 1]
51
52
  else
@@ -84,9 +85,11 @@ module OrigenTesters
84
85
  @indent = add_flow_enable ? 2 : 1
85
86
  @lines = []
86
87
  @stack = { on_fail: [], on_pass: [] }
87
- m = Processors::IfRanCleaner.new.process(model.ast)
88
+ m = Processors::ContinueImplementer.new.process(model.ast)
89
+ m = Processors::IfRanCleaner.new.process(m)
90
+ m = Processors::FlagOptimizer.new.run(m)
91
+ m = Processors::AdjacentIfCombiner.new.process(m)
88
92
  m = Processors::EmptyBranchCleaner.new.process(m)
89
- m = Processors::FlagOptimizer.new.process(m)
90
93
  @set_runtime_variables = Processors::ExtractSetVariables.new.run(m)
91
94
  process(m)
92
95
  end
@@ -122,10 +125,8 @@ module OrigenTesters
122
125
  line '{'
123
126
  @indent += 1
124
127
  on_fail = node.children.find { |n| n.try(:type) == :on_fail }
125
- with_continue(on_fail ? on_fail.children.any? { |n| n.try(:type) == :continue } : false) do
126
- process_all(on_fail) if on_fail
127
- stack[:on_fail].each { |n| process_all(n) }
128
- end
128
+ process_all(on_fail) if on_fail
129
+ stack[:on_fail].each { |n| process_all(n) }
129
130
  @indent -= 1
130
131
  line '}'
131
132
  else
@@ -160,6 +161,8 @@ module OrigenTesters
160
161
 
161
162
  def on_condition_flag(node)
162
163
  flag, state, *nodes = *node
164
+ flag_true = node.find(:flag_true)
165
+ flag_false = node.find(:flag_false)
163
166
  if flag.is_a?(Array)
164
167
  condition = flag.map { |f| "@#{generate_flag_name(f)} == 1" }.join(' or ')
165
168
  else
@@ -168,13 +171,21 @@ module OrigenTesters
168
171
  line "if #{condition} then"
169
172
  line '{'
170
173
  @indent += 1
171
- process_all(nodes) if state
174
+ if flag_true
175
+ process_all(flag_true.children)
176
+ else
177
+ process_all(nodes) if state
178
+ end
172
179
  @indent -= 1
173
180
  line '}'
174
181
  line 'else'
175
182
  line '{'
176
183
  @indent += 1
177
- process_all(nodes) unless state
184
+ if flag_false
185
+ process_all(flag_false.children)
186
+ else
187
+ process_all(nodes) unless state
188
+ end
178
189
  @indent -= 1
179
190
  line '}'
180
191
  end
@@ -182,7 +193,7 @@ module OrigenTesters
182
193
  def on_flow_flag(node)
183
194
  flag, state, *nodes = *node
184
195
  [flag].flatten.each do |f|
185
- flow_control_variables << f
196
+ flow_control_variables << generate_flag_name(f)
186
197
  end
187
198
  on_condition_flag(node)
188
199
  end
@@ -190,7 +201,7 @@ module OrigenTesters
190
201
  def on_run_flag(node)
191
202
  flag, state, *nodes = *node
192
203
  [flag].flatten.each do |f|
193
- runtime_control_variables << f
204
+ runtime_control_variables << generate_flag_name(f)
194
205
  end
195
206
  on_condition_flag(node)
196
207
  end
@@ -208,42 +219,38 @@ module OrigenTesters
208
219
  end
209
220
 
210
221
  def on_set_run_flag(node)
211
- flag = node.value
222
+ flag = generate_flag_name(node.value)
212
223
  runtime_control_variables << flag
213
- line "@#{generate_flag_name(flag)} = 1;"
224
+ line "@#{flag} = 1;"
214
225
  end
215
226
 
216
227
  def on_group(node)
217
228
  on_fail = node.children.find { |n| n.try(:type) == :on_fail }
218
229
  on_pass = node.children.find { |n| n.try(:type) == :on_pass }
219
- with_continue(on_fail && on_fail.children.any? { |n| n.try(:type) == :continue }) do
220
- line '{'
221
- @indent += 1
222
- stack[:on_fail] << on_fail if on_fail
223
- stack[:on_pass] << on_pass if on_pass
224
- process_all(node.children - [on_fail, on_pass])
225
- stack[:on_fail].pop if on_fail
226
- stack[:on_pass].pop if on_pass
227
- @indent -= 1
228
- line "}, open,\"#{unique_group_name(node.find(:name).value)}\", \"\""
229
- end
230
+ line '{'
231
+ @indent += 1
232
+ stack[:on_fail] << on_fail if on_fail
233
+ stack[:on_pass] << on_pass if on_pass
234
+ process_all(node.children - [on_fail, on_pass])
235
+ stack[:on_fail].pop if on_fail
236
+ stack[:on_pass].pop if on_pass
237
+ @indent -= 1
238
+ line "}, open,\"#{unique_group_name(node.find(:name).value)}\", \"\""
230
239
  end
231
240
 
232
241
  def on_set_result(node)
233
- unless @continue
234
- bin = node.find(:bin).try(:value)
235
- desc = node.find(:bin).to_a[1]
236
- sbin = node.find(:softbin).try(:value)
237
- sdesc = node.find(:softbin).to_a[1] || 'fail'
238
- if bin && desc
239
- hardware_bin_descriptions[bin] ||= desc
240
- end
242
+ bin = node.find(:bin).try(:value)
243
+ desc = node.find(:bin).to_a[1]
244
+ sbin = node.find(:softbin).try(:value)
245
+ sdesc = node.find(:softbin).to_a[1] || 'fail'
246
+ if bin && desc
247
+ hardware_bin_descriptions[bin] ||= desc
248
+ end
241
249
 
242
- if node.to_a[0] == 'pass'
243
- line "stop_bin \"#{sbin}\", \"\", , good, noreprobe, green, #{bin}, over_on;"
244
- else
245
- line "stop_bin \"#{sbin}\", \"#{sdesc}\", , bad, noreprobe, red, #{bin}, over_on;"
246
- end
250
+ if node.to_a[0] == 'pass'
251
+ line "stop_bin \"#{sbin}\", \"\", , good, noreprobe, green, #{bin}, over_on;"
252
+ else
253
+ line "stop_bin \"#{sbin}\", \"#{sdesc}\", , bad, noreprobe, red, #{bin}, over_on;"
247
254
  end
248
255
  end
249
256
 
@@ -266,13 +273,6 @@ module OrigenTesters
266
273
  [job].flatten.map { |j| "@JOB == \"#{j.to_s.upcase}\"" }
267
274
  end
268
275
 
269
- def with_continue(value)
270
- orig = @continue
271
- @continue = true if value
272
- yield
273
- @continue = orig
274
- end
275
-
276
276
  private
277
277
 
278
278
  def generate_flag_name(flag)
@@ -26,7 +26,8 @@ module OrigenTesters
26
26
 
27
27
  # @api private
28
28
  def at_flow_start
29
- flow.at_flow_start
29
+ f = flow
30
+ f.at_flow_start
30
31
  # Initialize this to the value currently set on the tester, any further setting of
31
32
  # this by the interface will override
32
33
  flow.add_flow_enable = tester.add_flow_enable
@@ -7,6 +7,9 @@ module OrigenTesters
7
7
  autoload :EmptyBranchCleaner, 'origen_testers/smartest_based_tester/base/processors/empty_branch_cleaner'
8
8
  autoload :FlagOptimizer, 'origen_testers/smartest_based_tester/base/processors/flag_optimizer'
9
9
  autoload :ExtractSetVariables, 'origen_testers/smartest_based_tester/base/processors/extract_set_variables'
10
+ autoload :AdjacentIfCombiner, 'origen_testers/smartest_based_tester/base/processors/adjacent_if_combiner'
11
+ autoload :ContinueImplementer, 'origen_testers/smartest_based_tester/base/processors/continue_implementer'
12
+ autoload :ExtractRunFlagTable, 'origen_testers/smartest_based_tester/base/processors/extract_run_flag_table'
10
13
  end
11
14
  end
12
15
  end
@@ -0,0 +1,106 @@
1
+ module OrigenTesters
2
+ module SmartestBasedTester
3
+ class Base
4
+ module Processors
5
+ # This combines adjacent if flag nodes where the flag is in the opposite state
6
+ #
7
+ # s(:flow,
8
+ # s(:name, "prb1"),
9
+ # s(:run_flag, "SOME_FLAG", true,
10
+ # s(:test,
11
+ # s(:name, "test1"))),
12
+ # s(:run_flag, "SOME_FLAG", false,
13
+ # s(:test,
14
+ # s(:name, "test2"))))
15
+ #
16
+ # s(:flow,
17
+ # s(:name, "prb1"),
18
+ # s(:run_flag, "SOME_FLAG",
19
+ # s(:flag_true,
20
+ # s(:test,
21
+ # s(:name, "test1"))),
22
+ # s(:flag_false,
23
+ # s(:test,
24
+ # s(:name, "test2")))))
25
+ #
26
+ # See here for an example of the kind of flow level effect it has:
27
+ # https://github.com/Origen-SDK/origen_testers/issues/43
28
+ class AdjacentIfCombiner < ATP::Processor
29
+ class SetRunFlagFinder < ATP::Processor
30
+ def contains?(node, flag_name)
31
+ @result = false
32
+ @flag_name = flag_name
33
+ process_all(node)
34
+ @result
35
+ end
36
+
37
+ def on_set_run_flag(node)
38
+ if node.to_a[0] == @flag_name
39
+ @result = true
40
+ end
41
+ end
42
+ alias_method :on_set_flow_flag, :on_set_run_flag
43
+ end
44
+
45
+ def on_unnamed_collection(node)
46
+ node.updated(nil, optimize(process_all(node.children)))
47
+ end
48
+ alias_method :on_on_fail, :on_unnamed_collection
49
+ alias_method :on_on_pass, :on_unnamed_collection
50
+
51
+ def on_named_collection(node)
52
+ name, *nodes = *node
53
+ node.updated(nil, [name] + optimize(process_all(nodes)))
54
+ end
55
+ alias_method :on_flow, :on_named_collection
56
+ alias_method :on_group, :on_named_collection
57
+
58
+ def on_group(node)
59
+ name, *nodes = *node
60
+ node.updated(nil, [name] + optimize(process_all(nodes)))
61
+ end
62
+
63
+ def optimize(nodes)
64
+ results = []
65
+ node1 = nil
66
+ nodes.each do |node2|
67
+ if node1
68
+ if opposite_flag_states?(node1, node2) && safe_to_combine?(node1, node2)
69
+ results << combine(node1, node2)
70
+ node1 = nil
71
+ else
72
+ results << node1
73
+ node1 = node2
74
+ end
75
+ else
76
+ node1 = node2
77
+ end
78
+ end
79
+ results << node1 if node1
80
+ results
81
+ end
82
+
83
+ def combine(node1, node2)
84
+ true_node = node1.to_a[1] ? node1 : node2
85
+ false_node = node1.to_a[1] ? node2 : node1
86
+ true_node = n(:flag_true, process_all(true_node.to_a[2..-1]))
87
+ false_node = n(:flag_false, process_all(false_node.to_a[2..-1]))
88
+
89
+ n(node1.type, [node1.to_a[0], true_node, false_node])
90
+ end
91
+
92
+ def opposite_flag_states?(node1, node2)
93
+ ((node1.type == :run_flag && node2.type == :run_flag) || (node1.type == :flow_flag && node2.type == :flow_flag)) &&
94
+ node1.to_a[0] == node2.to_a[0] && node1.to_a[1] != node2.to_a[1]
95
+ end
96
+
97
+ def safe_to_combine?(node1, node2)
98
+ # Nodes won't be collapsed if node1 touches the shared run flag, i.e. if there is any chance
99
+ # that by the time it would naturally execute node2, the flag could have been changed by node1
100
+ !SetRunFlagFinder.new.contains?(node1, node1.to_a[0])
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,39 @@
1
+ module OrigenTesters
2
+ module SmartestBasedTester
3
+ class Base
4
+ module Processors
5
+ # Implements continue on a fail branch for V93K by removing any bin nodes that are
6
+ # siblings of continue nodes. The continue nodes are also removed in the process since
7
+ # they have now served their function.
8
+ class ContinueImplementer < ATP::Processor
9
+ # Delete any on-fail child if it's 'empty'
10
+ def on_on_fail(node)
11
+ if cont = node.find(:continue) || @continue
12
+ node = node.updated(nil, node.children - [cont] - node.find_all(:set_result))
13
+ end
14
+ node.updated(nil, process_all(node.children))
15
+ end
16
+
17
+ def on_group(node)
18
+ f = node.find(:on_fail)
19
+ if f && f.find(:continue)
20
+ with_continue do
21
+ node = node.updated(nil, process_all(node.children))
22
+ end
23
+ node
24
+ else
25
+ node.updated(nil, process_all(node.children))
26
+ end
27
+ end
28
+
29
+ def with_continue
30
+ orig = @continue
31
+ @continue = true
32
+ yield
33
+ @continue = orig
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -2,45 +2,17 @@ module OrigenTesters
2
2
  module SmartestBasedTester
3
3
  class Base
4
4
  module Processors
5
+ # Removes any empty on_pass and on_fail branches
5
6
  class EmptyBranchCleaner < ATP::Processor
6
7
  # Delete any on-fail child if it's 'empty'
7
8
  def on_test(node)
8
- on_pass = node.find(:on_pass)
9
- on_fail = node.find(:on_fail)
10
- unless on_fail.nil?
11
- n = node.remove(on_fail) if branch_is_empty?(on_fail)
12
- return n
9
+ if on_pass = node.find(:on_pass)
10
+ node = node.remove(on_pass) if on_pass.children.empty?
13
11
  end
14
- node
15
- end
16
-
17
- # Returns true if:
18
- # - node is completely empty
19
- # - only child is (continue) node
20
- # - only two children, one continue and one set-result
21
- def branch_is_empty?(node)
22
- children = node.children.dup
23
- return true if children.nil?
24
-
25
- # test for only-child situation
26
- first_born = children.shift
27
- if children.empty?
28
- if first_born == n0(:continue)
29
- return true
30
- else
31
- return false
32
- end
33
- end
34
-
35
- # if only 2 children, check qualificataions, else done and return false
36
- next_born = children.shift
37
- if children.empty?
38
- if (first_born.type == :continue && next_born.type == :set_result) ||
39
- (first_born.type == :set_result && next_born.type == :continue)
40
- return true
41
- end
12
+ if on_fail = node.find(:on_fail)
13
+ node = node.remove(on_fail) if on_fail.children.empty?
42
14
  end
43
- false
15
+ node = node.updated(nil, process_all(node.children))
44
16
  end
45
17
  end
46
18
  end
@@ -0,0 +1,33 @@
1
+ module OrigenTesters
2
+ module SmartestBasedTester
3
+ class Base
4
+ module Processors
5
+ # Processes the AST and tabulates occurrences of unique set_run_flag nodes
6
+ class ExtractRunFlagTable < ATP::Processor
7
+ # Hash table of run_flag name with number of times used
8
+ attr_reader :run_flag_table
9
+
10
+ # Reset hash table
11
+ def initialize
12
+ @run_flag_table = {}.with_indifferent_access
13
+ end
14
+
15
+ # For run_flag nodes, increment # of occurrences for specified flag
16
+ def on_run_flag(node)
17
+ children = node.children.dup
18
+ names = children.shift
19
+ state = children.shift
20
+ Array(names).each do |name|
21
+ if @run_flag_table[name.to_sym].nil?
22
+ @run_flag_table[name.to_sym] = 1
23
+ else
24
+ @run_flag_table[name.to_sym] += 1
25
+ end
26
+ end
27
+ process_all(node.children)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -2,139 +2,184 @@ module OrigenTesters
2
2
  module SmartestBasedTester
3
3
  class Base
4
4
  module Processors
5
+ # This processor eliminates the use of run flags between adjacent tests:
6
+ #
7
+ # s(:flow,
8
+ # s(:name, "prb1"),
9
+ # s(:test,
10
+ # s(:name, "test1"),
11
+ # s(:id, "t1"),
12
+ # s(:on_fail,
13
+ # s(:set_run_flag, "t1_FAILED", "auto_generated"),
14
+ # s(:continue))),
15
+ # s(:run_flag, "t1_FAILED", true,
16
+ # s(:test,
17
+ # s(:name, "test2"))))
18
+ #
19
+ #
20
+ # s(:flow,
21
+ # s(:name, "prb1"),
22
+ # s(:test,
23
+ # s(:name, "test1"),
24
+ # s(:id, "t1"),
25
+ # s(:on_fail,
26
+ # s(:test,
27
+ # s(:name, "test2")))))
28
+ #
5
29
  class FlagOptimizer < ATP::Processor
6
30
  attr_reader :run_flag_table
7
- # This optimizes the AST such that any adjacent flow noes that
8
- #
9
- # For example this AST:
10
- # (flow
11
- # (test
12
- # (name "test1")
13
- # (on-fail
14
- # (set-run-flag "t1_FAILED")))
15
- # (run-flag "t1_FAILED" true
16
- # (test
17
- # (name "test2"))
18
- # (test
19
- # (name "test3")))
20
- # (test
21
- # (name "test4")
22
- # (on-pass
23
- # (set-run-flag "t4_PASSED"))
24
- # (on-fail
25
- # (continue)))
26
- # (run-flag "t4_PASSED" true
27
- # (test
28
- # (name "test5"))
29
- # (test
30
- # (name "test6"))))
31
- #
32
- # Will be optimized to this:
33
- # (flow
34
- # (test
35
- # (name "test1")
36
- # (on-fail
37
- # (test
38
- # (name "test2"))
39
- # (test
40
- # (name "test3"))))
41
- # (test
42
- # (name "test4")
43
- # (on-pass
44
- # (test
45
- # (name "test5"))
46
- # (test
47
- # (name "test6")))
48
- # (on-fail
49
- # (continue))))
50
31
 
51
- # Processes the AST and tabulates occurences of unique set_run_flag nodes
52
- class ExtractRunFlagTable < ATP::Processor
53
- # Hash table of run_flag name with number of times used
54
- attr_reader :run_flag_table
32
+ def run(node)
33
+ # Pre-process the AST for # of occurrences of each run-flag used
34
+ t = ExtractRunFlagTable.new
35
+ t.process(node)
36
+ @run_flag_table = t.run_flag_table
37
+ process(node)
38
+ end
55
39
 
56
- # Reset hash table
57
- def initialize
58
- @run_flag_table = {}
40
+ def on_named_collection(node)
41
+ name, *nodes = *node
42
+ node.updated(nil, [name] + optimize(process_all(nodes)))
43
+ end
44
+ alias_method :on_flow, :on_named_collection
45
+ alias_method :on_group, :on_named_collection
46
+
47
+ def on_run_flag(node)
48
+ name, state, *nodes = *node
49
+ if run_flag_to_remove.last && run_flag_to_remove.last == node.to_a[0..1]
50
+ node.to_a.last
51
+ else
52
+ node.updated(nil, [name, state] + optimize(process_all(nodes)))
59
53
  end
54
+ end
60
55
 
61
- # For run_flag nodes, increment # of occurences for specified flag
62
- def on_run_flag(node)
63
- children = node.children.dup
64
- name = children.shift
65
- state = children.shift
66
- unless name.is_a?(Array)
67
- if @run_flag_table[name.to_sym].nil?
68
- @run_flag_table[name.to_sym] = 1
69
- else
70
- @run_flag_table[name.to_sym] += 1
56
+ def on_on_fail(node)
57
+ if to_inline = nodes_to_inline_on_pass_or_fail.last
58
+ # If this node sets the flag that gates the node to be inlined
59
+ set_run_flag = node.find(:set_run_flag)
60
+ if set_run_flag && gated_by_set?(set_run_flag.to_a[0], to_inline)
61
+ # Remove the sub-node that sets the flag if there are no further references to it
62
+
63
+ if @run_flag_table[set_run_flag.to_a[0]] == 1 || !@run_flag_table[set_run_flag.to_a[0]]
64
+ node = node.updated(nil, node.children - [set_run_flag])
71
65
  end
66
+
67
+ # And append the content of the node to be in_lined at the end of this on pass/fail node
68
+ append = reorder_nested_run_flags(set_run_flag.to_a[0], to_inline).to_a[2..-1]
69
+
70
+ # Belt and braces approach to make sure this node to be inlined does
71
+ # not get picked up anywhere else
72
+ nodes_to_inline_on_pass_or_fail.pop
73
+ nodes_to_inline_on_pass_or_fail << nil
72
74
  end
73
75
  end
76
+ node.updated(nil, optimize(process_all(node.children + Array(append))))
74
77
  end
78
+ alias_method :on_on_pass, :on_on_fail
75
79
 
76
- # Only run this on top level flow and consider adjacent nodes, no need for
77
- # looking at nested conditions.
78
- def on_flow(node)
79
- # Pre-process the AST for # of occurences of each run-flag used
80
- t = ExtractRunFlagTable.new
81
- t.process(node)
82
- @run_flag_table = t.run_flag_table
83
-
84
- name, *nodes = *node
80
+ def optimize(nodes)
85
81
  results = []
86
- node_a = nil
87
- nodes.each do |node_b|
88
- if node_a && node_a.type == :test && node_b.type == :run_flag
89
- result, node_a = remove_run_flag(node_a, node_b)
90
- results << result
82
+ node1 = nil
83
+ nodes.each do |node2|
84
+ if node1
85
+ if can_be_combined?(node1, node2)
86
+ node1 = combine(node1, node2)
87
+ else
88
+ results << node1
89
+ node1 = node2
90
+ end
91
91
  else
92
- results << node_a unless node_a.nil?
93
- node_a = node_b
92
+ node1 = node2
94
93
  end
95
94
  end
96
- results << node_a unless node_a.nil?
97
- node.updated(nil, [name] + results)
95
+ results << node1 if node1
96
+ results
98
97
  end
99
98
 
100
- # Given two adjacent nodes, where the first (a) is a test and the second (b)
101
- # is a run_flag, determine if (a) conditionally sets the same flag that (b)
102
- # uses. If it does, do a logical replacement, if not, move on quietly.
103
- def remove_run_flag(node_a, node_b)
104
- on_pass = node_a.find(:on_pass)
105
- on_fail = node_a.find(:on_fail)
106
-
107
- unless on_pass.nil? && on_fail.nil?
108
- if on_pass.nil?
109
- flag_node = on_fail.find(:set_run_flag)
110
- conditional = [flag_node, on_fail]
111
- else
112
- flag_node = on_pass.find(:set_run_flag)
113
- conditional = [flag_node, on_pass]
99
+ def can_be_combined?(node1, node2)
100
+ if node1.type == :test && node2.type == :run_flag
101
+ if node1.find_all(:on_fail, :on_pass).any? do |node|
102
+ if n = node.find(:set_run_flag)
103
+ # Inline instead of setting a flag if...
104
+ gated_by_set?(n.to_a[0], node2) && # The flag set by node1 is gating node2
105
+ n.to_a[1] == 'auto_generated' && # The flag has been generated and not specified by the user
106
+ n.to_a[0] !~ /_RAN$/ # And don't compress RAN flags because they can be set by both on_fail and on_pass
107
+ end
108
+ end
109
+ return true
114
110
  end
115
111
  end
116
- unless conditional.nil?
117
- children = node_b.children.dup
118
- name = children.shift
119
- # remove the '_RAN' here so it won't match and if_ran cases are ignored
120
- name = name.gsub(/_RAN$/, '') unless name.is_a?(Array)
121
- state = children.shift
122
- *nodes = *children
123
- flag_node_b = n2(:set_run_flag, name, 'auto_generated') if state == true
112
+ false
113
+ end
124
114
 
125
- if conditional.first == flag_node_b
126
- n = conditional.last.dup
127
- result = node_a.remove(n)
128
- n = n.remove(conditional.first) if @run_flag_table[name.to_sym] == 1
129
- n = n.remove(n0(:continue)) if n.type == :on_fail
130
- s = n.find(:set_result) if n.type == :on_fail
131
- n = n.remove(s) if s
132
- n = n.updated(nil, n.children + (nodes.is_a?(Array) ? nodes : [nodes]))
133
- result = result.updated(nil, result.children + (n.is_a?(Array) ? n : [n]))
134
- return result, nil
135
- end
115
+ def combine(node1, node2)
116
+ nodes_to_inline_on_pass_or_fail << node2
117
+ node1 = node1.updated(nil, process_all(node1.children))
118
+ nodes_to_inline_on_pass_or_fail.pop
119
+ node1
120
+ end
121
+
122
+ # node will always be a run_flag type node, guaranteed by the caller
123
+ #
124
+ # Returns true if flag matches the one supplied and it is required to be set(true), like this:
125
+ #
126
+ # s(:run_flag, flag, true,
127
+ # s(:test, ...
128
+ #
129
+ # Also returns true if flag matches the one supplied, but it is nested within other flag conditions:
130
+ #
131
+ # s(:run_flag, other_flag, false,
132
+ # s(:run_flag, other_flag2, true,
133
+ # s(:run_flag, flag, true,
134
+ # s(:test, ...
135
+ def gated_by_set?(flag, node)
136
+ (flag == node.to_a[0] && node.to_a[1]) ||
137
+ (node.to_a.size == 3 && node.to_a.last.type == :run_flag && gated_by_set?(flag, node.to_a.last))
138
+ end
139
+
140
+ # Returns the node with the run_flag clauses re-ordered to have the given flag of interest at the top.
141
+ #
142
+ # The caller guarantees the run_flag clause containing the given flag is present.
143
+ #
144
+ # For example, given this node:
145
+ #
146
+ # s(:run_flag, "flag1", false,
147
+ # s(:run_flag, "ot_BEA7F3B_FAILED", true,
148
+ # s(:test,
149
+ # s(:object, <TestSuite: inner_test1_BEA7F3B>),
150
+ # s(:name, "inner_test1_BEA7F3B"),
151
+ # s(:number, 0),
152
+ # s(:id, "it1_BEA7F3B"),
153
+ # s(:on_fail,
154
+ # s(:render, "multi_bin;")))))
155
+ #
156
+ # Then this node would be returned when the flag of interest is ot_BEA7F3B_FAILED:
157
+ #
158
+ # s(:run_flag, "ot_BEA7F3B_FAILED", true,
159
+ # s(:run_flag, "flag1", false,
160
+ # s(:test,
161
+ # s(:object, <TestSuite: inner_test1_BEA7F3B>),
162
+ # s(:name, "inner_test1_BEA7F3B"),
163
+ # s(:number, 0),
164
+ # s(:id, "it1_BEA7F3B"),
165
+ # s(:on_fail,
166
+ # s(:render, "multi_bin;")))))
167
+ def reorder_nested_run_flags(flag, node)
168
+ # If the run_flag we care about is already at the top, just return node
169
+ unless node.to_a[0] == flag && node.to_a[1]
170
+ run_flag_to_remove << [flag, true]
171
+ node = n(:run_flag, [flag, true, process(node)])
172
+ run_flag_to_remove.pop
136
173
  end
137
- [node_a, node_b]
174
+ node
175
+ end
176
+
177
+ def run_flag_to_remove
178
+ @run_flag_to_remove ||= []
179
+ end
180
+
181
+ def nodes_to_inline_on_pass_or_fail
182
+ @nodes_to_inline_on_pass_or_fail ||= []
138
183
  end
139
184
  end
140
185
  end
@@ -5,9 +5,9 @@ declarations
5
5
 
6
6
  % clean_runtime_control_variables.each do |var|
7
7
  % if var.is_a?(Array)
8
- @<%= var[0].to_s.upcase %> = <%= var[1].is_a?(String) || var[1].is_a?(Symbol) ? "\"#{var[1]}\"" : var[1] %>;
8
+ @<%= var[0].to_s %> = <%= var[1].is_a?(String) || var[1].is_a?(Symbol) ? "\"#{var[1]}\"" : var[1] %>;
9
9
  % else
10
- @<%= var.to_s.upcase %> = 0;
10
+ @<%= var.to_s %> = 0;
11
11
  % end
12
12
  % end
13
13
 
@@ -17,9 +17,9 @@ flags
17
17
 
18
18
  % clean_flow_control_variables.each do |var|
19
19
  % if var.is_a?(Array)
20
- user <%= var[0].to_s.upcase %> = <%= var[1].is_a?(String) || var[1].is_a?(Symbol) ? "\"#{var[1]}\"" : var[1] %>;
20
+ user <%= var[0].to_s %> = <%= var[1].is_a?(String) || var[1].is_a?(Symbol) ? "\"#{var[1]}\"" : var[1] %>;
21
21
  % else
22
- user <%= var.to_s.upcase %> = 0;
22
+ user <%= var.to_s %> = 0;
23
23
  % end
24
24
  % end
25
25
 
@@ -146,12 +146,18 @@ module OrigenTesters
146
146
  original = @timeset
147
147
  timeset_changed(timeset)
148
148
  @timeset = timeset
149
+ dut.timeset = timeset.name if dut.timesets[timeset.name]
150
+ dut.current_timeset_period = timeset.period_in_ns
149
151
  yield
150
152
  timeset_changed(original)
151
153
  @timeset = original
154
+ dut.timeset = original.name if dut.timesets[original.name]
155
+ dut.current_timeset_period = original.period_in_ns
152
156
  else
153
157
  timeset_changed(timeset)
154
158
  @timeset = timeset
159
+ dut.timeset = timeset.name if dut.timesets[timeset.name]
160
+ dut.current_timeset_period = timeset.period_in_ns
155
161
  end
156
162
  end
157
163
 
@@ -208,5 +208,15 @@ Flow.create do |options|
208
208
 
209
209
  pass 2, if_ran: :g100
210
210
 
211
+ log 'Test node optimization within an if_failed branch'
212
+ func :some_func_test, id: :sft1
213
+
214
+ if_failed :sft1 do
215
+ bin 10, if_flag: "Alarm"
216
+ bin 11, unless_flag: "Alarm"
217
+ bin 12, if_enable: "AlarmEnabled"
218
+ bin 13, unless_enable: "AlarmEnabled"
219
+ end
220
+
211
221
  pass 1, description: "Good die!", softbin: 1
212
222
  end
@@ -338,4 +338,85 @@ Flow.create interface: 'OrigenTesters::Test::Interface' do
338
338
 
339
339
  func :test36, on_fail: { render: 'multi_bin;' }, if_flag: :my_flag
340
340
  end
341
+
342
+ log 'An optimization test case, this should not generate a flag on V93K'
343
+ func :test1, id: :t1a
344
+
345
+ if_passed :t1a do
346
+ func :test2
347
+ end
348
+
349
+ if_failed :t1a do
350
+ func :test3
351
+ bin 10
352
+ end
353
+
354
+ log 'The reverse optimization test case, this should not generate a flag on V93K'
355
+ func :test1, id: :t1b
356
+
357
+ if_failed :t1b do
358
+ func :test3
359
+ bin 10
360
+ end
361
+
362
+ if_passed :t1b do
363
+ func :test2
364
+ end
365
+
366
+ if tester.v93k?
367
+ log 'Nested optimization test case'
368
+ func :outer_test, id: :ot
369
+ if_failed :ot do
370
+ unless_flag :flag1 do
371
+ func :inner_test1, id: :it1
372
+ render 'multi_bin;', if_failed: :it1
373
+ end
374
+ end
375
+
376
+ log 'Nested flag optimization test case'
377
+ if_flag :flag1 do
378
+ func :test4, id: :nf_t4
379
+ if_failed :nf_t4 do
380
+ render 'multi_bin;', if_flag: :flag1
381
+ end
382
+ end
383
+
384
+ log 'The setting of flags used in later OR conditions should be preserved'
385
+ func :test2, id: :of1
386
+ func :test3, if_failed: :of1
387
+ func :test2, id: :of2
388
+ func :test3, if_failed: :of2
389
+ func :test4
390
+ func :test4, if_any_failed: [:of1, :of2]
391
+
392
+ log 'The setting of flags used in later AND conditions should be preserved'
393
+ func :test2, id: :af1
394
+ func :test3, if_failed: :af1
395
+ func :test2, id: :af2
396
+ func :test3, if_failed: :af2
397
+ func :test4
398
+ func :test4, if_all_failed: [:af1, :af2]
399
+
400
+ log 'Adjacent tests that set a flag and then use it in an OR condition should be valid'
401
+ func :test2, id: :of11
402
+ func :test2, id: :of12
403
+ func :test4, if_any_failed: [:of11, :of12]
404
+
405
+ log 'Adjacent tests that set a flag and then use it in an AND condition should be valid'
406
+ func :test2, id: :af11
407
+ func :test2, id: :af12
408
+ func :test4, if_all_failed: [:af11, :af12]
409
+
410
+ log 'Adjacent if combiner test case 1'
411
+ func :test1, if_enable: :my_enable_word
412
+ func :test2, unless_enable: :my_enable_word
413
+ func :test1, if_flag: :my_flag
414
+ func :test2, unless_flag: :my_flag
415
+
416
+ log 'Adjacent if combiner test case 2'
417
+ func :test2, unless_enable: :my_enable_word
418
+ func :test1, if_enable: :my_enable_word
419
+ func :test2, unless_flag: :my_flag
420
+ func :test1, if_flag: :my_flag
421
+ end
341
422
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: origen_testers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen McGinty
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-19 00:00:00.000000000 Z
11
+ date: 2017-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: origen
@@ -241,7 +241,10 @@ files:
241
241
  - lib/origen_testers/smartest_based_tester/base/pattern_compiler.rb
242
242
  - lib/origen_testers/smartest_based_tester/base/pattern_master.rb
243
243
  - lib/origen_testers/smartest_based_tester/base/processors.rb
244
+ - lib/origen_testers/smartest_based_tester/base/processors/adjacent_if_combiner.rb
245
+ - lib/origen_testers/smartest_based_tester/base/processors/continue_implementer.rb
244
246
  - lib/origen_testers/smartest_based_tester/base/processors/empty_branch_cleaner.rb
247
+ - lib/origen_testers/smartest_based_tester/base/processors/extract_run_flag_table.rb
245
248
  - lib/origen_testers/smartest_based_tester/base/processors/extract_set_variables.rb
246
249
  - lib/origen_testers/smartest_based_tester/base/processors/flag_optimizer.rb
247
250
  - lib/origen_testers/smartest_based_tester/base/processors/if_ran_cleaner.rb