origen_testers 0.45.4 → 0.48.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 1b76b067afa328f7b2510afb5208e8171f7bec61740a81eda88304e7e4bcd5fe
4
- data.tar.gz: a66d71937a817171248d7bd496bee8208e2482b6f3cc0db19eb0b5375e46726e
2
+ SHA1:
3
+ metadata.gz: 4d062217b6f69bd8190818c2b24c2574bb163dab
4
+ data.tar.gz: 9b139b2ef824933744d66c817baba75524ff7d3b
5
5
  SHA512:
6
- metadata.gz: 7c832106032077a4d59ed06c3d4909d7847b0b65e9a953e8f8d7f8709baae25d6d2647117c080e4994b5b16f6fd1a59cedc9a7723e5648e7c3beb5e3e7714df3
7
- data.tar.gz: bc1837f05d87eaf7bb8c3640068e754468dcd23142e15f74ad68cf17e78f12d3f03ff4f6d77fe2da444f4ddd7f1d20cb533f2a6966801438c5077a8c613eca71
6
+ metadata.gz: 5f0e2c810aa3f8826897a16099274fc65d307c1650dab5d60ca9d3ef84da37e390932d3802c5e4980f81304cefff12b6b31de53ee798ad132f9e708cc3aa03df
7
+ data.tar.gz: b1bf66931f6056f6ae314715b7e9b368534cb13b5a4bed46e364f2318e80fe57d07fd50e071adc158b8d29a3129ab49ecb724e16fa52e3e344dcd379d21b9413
@@ -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 = 45
4
- BUGFIX = 4
3
+ MINOR = 48
4
+ BUGFIX = 1
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