origen_testers 0.47.0 → 0.48.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/config/application.rb +1 -0
- data/config/version.rb +1 -1
- data/lib/origen_testers.rb +1 -0
- data/lib/origen_testers/charz.rb +421 -0
- data/lib/origen_testers/charz/profile.rb +120 -0
- data/lib/origen_testers/charz/routine.rb +38 -0
- data/lib/origen_testers/charz/routines/search_routine.rb +42 -0
- data/lib/origen_testers/charz/routines/shmoo_routine.rb +62 -0
- data/lib/origen_testers/charz/session.rb +100 -0
- data/lib/origen_testers/origen_ext/generator/flow.rb +1 -0
- data/lib/origen_testers/test/interface.rb +80 -0
- data/program/charz.rb +48 -0
- data/templates/origen_guides/program/charz.md.erb +221 -0
- metadata +41 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: aab714d801c978890bf63dcf475ccf275b87b54e
|
4
|
+
data.tar.gz: 37d3ef0d30281f9e467ba8475957aacebdb2959a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b2abd50fe57675fa06d61afe99ca4930a36bdfeaf172b8f166c40e0af190cf57b90a5e01ce366471a5aec5dd3a9be7957c09bb089c9922bdf07891f12226a9d6
|
7
|
+
data.tar.gz: b53c79a3dbc31a29fd74a984b4dc5111c245032d093d099a66195c08404f7d12980dd1f33d2f454ec4df1759a72c775aeb612c578dcfe4155af12f3cbe9d8b54
|
data/config/application.rb
CHANGED
@@ -31,6 +31,7 @@ class OrigenTestersApplication < Origen::Application
|
|
31
31
|
section.page :interface, heading: "Creating an Interface"
|
32
32
|
section.page :resources, heading: "Additional Resources"
|
33
33
|
section.page :code, heading: "Dynamic Custom Code"
|
34
|
+
section.page :charz, heading: "Characterization API"
|
34
35
|
section.page :j750, heading: "J750 API"
|
35
36
|
section.page :v93k, heading: "V93K Common API"
|
36
37
|
section.page :v93ksmt7, heading: "V93K SMT7 API"
|
data/config/version.rb
CHANGED
data/lib/origen_testers.rb
CHANGED
@@ -24,6 +24,7 @@ module OrigenTesters
|
|
24
24
|
autoload :NoInterface, 'origen_testers/no_interface'
|
25
25
|
autoload :MemoryStyle, 'origen_testers/memory_style'
|
26
26
|
autoload :ATP, 'origen_testers/atp'
|
27
|
+
autoload :Charz, 'origen_testers/charz'
|
27
28
|
|
28
29
|
# not yet autoload :Time, 'origen_testers/time'
|
29
30
|
|
@@ -0,0 +1,421 @@
|
|
1
|
+
Dir.glob("#{File.dirname(__FILE__)}/charz/**/*.rb").sort.each do |file|
|
2
|
+
require file
|
3
|
+
end
|
4
|
+
module OrigenTesters
|
5
|
+
module Charz
|
6
|
+
# @!attribute charz_stack
|
7
|
+
# @return [Array] FILO queue of charz session defining data
|
8
|
+
# @!attribute charz_routines
|
9
|
+
# @return [Hash] user defined charz routines
|
10
|
+
# @!attribute charz_profiles
|
11
|
+
# @return [Hash] user defined charz profiles
|
12
|
+
# @!attribute charz_session
|
13
|
+
# @return [Session] current charz session, based on data in the top of the charz_stack
|
14
|
+
# @!attribute eof_charz_tests
|
15
|
+
# @return [Array] charz tests to be added at the end of the flow
|
16
|
+
# @!attribute skip_group_eof_charz_tests
|
17
|
+
# @return [Boolean] whether or not to wrap eof charz tests in a group
|
18
|
+
# @!attribute eof_charz_tests_group_name
|
19
|
+
# @return [String, Symbol] group name to be used to for eof charz tests
|
20
|
+
attr_accessor :charz_stack, :charz_routines, :charz_profiles, :charz_session, :eof_charz_tests, :skip_group_eof_charz_tests, :eof_charz_tests_group_name
|
21
|
+
|
22
|
+
def charz_stack
|
23
|
+
@charz_stack ||= []
|
24
|
+
end
|
25
|
+
|
26
|
+
def charz_profiles
|
27
|
+
@charz_profiles ||= {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def charz_routines
|
31
|
+
@charz_routines ||= {}
|
32
|
+
end
|
33
|
+
|
34
|
+
def charz_session
|
35
|
+
@charz_session ||= Session.new
|
36
|
+
end
|
37
|
+
|
38
|
+
def eof_charz_tests
|
39
|
+
@eof_charz_tests ||= []
|
40
|
+
end
|
41
|
+
|
42
|
+
# Add a new charz routine to @charz_routines
|
43
|
+
# A charz routine is a object that contains all the necessary info specific to a characterization test
|
44
|
+
# Its intended to be used in combination with an existing point test (regular non charz test) to create
|
45
|
+
# a characterization version of the point test
|
46
|
+
#
|
47
|
+
# @example create a 1d search routine that searches vdd, from 900mv to 300mv, resolution of 5mv
|
48
|
+
# add_charz_routine :my_routine, type: search do |rt|
|
49
|
+
# rt.start = 900.mv
|
50
|
+
# rt.stop = 300.mv
|
51
|
+
# rt.res = 5.mv
|
52
|
+
# rt.spec = 'vdd'
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# @param [Symbol] id charz_routine id, will be the key value in the @charz_routines hash. Must not have been previously used
|
56
|
+
# @param [Hash] options charz_routine options
|
57
|
+
# @option options [Symbol] :type :search or :'1d' will create a SearchRoutine, :shmoo or :'2d' will create a ShmooRoutine, nil will create a Routine
|
58
|
+
def add_charz_routine(id, options = {}, &block)
|
59
|
+
if charz_routines.ids.include?(id)
|
60
|
+
Origen.log.error("Cannot create charz routine '#{id}', it already exists!")
|
61
|
+
fail
|
62
|
+
end
|
63
|
+
case options[:type]
|
64
|
+
when :search, :'1d'
|
65
|
+
charz_routines[id] = SearchRoutine.new(id, options, &block)
|
66
|
+
when :shmoo, :'2d'
|
67
|
+
charz_routines[id] = ShmooRoutine.new(id, options, &block)
|
68
|
+
else
|
69
|
+
charz_routines[id] = Routine.new(id, options, &block)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Add a new charz profile to @charz_profiles
|
74
|
+
# A charz profile is a collection of one or more charz routines, as well as flow control and placement data for
|
75
|
+
# the charz tests generated by those routines
|
76
|
+
#
|
77
|
+
# @example create a profile containing 2 routines, end of flow placement, whose tests are only ran if the parent fails
|
78
|
+
# add_charz_profile :my_profile do |prof|
|
79
|
+
# prof.routines = [:my_routine1, :my_routine2]
|
80
|
+
# prof.placement = :eof
|
81
|
+
# prof.on_result = :on_fail
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# @param [Symbol] id charz_profile id, will be the key value in the @charz_profiles hash. Must not have been previously used
|
85
|
+
# @param [Hash] options charz_profile options
|
86
|
+
def add_charz_profile(id, options = {}, &block)
|
87
|
+
if charz_profiles.ids.include?(id)
|
88
|
+
Origen.log.error("Cannot create charz profile '#{id}', it already exists!")
|
89
|
+
fail
|
90
|
+
end
|
91
|
+
charz_profiles[id] = Profile.new(id, options.merge(defined_routines: charz_routines.ids), &block)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Queries the current charz session to see if its active, indicating point tests should be generating charz tests
|
95
|
+
def charz_active?
|
96
|
+
charz_session.active
|
97
|
+
end
|
98
|
+
|
99
|
+
# Queries the current charz session to see if point tests should skip generation, only adding the resulting charz test
|
100
|
+
def charz_only?
|
101
|
+
charz_active? && charz_session.charz_only
|
102
|
+
end
|
103
|
+
|
104
|
+
# Pauses the current charz session, preventing point tests from generating charz tests even if the session is valid
|
105
|
+
def charz_pause
|
106
|
+
charz_session.pause
|
107
|
+
end
|
108
|
+
|
109
|
+
# Resumes the current charz session. If the session isn't valid (ie charz_resume before setting up the session) then nothing will happen
|
110
|
+
def charz_resume
|
111
|
+
charz_session.resume
|
112
|
+
end
|
113
|
+
|
114
|
+
# Removes the current session generating data off the charz stack
|
115
|
+
# If charz data is still on the stack afterward, the session will update to reflect the new data
|
116
|
+
# if not, the session will become inactive
|
117
|
+
def charz_off
|
118
|
+
charz_stack.pop
|
119
|
+
if charz_stack.empty?
|
120
|
+
update_charz_session(nil)
|
121
|
+
else
|
122
|
+
update_charz_session(*charz_stack.last)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Pushes a charz object (either a profile or a routine) onto the stack, along with any optional updates to modify the current session
|
127
|
+
# Once pushed, the charz_session will attempt to update itself with the new data, failing if the resulting session is invalid
|
128
|
+
#
|
129
|
+
# If a block is passed, yield the block of tests to enable charz for those tests, then disable charz with a charz_off call
|
130
|
+
#
|
131
|
+
# @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
|
132
|
+
# @param [Hash] options charz_on options
|
133
|
+
# @option options [Symbol] :type (:profile) whether the charz_id refers to a charz profile or routine
|
134
|
+
def charz_on(charz_id, options = {})
|
135
|
+
options = {
|
136
|
+
type: :profile
|
137
|
+
}.merge(options)
|
138
|
+
case options[:type]
|
139
|
+
when :profile
|
140
|
+
charz_obj = charz_profiles[charz_id]
|
141
|
+
when :routine
|
142
|
+
if charz_id.is_a?(Array)
|
143
|
+
charz_obj = charz_routines[charz_id.first]
|
144
|
+
options[:routines] = charz_id
|
145
|
+
else
|
146
|
+
charz_obj = charz_routines[charz_id]
|
147
|
+
options[:routines] = [charz_id]
|
148
|
+
end
|
149
|
+
else
|
150
|
+
Origen.log.error "Unknown charz object type #{options[:type]}, valid types: :profile, :routine"
|
151
|
+
fail
|
152
|
+
end
|
153
|
+
if charz_obj.nil?
|
154
|
+
Origen.log.error "No #{options[:type]} found for charz_id: #{charz_id}"
|
155
|
+
fail
|
156
|
+
end
|
157
|
+
charz_stack.push([charz_obj, options])
|
158
|
+
unless update_charz_session(*charz_stack.last)
|
159
|
+
Origen.log.error 'charz_on failed to create a valid charz session'
|
160
|
+
fail
|
161
|
+
end
|
162
|
+
if block_given?
|
163
|
+
yield
|
164
|
+
charz_off
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# 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
|
169
|
+
# @param [Hash] options the options for a test before its created and added to the flow
|
170
|
+
# @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
|
171
|
+
def set_conditional_charz_id(*args)
|
172
|
+
case args.size
|
173
|
+
when 1
|
174
|
+
options = args[0]
|
175
|
+
parent_test_name = options[:parent_test_name]
|
176
|
+
when 2
|
177
|
+
instance = args[0]
|
178
|
+
options = args[1]
|
179
|
+
parent_test_name = instance.name
|
180
|
+
else
|
181
|
+
Origen.log.error 'Too many arguments passed to set_conditional_charz_id. Pass either (test_instance, options), or just (options)'
|
182
|
+
fail
|
183
|
+
end
|
184
|
+
unless options[:id]
|
185
|
+
if charz_active?
|
186
|
+
if charz_session.on_result
|
187
|
+
options[:id] = "#{parent_test_name}_charz_#{charz_session.name}".to_sym
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Called after the relevant point test has been inserted into the flow
|
194
|
+
# Takes the options used to build the previous point test as well as insert_charz_test specific options to then
|
195
|
+
# 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
|
196
|
+
# interface to handle creating and inserting the test
|
197
|
+
#
|
198
|
+
# By default, this method will handle:
|
199
|
+
# - the placement of the test (inline aka right after the point test, end of flow, or other)
|
200
|
+
# - wrapping the created charz tests in a group (skippable, group name defaults to <point test name> charz <session name>)
|
201
|
+
# - conditionally executing the charz tests based on if the point test passed or failed (see set_conditional_charz_id)
|
202
|
+
# - conditionally executing some/all charz tests based on a mix of enables and flags
|
203
|
+
#
|
204
|
+
# After the above is determined, the user regains control on a per-routine (if multiple routines) basis to then process generating the charz test
|
205
|
+
def insert_charz_tests(options, &block)
|
206
|
+
if charz_active?
|
207
|
+
if options[:id]
|
208
|
+
# two purposes:
|
209
|
+
# 1) prevent all charz tests inadverntently using the same ID as their parent
|
210
|
+
# 2) used in on_result behavior
|
211
|
+
current_id = options.delete(:id)
|
212
|
+
options[:last_test_id] ||= current_id
|
213
|
+
end
|
214
|
+
case charz_session.placement
|
215
|
+
when :inline
|
216
|
+
create_charz_group(options, &block)
|
217
|
+
when :eof
|
218
|
+
# collect the current session and options into a proc, stored in eof_charz_tests to be called later
|
219
|
+
current_session = charz_session.clone
|
220
|
+
eof_charz_tests << proc do
|
221
|
+
@charz_session = current_session
|
222
|
+
create_charz_group(options, &block)
|
223
|
+
end
|
224
|
+
else
|
225
|
+
# inline is the default behavior, and eof (end of flow) has built in support.
|
226
|
+
if respond_to?(:"create_#{charz_session.placement}_charz_tests")
|
227
|
+
send(:"create_#{charz_session.placement}_charz_tests", options, &block)
|
228
|
+
elsif respond_to?(:"insert_#{charz_session.placement}_charz_tests")
|
229
|
+
send(:"insert_#{charz_session.placement}_charz_tests", options, &block)
|
230
|
+
else
|
231
|
+
Origen.log.error "No handling specified for #{charz_session.placement} placement charz tests"
|
232
|
+
fail
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# called automatically right after a top_level shutdown, generates end of flow charz tests
|
239
|
+
# user should not have to reference this call explicitly
|
240
|
+
def generate_eof_charz_tests
|
241
|
+
unless eof_charz_tests.empty?
|
242
|
+
if skip_group_eof_charz_tests
|
243
|
+
eof_charz_tests.map(&:call)
|
244
|
+
else
|
245
|
+
group_name = eof_charz_tests_group_name || 'End of Flow Charz Tests'
|
246
|
+
group group_name do
|
247
|
+
eof_charz_tests.map(&:call)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
private
|
254
|
+
|
255
|
+
# called by charz_on, updates the current session, and passes the available routines in for validity checks
|
256
|
+
def update_charz_session(charz_obj, options = {})
|
257
|
+
charz_session.update(charz_obj, options.merge(defined_routines: charz_routines.ids))
|
258
|
+
end
|
259
|
+
|
260
|
+
# called by insert_charz_tests
|
261
|
+
#
|
262
|
+
# if insert_charz_tests was called with the skip group option, then skip to processing the sessions on_result functionality
|
263
|
+
# otherwise, on_result processing occurs within the created group
|
264
|
+
#
|
265
|
+
# group name defaults to <point test name> charz <session name>, but can be set by the user by passing :group_name in the options
|
266
|
+
def create_charz_group(options, &block)
|
267
|
+
if options[:skip_group]
|
268
|
+
process_on_result(options, &block)
|
269
|
+
else
|
270
|
+
group_name = options[:group_name] || "#{options[:parent_test_name]} charz #{charz_session.name}"
|
271
|
+
group group_name.to_sym do
|
272
|
+
process_on_result(options, &block)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
# called by create_charz_group
|
278
|
+
#
|
279
|
+
# Handles the case where the session indicates these charz tests' execution depend on the point test's result
|
280
|
+
# Requires that the id of the point test has been passed to use this functionality. Otherwise, make sure that
|
281
|
+
# charz_session.on_result == nil
|
282
|
+
#
|
283
|
+
# on_fail and on_pass results are built-in, but if the user has a different check to make, it can be handled
|
284
|
+
# by defining the method process_<custom result>_charz_tests
|
285
|
+
#
|
286
|
+
# @see set_conditional_charz_id
|
287
|
+
def process_on_result(options, &block)
|
288
|
+
if charz_session.on_result
|
289
|
+
case charz_session.on_result
|
290
|
+
when :on_fail, :fail, :failed
|
291
|
+
last_test_id = options[:last_test_id] || @last_test_id
|
292
|
+
if_failed last_test_id do
|
293
|
+
process_gates(options, &block)
|
294
|
+
end
|
295
|
+
when :on_pass, :pass, :passed
|
296
|
+
last_test_id = options[:last_test_id] || @last_test_id
|
297
|
+
if_passed last_test_id do
|
298
|
+
process_gates(options, &block)
|
299
|
+
end
|
300
|
+
else
|
301
|
+
if respond_to?(:"process_#{charz_session.placement}_charz_tests")
|
302
|
+
send(:"process_#{charz_session.on_result}_charz_tests", options, &block)
|
303
|
+
else
|
304
|
+
Origen.log.error "No handling specified for result #{charz_session.on_result} charz tests"
|
305
|
+
fail
|
306
|
+
end
|
307
|
+
end
|
308
|
+
else
|
309
|
+
process_gates(options, &block)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
# called by process_on_result
|
314
|
+
#
|
315
|
+
# Handles the case where charz_session.enables or charz_session.flags have been set
|
316
|
+
# referring to enables and flags both as gates, gates can wrap all routines in a session if they're in the form of an
|
317
|
+
# array, symbol, or a string (think of the normal use case of if_enable or if_flag)
|
318
|
+
#
|
319
|
+
# If the gate is a Hash, then that means different routines are getting different gate wrappers.
|
320
|
+
# Also if a routine is not indicated in the values of the gate, then that means that routine should not be gated at all
|
321
|
+
#
|
322
|
+
# This is the final method of handling the insert_charz_test usecases, where the block thats been passed around is finally called
|
323
|
+
# the user's provided block is passed the current routine (one at a time) to then take its info to generate a charz test
|
324
|
+
def process_gates(options, &block)
|
325
|
+
if options[:skip_gates] || !(charz_session.enables || charz_session.flags)
|
326
|
+
charz_session.routines.each do |routine|
|
327
|
+
block.call(options.merge(current_routine: routine))
|
328
|
+
end
|
329
|
+
else
|
330
|
+
if charz_session.enables && charz_session.flags
|
331
|
+
if charz_session.enables.is_a?(Hash) && !charz_session.flags.is_a?(Hash)
|
332
|
+
# wrap all tests in flags, wrap specific tests in enables
|
333
|
+
if_flag charz_session.flags do
|
334
|
+
insert_hash_gates(options, charz_session.enables, :if_enable, &block)
|
335
|
+
end
|
336
|
+
elsif !charz_session.enables.is_a?(Hash) && charz_session.flags.is_a?(Hash)
|
337
|
+
# wrap all tests in enables, wrap specific tests in flags
|
338
|
+
if_enable charz_session.enables do
|
339
|
+
insert_hash_gates(options, charz_session.flags, :if_flag, &block)
|
340
|
+
end
|
341
|
+
elsif charz_session.enables.is_a?(Hash) && charz_session.flags.is_a?(Hash)
|
342
|
+
# first insert the tests that are not tied to an enable or flag gate
|
343
|
+
ungated_routines = charz_session.routines - (charz_session.enables.values.flatten | charz_session.flags.values.flatten)
|
344
|
+
ungated_routines.each do |routine|
|
345
|
+
block.call(options.merge(current_routine: routine))
|
346
|
+
end
|
347
|
+
# wrap tests in an enable gate, flag gate, or both
|
348
|
+
gated_routines = charz_session.routines - ungated_routines
|
349
|
+
gated_routines.each do |routine|
|
350
|
+
enable = charz_session.enables.find { |gates, routines| routines.include?(routine) }&.first
|
351
|
+
flag = charz_session.flags.find { |gates, routines| routines.include?(routine) }&.first
|
352
|
+
if enable && flag
|
353
|
+
if_enable enable do
|
354
|
+
if_flag flag do
|
355
|
+
# wrap test in both enable and flag gate
|
356
|
+
block.call(options.merge(current_routine: routine))
|
357
|
+
end
|
358
|
+
end
|
359
|
+
elsif enable
|
360
|
+
if_enable enable do
|
361
|
+
# enable only
|
362
|
+
block.call(options.merge(current_routine: routine))
|
363
|
+
end
|
364
|
+
elsif flag
|
365
|
+
if_flag flag do
|
366
|
+
# flag only
|
367
|
+
block.call(options.merge(current_routine: routine))
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
else
|
372
|
+
# both enable and flag is set, and both apply to all routines in session
|
373
|
+
if_enable charz_session.enables do
|
374
|
+
if_flag charz_session.flags do
|
375
|
+
charz_session.routines.each do |routine|
|
376
|
+
block.call(options.merge(current_routine: routine))
|
377
|
+
end
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
381
|
+
else
|
382
|
+
# only enables or flags is set, not both
|
383
|
+
if charz_session.enables
|
384
|
+
gates = charz_session.enables
|
385
|
+
gate_method = :if_enable
|
386
|
+
elsif charz_session.flags
|
387
|
+
gates = charz_session.flags
|
388
|
+
gate_method = :if_flag
|
389
|
+
end
|
390
|
+
if gates.is_a?(Hash)
|
391
|
+
# wrap some tests in specific gates
|
392
|
+
insert_hash_gates(options, gates, gate_method, &block)
|
393
|
+
else
|
394
|
+
# wrap all tests in the indicated gates
|
395
|
+
send(gate_method, gates) do
|
396
|
+
charz_session.routines.each do |routine|
|
397
|
+
block.call(options.merge(current_routine: routine))
|
398
|
+
end
|
399
|
+
end
|
400
|
+
end
|
401
|
+
end
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
# helper method for the process gates method above
|
406
|
+
# handles wrapping routines in specific gates, and passing ungated routines back to the user
|
407
|
+
def insert_hash_gates(options, gate_hash, gate_method, &block)
|
408
|
+
ungated_routines = charz_session.routines - gate_hash.values.flatten
|
409
|
+
ungated_routines.each do |routine|
|
410
|
+
block.call(options.merge(current_routine: routine))
|
411
|
+
end
|
412
|
+
gate_hash.each do |gate, gated_routines|
|
413
|
+
send(gate_method, gate) do
|
414
|
+
gated_routines.each do |routine|
|
415
|
+
block.call(options.merge(current_routine: routine))
|
416
|
+
end
|
417
|
+
end
|
418
|
+
end
|
419
|
+
end
|
420
|
+
end
|
421
|
+
end
|
@@ -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
|
@@ -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|
|
@@ -2,6 +2,7 @@ module OrigenTesters
|
|
2
2
|
module Test
|
3
3
|
class Interface
|
4
4
|
include OrigenTesters::ProgramGenerators
|
5
|
+
include OrigenTesters::Charz
|
5
6
|
|
6
7
|
attr_accessor :include_additional_prb2_test
|
7
8
|
attr_reader :environment
|
@@ -10,6 +11,45 @@ module OrigenTesters
|
|
10
11
|
# desired to configure your interface
|
11
12
|
def initialize(options = {})
|
12
13
|
@environment = options[:environment]
|
14
|
+
add_charz
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_charz
|
18
|
+
add_charz_routine :routine1 do |routine|
|
19
|
+
routine.name = '_cz__rt1'
|
20
|
+
end
|
21
|
+
add_charz_routine :routine2 do |routine|
|
22
|
+
routine.name = '_cz__rt2'
|
23
|
+
end
|
24
|
+
add_charz_routine :routine3 do |routine|
|
25
|
+
routine.name = '_cz__rt3'
|
26
|
+
end
|
27
|
+
add_charz_routine :routine4 do |routine|
|
28
|
+
routine.name = '_cz__rt4'
|
29
|
+
end
|
30
|
+
add_charz_routine :routine5 do |routine|
|
31
|
+
routine.name = '_cz__rt5'
|
32
|
+
end
|
33
|
+
add_charz_routine :routine6 do |routine|
|
34
|
+
routine.name = '_cz__rt6'
|
35
|
+
end
|
36
|
+
add_charz_profile :cz do |profile|
|
37
|
+
profile.routines = [:routine3]
|
38
|
+
end
|
39
|
+
add_charz_profile :cz_only do |profile|
|
40
|
+
profile.charz_only = true
|
41
|
+
profile.routines = [:routine1]
|
42
|
+
end
|
43
|
+
add_charz_profile :simple_gates do |profile|
|
44
|
+
profile.flags = :my_flag
|
45
|
+
profile.enables = :my_enable
|
46
|
+
profile.routines = [:routine1]
|
47
|
+
end
|
48
|
+
add_charz_profile :complex_gates do |profile|
|
49
|
+
profile.flags = { ['$MyFlag1'] => [:routine1, :routine2], ['$MyFlag2'] => [:routine3], '$MyFlag3' => :routine4 }
|
50
|
+
profile.enables = { ['$MyEnable1'] => [:routine1], ['$MyEnable2'] => [:routine2, :routine3], '$MyEnable3' => :routine5 }
|
51
|
+
profile.routines = [:routine1, :routine2, :routine3, :routine4, :routine5, :routine6]
|
52
|
+
end
|
13
53
|
end
|
14
54
|
|
15
55
|
# Test that the block form of flow control methods like this can
|
@@ -86,6 +126,46 @@ module OrigenTesters
|
|
86
126
|
end
|
87
127
|
end
|
88
128
|
|
129
|
+
def func_with_charz(name, options = {})
|
130
|
+
options = {
|
131
|
+
duration: :static
|
132
|
+
}.merge(options)
|
133
|
+
|
134
|
+
if tester.v93k?
|
135
|
+
if tester.smt7?
|
136
|
+
tm = test_methods.ac_tml.ac_test.functional_test
|
137
|
+
ts = test_suites.run(name, options)
|
138
|
+
ts.test_method = tm
|
139
|
+
ts.pattern = 'charz_example'
|
140
|
+
|
141
|
+
test_level_charz = false
|
142
|
+
if options[:charz]
|
143
|
+
charz_on(*options[:charz])
|
144
|
+
test_level_charz = true
|
145
|
+
end
|
146
|
+
|
147
|
+
unless charz_only? && !options[:charz_test]
|
148
|
+
options[:parent_test_name] = name
|
149
|
+
set_conditional_charz_id(options)
|
150
|
+
flow.test ts, options
|
151
|
+
end
|
152
|
+
|
153
|
+
unless options[:charz_test]
|
154
|
+
insert_charz_tests(options.merge(parent_test_name: name, charz_test: true)) do |options|
|
155
|
+
charz_name = :"#{name}_#{charz_routines[options[:current_routine]].name}"
|
156
|
+
func_with_charz(charz_name, options)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
charz_off if test_level_charz
|
161
|
+
else
|
162
|
+
fail 'Only SMT7 is Implemented for Charz'
|
163
|
+
end
|
164
|
+
else
|
165
|
+
fail "Tester #{tester.name} Not Yet Implemented for Charz"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
89
169
|
def func_with_comment(name, options = {})
|
90
170
|
if tester.v93k?
|
91
171
|
options = {
|
data/program/charz.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# An instance of the interface is
|
2
|
+
# passed in here, iterators and other
|
3
|
+
# argument passing will be supported
|
4
|
+
# similar to Pattern.create.
|
5
|
+
Flow.create interface: 'OrigenTesters::Test::Interface' do
|
6
|
+
flow.flow_description = '' if tester.v93k?
|
7
|
+
|
8
|
+
if tester.v93k? && tester.smt7?
|
9
|
+
charz_on :complex_gates, { on_result: :fail }
|
10
|
+
func_with_charz :func_complex_gates_on_fail
|
11
|
+
charz_off
|
12
|
+
|
13
|
+
charz_on :complex_gates, { enables: :my_enable }
|
14
|
+
func_with_charz :func_complex_flag_simple_enable
|
15
|
+
charz_off
|
16
|
+
|
17
|
+
charz_on :complex_gates, { flags: :my_flag } do
|
18
|
+
func_with_charz :func_complex_enable_simple_flag
|
19
|
+
end
|
20
|
+
|
21
|
+
charz_on :cz_only, { placement: :eof }
|
22
|
+
func_with_charz :func_charz_only
|
23
|
+
charz_off
|
24
|
+
|
25
|
+
func_with_charz :func_test_level_routine, charz: [:routine1, { type: :routine }]
|
26
|
+
|
27
|
+
charz_on :cz
|
28
|
+
func_with_charz :func_skip_group, skip_group: true
|
29
|
+
charz_pause
|
30
|
+
func_with_charz :func_pause_charz
|
31
|
+
charz_resume
|
32
|
+
func_with_charz :func_resume_charz
|
33
|
+
charz_off
|
34
|
+
|
35
|
+
charz_on :simple_gates, { on_result: :pass } do
|
36
|
+
func_with_charz :func_simple_gates_on_pass
|
37
|
+
end
|
38
|
+
|
39
|
+
charz_on :simple_gates, { enables: nil }
|
40
|
+
func_with_charz :func_simple_flags
|
41
|
+
charz_off
|
42
|
+
|
43
|
+
charz_on :simple_gates, { flags: nil }
|
44
|
+
func_with_charz :func_simple_enables
|
45
|
+
charz_off
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
% render "layouts/guides.html" do
|
2
|
+
|
3
|
+
Be sure to read and understand the guide to
|
4
|
+
[Creating an Interface](<%= path "guides/program/interface" %>) before
|
5
|
+
reading this guide.
|
6
|
+
This guide covers aspects of the Characterization (charz) API.
|
7
|
+
|
8
|
+
Currently, the charz API has only been proven out for V93K SMT7, but isn't inherently designed around working only for that environment.
|
9
|
+
|
10
|
+
The Charz API is enabled by including the Charz module in your interface:
|
11
|
+
|
12
|
+
~~~ruby
|
13
|
+
# app/lib/my_app/interface.rb
|
14
|
+
module MyApp
|
15
|
+
class Interface
|
16
|
+
include OrigenTesters::ProgramGenerators
|
17
|
+
include OrigenTesters::Charz
|
18
|
+
~~~
|
19
|
+
|
20
|
+
Note this guide assumes the audience is familiar with interface creation and custom test methods, and will not go into detail explaining those topics.
|
21
|
+
|
22
|
+
## Overview
|
23
|
+
|
24
|
+
The Characterization API allows a flow to add characterization to existing production tests with little additional overhead.
|
25
|
+
|
26
|
+
First specify charz routines to set charz test options, then create a profile with flow creation meta for the resulting tests.
|
27
|
+
Afterwards, the `charz_on` method can be called in the flow to activate charz profiles, which is explained below.
|
28
|
+
|
29
|
+
### Charz Routines
|
30
|
+
|
31
|
+
Charz routines contain relevant charz data thats specific to a charz test to be created. Created routines are stored in the `@charz_routines` attribute.
|
32
|
+
The data stored within a routine will be used in combination with the options used to make a production test to make a charz variant of the production test.
|
33
|
+
|
34
|
+
The interface adds charz routines by calling the `add_charz_routine` method:
|
35
|
+
|
36
|
+
~~~ruby
|
37
|
+
add_charz_routine :vmin do |routine|
|
38
|
+
routine.name = 'cz_vmin_vdd'
|
39
|
+
routine.start = 1.0.V
|
40
|
+
routine.stop = 0.5.V
|
41
|
+
routine.res = 5.mV
|
42
|
+
routine.spec = 'VDD'
|
43
|
+
end
|
44
|
+
~~~
|
45
|
+
|
46
|
+
### Charz Profiles
|
47
|
+
|
48
|
+
Charz profiles contain a collection of routines, as well as test creation meta data related to test placement, production test result dependence, and conditional execution.
|
49
|
+
|
50
|
+
The interface adds charz profiles by calling the `add_charz_profile` method. To create a profile that contains previously defined vmin and vmax search routines, whose resulting searches
|
51
|
+
only run if the production test failed, and sets the vmax search routine to only run if the 'VmaxEnable' variable is set:
|
52
|
+
|
53
|
+
~~~ruby
|
54
|
+
add_charz_profile :fail_searches do |profile|
|
55
|
+
profile.name = 'fail_searches'
|
56
|
+
profile.on_result = :on_fail
|
57
|
+
profile.routines = [:vmin, :vmax]
|
58
|
+
profile.enables = { ['$VmaxEnable'] => [:vmax] }
|
59
|
+
end
|
60
|
+
~~~
|
61
|
+
|
62
|
+
### Charz Session
|
63
|
+
|
64
|
+
The charz session (stored in your interfaces `@charz_session` attribute) monitors the current state of characterization at a given point in flow generation.
|
65
|
+
|
66
|
+
The API provides some key methods for querying that state during generation, such as:
|
67
|
+
|
68
|
+
* `charz_active?` : indicates if applicable productions tests should be generating charz tests as well
|
69
|
+
* `charz_only?` : indicates if the production tests should be added to the flow or not, only generating the resulting charz test
|
70
|
+
|
71
|
+
## Interface Considerations
|
72
|
+
|
73
|
+
A couple of enhancements will need to be added to your interface to take advantage of the API in addition to adding `include OrigenTesters::Charz` as shown above.
|
74
|
+
The charz routines and profiles will need to be added, and your flow methods will need to be updated to know what to do when a charz session is active.
|
75
|
+
|
76
|
+
### Adding charz routines and profiles
|
77
|
+
|
78
|
+
As long as the desired routines and profiles exist in the interface's @charz_routines and @charz_profiles hashes, the rest of the API will work as expected.
|
79
|
+
One option is to add them during the interface initialization:
|
80
|
+
|
81
|
+
~~~ruby
|
82
|
+
# app/lib/my_app/interface.rb
|
83
|
+
module MyApp
|
84
|
+
class Interface
|
85
|
+
include OrigenTesters::ProgramGenerators
|
86
|
+
include OrigenTesters::Charz
|
87
|
+
|
88
|
+
def add_charz
|
89
|
+
add_charz_routine :my_routine do |routine|
|
90
|
+
routine.name = 'cz_vmin_vdd'
|
91
|
+
routine.start = 1.0.V
|
92
|
+
routine.stop = 0.5.V
|
93
|
+
routine.res = 5.mV
|
94
|
+
routine.spec = 'VDD'
|
95
|
+
end
|
96
|
+
add_charz_profile :my_profile do |profile|
|
97
|
+
profile.name = 'vmin_search'
|
98
|
+
profile.routines = [:vmin]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def initialize(options = {})
|
103
|
+
add_charz
|
104
|
+
end
|
105
|
+
~~~
|
106
|
+
|
107
|
+
### Configuring Existing Flow Methods
|
108
|
+
|
109
|
+
Now that your interface has defined some routines and profiles, the flow methods needs to be updated to work with an active charz session.
|
110
|
+
|
111
|
+
Lets take a simplistic example functional flow method defined in `MyApp::Interface`:
|
112
|
+
|
113
|
+
~~~ruby
|
114
|
+
# V93K SMT7 example
|
115
|
+
def func(name, options = {})
|
116
|
+
tm = test_methods.ac_tml.ac_test.functional_test
|
117
|
+
ts = test_suites.run(name, options)
|
118
|
+
ts.test_method = tm
|
119
|
+
ts.pattern = 'example'
|
120
|
+
flow.test ts, options
|
121
|
+
end
|
122
|
+
~~~
|
123
|
+
|
124
|
+
And now we'll add the ability for this flow method to generate a charz test as well:
|
125
|
+
|
126
|
+
~~~ruby
|
127
|
+
# V93K SMT7 example
|
128
|
+
def func(name, options = {})
|
129
|
+
if options[:routine]
|
130
|
+
tm = test_methods.ac_tml.ac_test.spec_search
|
131
|
+
else
|
132
|
+
tm = test_methods.ac_tml.ac_test.functional_test
|
133
|
+
end
|
134
|
+
ts = test_suites.run(name, options)
|
135
|
+
ts.test_method = tm
|
136
|
+
ts.pattern = 'example'
|
137
|
+
|
138
|
+
if options[:routine]
|
139
|
+
ts.spec = options[:routine].spec
|
140
|
+
ts.min = options[:routine].stop
|
141
|
+
ts.max = options[:routine].start
|
142
|
+
ts.resolution = options[:routine].res
|
143
|
+
end
|
144
|
+
|
145
|
+
flow.test ts, options
|
146
|
+
|
147
|
+
unless options[:charz_test]
|
148
|
+
insert_charz_tests(options.merge(parent_test_name: name, charz_test: true)) do |options|
|
149
|
+
charz_name = :"#{name}_#{charz_routines[options[:current_routine]].name}"
|
150
|
+
options[:routine] = charz_routines[options[:current_routine]]
|
151
|
+
func(charz_name, options)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
~~~
|
156
|
+
|
157
|
+
### #insert_charz_tests
|
158
|
+
|
159
|
+
The `insert_charz_tests` method handles everything regarding adding the charz test into the flow except determining the actual name and parameters of the test, which is
|
160
|
+
done by the local interface in the block passed to the `insert_charz_tests` method. This method handles:
|
161
|
+
|
162
|
+
* querying the charz session
|
163
|
+
* test placement
|
164
|
+
* charz test grouping
|
165
|
+
* production test result dependency
|
166
|
+
* gate processing (enables, flags)
|
167
|
+
|
168
|
+
The block that gets passed is yielded the latest options (with id removed if passed for the production test, so it doesn't get re-used for charz tests).
|
169
|
+
Routines in the current session are yielded one at a time, with their id being returned in `options[:current_routine]`.
|
170
|
+
|
171
|
+
#### Company Plugin Oppurtunity
|
172
|
+
|
173
|
+
If your company is already using a plugin to distribute the definitions of these flow methods, this is a good oppurtunity to add charz variants of those methods
|
174
|
+
that take routine as an input. This can really streamline the process, for example if you combine the charz flow methods plugin with a central flow entry point method called by
|
175
|
+
all flow methods, then the implementation becomes:
|
176
|
+
|
177
|
+
~~~ruby
|
178
|
+
def add_to_flow(ts, options = {})
|
179
|
+
flow.test ts, options
|
180
|
+
|
181
|
+
unless options[:charz_test]
|
182
|
+
insert_charz_tests(options.merge(parent_test_name: name, charz_test: true)) do |options|
|
183
|
+
insert_current_charz_test(options)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
~~~
|
188
|
+
|
189
|
+
Where insert_current_charz_test is a method defined in the company charz flow method plugin.
|
190
|
+
|
191
|
+
### Flow Usage Examples
|
192
|
+
|
193
|
+
Now that the interface has charz routines and profiles, lets look at how to use the API within the flow itself:
|
194
|
+
|
195
|
+
~~~ruby
|
196
|
+
Flow.create(interface: 'MyApp:Interface') do
|
197
|
+
|
198
|
+
# regular non charz test
|
199
|
+
func :my_test1
|
200
|
+
|
201
|
+
# create charz test variants of my_test2 following the production
|
202
|
+
# version of my_test2 using the routines in :my_profile
|
203
|
+
charz_on :my_profile do
|
204
|
+
func :my_test2
|
205
|
+
end
|
206
|
+
|
207
|
+
# conditional charz enablement
|
208
|
+
# besides dut.enable_charz? check, identical to above
|
209
|
+
charz_on :my_profile if dut.enable_charz?
|
210
|
+
func :my_test3
|
211
|
+
charz_off if dut.enable_charz?
|
212
|
+
|
213
|
+
# override session values at the flow level
|
214
|
+
charz_on :my_profile, placement: :eof do
|
215
|
+
func :my_test4
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
219
|
+
~~~
|
220
|
+
|
221
|
+
% 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.48.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: 2020-08-
|
11
|
+
date: 2020-08-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: origen
|
@@ -16,14 +16,42 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.57.1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.57.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: simplecov
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.17'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.17'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: simplecov-html
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.10.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.10.0
|
27
55
|
- !ruby/object:Gem::Dependency
|
28
56
|
name: require_all
|
29
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -175,6 +203,12 @@ files:
|
|
175
203
|
- lib/origen_testers/atp_deprecation.rb
|
176
204
|
- lib/origen_testers/basic_test_setups.rb
|
177
205
|
- lib/origen_testers/callback_handlers.rb
|
206
|
+
- lib/origen_testers/charz.rb
|
207
|
+
- lib/origen_testers/charz/profile.rb
|
208
|
+
- lib/origen_testers/charz/routine.rb
|
209
|
+
- lib/origen_testers/charz/routines/search_routine.rb
|
210
|
+
- lib/origen_testers/charz/routines/shmoo_routine.rb
|
211
|
+
- lib/origen_testers/charz/session.rb
|
178
212
|
- lib/origen_testers/command_based_tester.rb
|
179
213
|
- lib/origen_testers/decompiler.rb
|
180
214
|
- lib/origen_testers/decompiler/decompiler_api.rb
|
@@ -474,6 +508,7 @@ files:
|
|
474
508
|
- program/_erase_vfy.rb
|
475
509
|
- program/_iv_resources.rb
|
476
510
|
- program/basic_interface.rb
|
511
|
+
- program/charz.rb
|
477
512
|
- program/components/_deep_nested.rb
|
478
513
|
- program/components/_prb1_main.rb
|
479
514
|
- program/components/_prb2_main.rb
|
@@ -509,6 +544,7 @@ files:
|
|
509
544
|
- templates/origen_guides/pattern/timing.md.erb
|
510
545
|
- templates/origen_guides/pattern/ultraflex.md.erb
|
511
546
|
- templates/origen_guides/pattern/v93k.md.erb
|
547
|
+
- templates/origen_guides/program/charz.md.erb
|
512
548
|
- templates/origen_guides/program/code.md.erb
|
513
549
|
- templates/origen_guides/program/custom.md.erb
|
514
550
|
- templates/origen_guides/program/doc.md.erb
|
@@ -549,7 +585,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
549
585
|
version: '0'
|
550
586
|
requirements: []
|
551
587
|
rubyforge_project:
|
552
|
-
rubygems_version: 2.
|
588
|
+
rubygems_version: 2.6.14.4
|
553
589
|
signing_key:
|
554
590
|
specification_version: 4
|
555
591
|
summary: This plugin provides Origen tester models to drive ATE type testers like
|