origen_testers 0.46.0 → 0.48.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7360238666a0fc1e9b4c102d2a37848d405fe98517409bdb831cda332981a13c
4
- data.tar.gz: c92ae39d1a231092b5369e218e339fce91b1d64a7550373c34483ea380fd7785
3
+ metadata.gz: 55301a17d683ca18d323223ba90def92f9d4696152f160e2cd48f6a60f34fa01
4
+ data.tar.gz: 1049c5cd883d006bba7702acf5090355de254c3e44e8ff76b391b9a10a610199
5
5
  SHA512:
6
- metadata.gz: 82fda3ff54f95ccb5b50f668fc0a9a6488171a0f3b855e58381385f1a68d619da71a815c74c9a46ed7443122a6d78606415e4ba191dc6ecca28b358b94a7c8ec
7
- data.tar.gz: 64c3c447fc4828c2714ea84df9af17af9d35e000c10afd51675edccf6935dbbcb184669cb3b36e7f5b7c42261e2a3c504066ad440b2ef4b4db721fd94ef9a681
6
+ metadata.gz: c8065dab6a6d37ae9c6e8346c6cba7c4a95be66360edfb667727921f85e5ba712172b5266bb7eba4280426c70294342fdea1d6b17fc79997c92e5dab3f3a3bbd
7
+ data.tar.gz: f52e174c381f347ae489a5c5cced814a844675b5ee0b13f33e7cf2d7c43617efbfe2dffe51818eafa3a63655eb1e749486974776b86dcfe467f22553331a6922
@@ -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"
@@ -1,7 +1,7 @@
1
1
  module OrigenTesters
2
2
  MAJOR = 0
3
- MINOR = 46
4
- BUGFIX = 0
3
+ MINOR = 48
4
+ BUGFIX = 2
5
5
  DEV = nil
6
6
  VERSION = [MAJOR, MINOR, BUGFIX].join(".") + (DEV ? ".pre#{DEV}" : '')
7
7
  end
@@ -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
 
@@ -408,6 +408,10 @@ module OrigenTesters::ATP
408
408
  children << n(:meta, attrs)
409
409
  end
410
410
 
411
+ if options[:test_text]
412
+ children << n(:test_text, [options[:test_text]])
413
+ end
414
+
411
415
  if subs = options[:sub_test] || options[:sub_tests]
412
416
  subs = [subs] unless subs.is_a?(Array)
413
417
  subs.each do |s|
@@ -0,0 +1,434 @@
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
+ # To use your own Routine classes, override the create_charz_routine method in your interface
48
+ #
49
+ # @example create a 1d search routine that searches vdd, from 900mv to 300mv, resolution of 5mv
50
+ # add_charz_routine :my_routine, type: search do |rt|
51
+ # rt.start = 900.mv
52
+ # rt.stop = 300.mv
53
+ # rt.res = 5.mv
54
+ # rt.spec = 'vdd'
55
+ # end
56
+ #
57
+ # @param [Symbol] id charz_routine id, will be the key value in the @charz_routines hash. Must not have been previously used
58
+ # @param [Hash] options charz_routine options
59
+ # @option options [Symbol] :type :search or :'1d' will create a SearchRoutine, :shmoo or :'2d' will create a ShmooRoutine, nil will create a Routine
60
+ def add_charz_routine(id, options = {}, &block)
61
+ if charz_routines.ids.include?(id)
62
+ Origen.log.error("Cannot create charz routine '#{id}', it already exists!")
63
+ fail
64
+ end
65
+ charz_routines[id] = create_charz_routine(id, options, &block)
66
+ end
67
+
68
+ # Called by add_charz_routine, split out from that method to make it easier to override this handler from a user's interface
69
+ # This is the method to override if you want to use custom Routines specifc to your company's implementation
70
+ #
71
+ # @param [Symbol] id charz_routine id, will be the key value in the @charz_routines hash. Must not have been previously used
72
+ # @param [Hash] options charz_routine options
73
+ # @option options [Symbol] :type :search or :'1d' will create a SearchRoutine, :shmoo or :'2d' will create a ShmooRoutine, nil will create a Routine
74
+ # @return [Routine] a charz routine object
75
+ def create_charz_routine(id, options = {}, &block)
76
+ case options[:type]
77
+ when :search, :'1d'
78
+ SearchRoutine.new(id, options, &block)
79
+ when :shmoo, :'2d'
80
+ ShmooRoutine.new(id, options, &block)
81
+ else
82
+ Routine.new(id, options, &block)
83
+ end
84
+ end
85
+
86
+ # Add a new charz profile to @charz_profiles
87
+ # A charz profile is a collection of one or more charz routines, as well as flow control and placement data for
88
+ # the charz tests generated by those routines
89
+ #
90
+ # @example create a profile containing 2 routines, end of flow placement, whose tests are only ran if the parent fails
91
+ # add_charz_profile :my_profile do |prof|
92
+ # prof.routines = [:my_routine1, :my_routine2]
93
+ # prof.placement = :eof
94
+ # prof.on_result = :on_fail
95
+ # end
96
+ #
97
+ # @param [Symbol] id charz_profile id, will be the key value in the @charz_profiles hash. Must not have been previously used
98
+ # @param [Hash] options charz_profile options
99
+ def add_charz_profile(id, options = {}, &block)
100
+ if charz_profiles.ids.include?(id)
101
+ Origen.log.error("Cannot create charz profile '#{id}', it already exists!")
102
+ fail
103
+ end
104
+ charz_profiles[id] = Profile.new(id, options.merge(defined_routines: charz_routines.ids), &block)
105
+ end
106
+
107
+ # Queries the current charz session to see if its active, indicating point tests should be generating charz tests
108
+ def charz_active?
109
+ charz_session.active
110
+ end
111
+
112
+ # Queries the current charz session to see if point tests should skip generation, only adding the resulting charz test
113
+ def charz_only?
114
+ charz_active? && charz_session.charz_only
115
+ end
116
+
117
+ # Pauses the current charz session, preventing point tests from generating charz tests even if the session is valid
118
+ def charz_pause
119
+ charz_session.pause
120
+ end
121
+
122
+ # Resumes the current charz session. If the session isn't valid (ie charz_resume before setting up the session) then nothing will happen
123
+ def charz_resume
124
+ charz_session.resume
125
+ end
126
+
127
+ # Removes the current session generating data off the charz stack
128
+ # If charz data is still on the stack afterward, the session will update to reflect the new data
129
+ # if not, the session will become inactive
130
+ def charz_off
131
+ charz_stack.pop
132
+ if charz_stack.empty?
133
+ update_charz_session(nil)
134
+ else
135
+ update_charz_session(*charz_stack.last)
136
+ end
137
+ end
138
+
139
+ # Pushes a charz object (either a profile or a routine) onto the stack, along with any optional updates to modify the current session
140
+ # Once pushed, the charz_session will attempt to update itself with the new data, failing if the resulting session is invalid
141
+ #
142
+ # If a block is passed, yield the block of tests to enable charz for those tests, then disable charz with a charz_off call
143
+ #
144
+ # @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
145
+ # @param [Hash] options charz_on options
146
+ # @option options [Symbol] :type (:profile) whether the charz_id refers to a charz profile or routine
147
+ def charz_on(charz_id, options = {})
148
+ options = {
149
+ type: :profile
150
+ }.merge(options)
151
+ case options[:type]
152
+ when :profile
153
+ charz_obj = charz_profiles[charz_id]
154
+ when :routine
155
+ if charz_id.is_a?(Array)
156
+ charz_obj = charz_routines[charz_id.first]
157
+ options[:routines] = charz_id
158
+ else
159
+ charz_obj = charz_routines[charz_id]
160
+ options[:routines] = [charz_id]
161
+ end
162
+ else
163
+ Origen.log.error "Unknown charz object type #{options[:type]}, valid types: :profile, :routine"
164
+ fail
165
+ end
166
+ if charz_obj.nil?
167
+ Origen.log.error "No #{options[:type]} found for charz_id: #{charz_id}"
168
+ fail
169
+ end
170
+ charz_stack.push([charz_obj, options])
171
+ unless update_charz_session(*charz_stack.last)
172
+ Origen.log.error 'charz_on failed to create a valid charz session'
173
+ fail
174
+ end
175
+ if block_given?
176
+ yield
177
+ charz_off
178
+ end
179
+ end
180
+
181
+ # 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
182
+ # @param [Hash] options the options for a test before its created and added to the flow
183
+ # @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
184
+ def set_conditional_charz_id(*args)
185
+ case args.size
186
+ when 1
187
+ options = args[0]
188
+ parent_test_name = options[:parent_test_name]
189
+ when 2
190
+ instance = args[0]
191
+ options = args[1]
192
+ parent_test_name = instance.name
193
+ else
194
+ Origen.log.error 'Too many arguments passed to set_conditional_charz_id. Pass either (test_instance, options), or just (options)'
195
+ fail
196
+ end
197
+ unless options[:id]
198
+ if charz_active?
199
+ if charz_session.on_result
200
+ options[:id] = "#{parent_test_name}_charz_#{charz_session.name}".to_sym
201
+ end
202
+ end
203
+ end
204
+ end
205
+
206
+ # Called after the relevant point test has been inserted into the flow
207
+ # Takes the options used to build the previous point test as well as insert_charz_test specific options to then
208
+ # 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
209
+ # interface to handle creating and inserting the test
210
+ #
211
+ # By default, this method will handle:
212
+ # - the placement of the test (inline aka right after the point test, end of flow, or other)
213
+ # - wrapping the created charz tests in a group (skippable, group name defaults to <point test name> charz <session name>)
214
+ # - conditionally executing the charz tests based on if the point test passed or failed (see set_conditional_charz_id)
215
+ # - conditionally executing some/all charz tests based on a mix of enables and flags
216
+ #
217
+ # After the above is determined, the user regains control on a per-routine (if multiple routines) basis to then process generating the charz test
218
+ def insert_charz_tests(options, &block)
219
+ if charz_active?
220
+ if options[:id]
221
+ # two purposes:
222
+ # 1) prevent all charz tests inadverntently using the same ID as their parent
223
+ # 2) used in on_result behavior
224
+ current_id = options.delete(:id)
225
+ options[:last_test_id] ||= current_id
226
+ end
227
+ case charz_session.placement
228
+ when :inline
229
+ create_charz_group(options, &block)
230
+ when :eof
231
+ # collect the current session and options into a proc, stored in eof_charz_tests to be called later
232
+ current_session = charz_session.clone
233
+ eof_charz_tests << proc do
234
+ @charz_session = current_session
235
+ create_charz_group(options, &block)
236
+ end
237
+ else
238
+ # inline is the default behavior, and eof (end of flow) has built in support.
239
+ if respond_to?(:"create_#{charz_session.placement}_charz_tests")
240
+ send(:"create_#{charz_session.placement}_charz_tests", options, &block)
241
+ elsif respond_to?(:"insert_#{charz_session.placement}_charz_tests")
242
+ send(:"insert_#{charz_session.placement}_charz_tests", options, &block)
243
+ else
244
+ Origen.log.error "No handling specified for #{charz_session.placement} placement charz tests"
245
+ fail
246
+ end
247
+ end
248
+ end
249
+ end
250
+
251
+ # called automatically right after a top_level shutdown, generates end of flow charz tests
252
+ # user should not have to reference this call explicitly
253
+ def generate_eof_charz_tests
254
+ unless eof_charz_tests.empty?
255
+ if skip_group_eof_charz_tests
256
+ eof_charz_tests.map(&:call)
257
+ else
258
+ group_name = eof_charz_tests_group_name || 'End of Flow Charz Tests'
259
+ group group_name do
260
+ eof_charz_tests.map(&:call)
261
+ end
262
+ end
263
+ end
264
+ end
265
+
266
+ private
267
+
268
+ # called by charz_on, updates the current session, and passes the available routines in for validity checks
269
+ def update_charz_session(charz_obj, options = {})
270
+ charz_session.update(charz_obj, options.merge(defined_routines: charz_routines.ids))
271
+ end
272
+
273
+ # called by insert_charz_tests
274
+ #
275
+ # if insert_charz_tests was called with the skip group option, then skip to processing the sessions on_result functionality
276
+ # otherwise, on_result processing occurs within the created group
277
+ #
278
+ # group name defaults to <point test name> charz <session name>, but can be set by the user by passing :group_name in the options
279
+ def create_charz_group(options, &block)
280
+ if options[:skip_group]
281
+ process_on_result(options, &block)
282
+ else
283
+ group_name = options[:group_name] || "#{options[:parent_test_name]} charz #{charz_session.name}"
284
+ group group_name.to_sym do
285
+ process_on_result(options, &block)
286
+ end
287
+ end
288
+ end
289
+
290
+ # called by create_charz_group
291
+ #
292
+ # Handles the case where the session indicates these charz tests' execution depend on the point test's result
293
+ # Requires that the id of the point test has been passed to use this functionality. Otherwise, make sure that
294
+ # charz_session.on_result == nil
295
+ #
296
+ # on_fail and on_pass results are built-in, but if the user has a different check to make, it can be handled
297
+ # by defining the method process_<custom result>_charz_tests
298
+ #
299
+ # @see set_conditional_charz_id
300
+ def process_on_result(options, &block)
301
+ if charz_session.on_result
302
+ case charz_session.on_result
303
+ when :on_fail, :fail, :failed
304
+ last_test_id = options[:last_test_id] || @last_test_id
305
+ if_failed last_test_id do
306
+ process_gates(options, &block)
307
+ end
308
+ when :on_pass, :pass, :passed
309
+ last_test_id = options[:last_test_id] || @last_test_id
310
+ if_passed last_test_id do
311
+ process_gates(options, &block)
312
+ end
313
+ else
314
+ if respond_to?(:"process_#{charz_session.placement}_charz_tests")
315
+ send(:"process_#{charz_session.on_result}_charz_tests", options, &block)
316
+ else
317
+ Origen.log.error "No handling specified for result #{charz_session.on_result} charz tests"
318
+ fail
319
+ end
320
+ end
321
+ else
322
+ process_gates(options, &block)
323
+ end
324
+ end
325
+
326
+ # called by process_on_result
327
+ #
328
+ # Handles the case where charz_session.enables or charz_session.flags have been set
329
+ # referring to enables and flags both as gates, gates can wrap all routines in a session if they're in the form of an
330
+ # array, symbol, or a string (think of the normal use case of if_enable or if_flag)
331
+ #
332
+ # If the gate is a Hash, then that means different routines are getting different gate wrappers.
333
+ # Also if a routine is not indicated in the values of the gate, then that means that routine should not be gated at all
334
+ #
335
+ # This is the final method of handling the insert_charz_test usecases, where the block thats been passed around is finally called
336
+ # the user's provided block is passed the current routine (one at a time) to then take its info to generate a charz test
337
+ def process_gates(options, &block)
338
+ if options[:skip_gates] || !(charz_session.enables || charz_session.flags)
339
+ charz_session.routines.each do |routine|
340
+ block.call(options.merge(current_routine: routine))
341
+ end
342
+ else
343
+ if charz_session.enables && charz_session.flags
344
+ if charz_session.enables.is_a?(Hash) && !charz_session.flags.is_a?(Hash)
345
+ # wrap all tests in flags, wrap specific tests in enables
346
+ if_flag charz_session.flags do
347
+ insert_hash_gates(options, charz_session.enables, :if_enable, &block)
348
+ end
349
+ elsif !charz_session.enables.is_a?(Hash) && charz_session.flags.is_a?(Hash)
350
+ # wrap all tests in enables, wrap specific tests in flags
351
+ if_enable charz_session.enables do
352
+ insert_hash_gates(options, charz_session.flags, :if_flag, &block)
353
+ end
354
+ elsif charz_session.enables.is_a?(Hash) && charz_session.flags.is_a?(Hash)
355
+ # first insert the tests that are not tied to an enable or flag gate
356
+ ungated_routines = charz_session.routines - (charz_session.enables.values.flatten | charz_session.flags.values.flatten)
357
+ ungated_routines.each do |routine|
358
+ block.call(options.merge(current_routine: routine))
359
+ end
360
+ # wrap tests in an enable gate, flag gate, or both
361
+ gated_routines = charz_session.routines - ungated_routines
362
+ gated_routines.each do |routine|
363
+ enable = charz_session.enables.find { |gates, routines| routines.include?(routine) }&.first
364
+ flag = charz_session.flags.find { |gates, routines| routines.include?(routine) }&.first
365
+ if enable && flag
366
+ if_enable enable do
367
+ if_flag flag do
368
+ # wrap test in both enable and flag gate
369
+ block.call(options.merge(current_routine: routine))
370
+ end
371
+ end
372
+ elsif enable
373
+ if_enable enable do
374
+ # enable only
375
+ block.call(options.merge(current_routine: routine))
376
+ end
377
+ elsif flag
378
+ if_flag flag do
379
+ # flag only
380
+ block.call(options.merge(current_routine: routine))
381
+ end
382
+ end
383
+ end
384
+ else
385
+ # both enable and flag is set, and both apply to all routines in session
386
+ if_enable charz_session.enables do
387
+ if_flag charz_session.flags do
388
+ charz_session.routines.each do |routine|
389
+ block.call(options.merge(current_routine: routine))
390
+ end
391
+ end
392
+ end
393
+ end
394
+ else
395
+ # only enables or flags is set, not both
396
+ if charz_session.enables
397
+ gates = charz_session.enables
398
+ gate_method = :if_enable
399
+ elsif charz_session.flags
400
+ gates = charz_session.flags
401
+ gate_method = :if_flag
402
+ end
403
+ if gates.is_a?(Hash)
404
+ # wrap some tests in specific gates
405
+ insert_hash_gates(options, gates, gate_method, &block)
406
+ else
407
+ # wrap all tests in the indicated gates
408
+ send(gate_method, gates) do
409
+ charz_session.routines.each do |routine|
410
+ block.call(options.merge(current_routine: routine))
411
+ end
412
+ end
413
+ end
414
+ end
415
+ end
416
+ end
417
+
418
+ # helper method for the process gates method above
419
+ # handles wrapping routines in specific gates, and passing ungated routines back to the user
420
+ def insert_hash_gates(options, gate_hash, gate_method, &block)
421
+ ungated_routines = charz_session.routines - gate_hash.values.flatten
422
+ ungated_routines.each do |routine|
423
+ block.call(options.merge(current_routine: routine))
424
+ end
425
+ gate_hash.each do |gate, gated_routines|
426
+ send(gate_method, gate) do
427
+ gated_routines.each do |routine|
428
+ block.call(options.merge(current_routine: routine))
429
+ end
430
+ end
431
+ end
432
+ end
433
+ end
434
+ end