origen_testers 0.12.0 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/config/version.rb +1 -1
- data/lib/origen_testers/flow.rb +2 -2
- data/lib/origen_testers/smartest_based_tester/base/flow.rb +44 -44
- data/lib/origen_testers/smartest_based_tester/base/generator.rb +2 -1
- data/lib/origen_testers/smartest_based_tester/base/processors.rb +3 -0
- data/lib/origen_testers/smartest_based_tester/base/processors/adjacent_if_combiner.rb +106 -0
- data/lib/origen_testers/smartest_based_tester/base/processors/continue_implementer.rb +39 -0
- data/lib/origen_testers/smartest_based_tester/base/processors/empty_branch_cleaner.rb +6 -34
- data/lib/origen_testers/smartest_based_tester/base/processors/extract_run_flag_table.rb +33 -0
- data/lib/origen_testers/smartest_based_tester/base/processors/flag_optimizer.rb +157 -112
- data/lib/origen_testers/smartest_based_tester/v93k/templates/vars.tf.erb +4 -4
- data/lib/origen_testers/timing.rb +6 -0
- data/program/components/_prb1_main.rb +10 -0
- data/program/flow_control.rb +81 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 112e2af4457169ff2ba79641610c0722d565f1fb
|
4
|
+
data.tar.gz: 8833d9bcc8538cb5e5a32f934222e90360957d0d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c28c0d2cba87e54110b23a77a7f4cf4eb6adc54f93daca4531a9168e98bd0915481d1bc7d4eefae082fbdfb648c7bb31f93a4e8dc7f2b12abcc164ede3b2b039
|
7
|
+
data.tar.gz: ca63134cf7ac29bb74ece0bd9487251ad16ba4b59c6901ebc34288f471591138ad72a433d84d7490586daaee38722189b9d1b088d780b611164cde7aff7758df
|
data/config/version.rb
CHANGED
data/lib/origen_testers/flow.rb
CHANGED
@@ -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::
|
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
|
-
|
126
|
-
|
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
|
-
|
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
|
-
|
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 "@#{
|
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
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
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
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
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
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
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
|
-
|
57
|
-
|
58
|
-
|
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
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
-
|
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
|
-
|
87
|
-
nodes.each do |
|
88
|
-
if
|
89
|
-
|
90
|
-
|
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
|
-
|
93
|
-
node_a = node_b
|
92
|
+
node1 = node2
|
94
93
|
end
|
95
94
|
end
|
96
|
-
results <<
|
97
|
-
|
95
|
+
results << node1 if node1
|
96
|
+
results
|
98
97
|
end
|
99
98
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
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
|
-
|
117
|
-
|
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
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
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
|
-
|
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
|
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
|
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
|
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
|
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
|
data/program/flow_control.rb
CHANGED
@@ -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.
|
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-
|
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
|