• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Origen-SDK / origen_testers / 16890580354

11 Aug 2025 07:53PM UTC coverage: 87.679% (+0.009%) from 87.67%
16890580354

push

github

rlaj
lint

1 of 1 new or added line in 1 file covered. (100.0%)

52 existing lines in 3 files now uncovered.

13200 of 15055 relevant lines covered (87.68%)

9387.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.11
/lib/origen_testers/test/interface.rb
1
module OrigenTesters
6✔
2
  module Test
6✔
3
    class Interface
6✔
4
      include OrigenTesters::ProgramGenerators
6✔
5
      include OrigenTesters::Charz
6✔
6

7
      attr_accessor :include_additional_prb2_test
6✔
8
      attr_reader :environment
6✔
9

10
      # Options passed to Flow.create and Library.create will be passed in here, use as
11
      # desired to configure your interface
12
      def initialize(options = {})
6✔
13
        @environment = options[:environment]
600✔
14
        add_charz
600✔
15
        add_my_tml if tester.v93k?
600✔
16
      end
17

18
      def add_my_tml
6✔
19
        add_tml :my_hash_tml,
462✔
20
                class_name:   'MyTmlHashNamespace',
21

22
                # Here is a test definition.
23
                # The identifier should be lower-cased and underscored, in-keeping with Ruby naming conventions.
24
                # By default the class name will be the camel-cased version of this identifier, so 'myTest' in
25
                # this case.
26
                my_hash_test: {
27
                  # [OPTIONAL] The C++ test method class name can be overridden from the default like this:
28
                  class_name:             'MyHashExampleClass',
29
                  # [OPTIONAL] If the test method does not require a definition in the testmethodlimits section
30
                  #    of the .tf file, you can suppress like this:
31
                  # render_limits_in_file: false,
32
                  # Parameters can be defined with an underscored symbol as the name, this can be used
33
                  # if the C++ implementation follows the standard V93K convention of calling the attribute
34
                  # the camel cased version, starting with a lower-cased letter, i.e. 'testerState' in this
35
                  # first example.
36
                  # The attribute definition has two required parameters, the type and the default value.
37
                  # The type can be :string, :current, :voltage, :time, :frequency, integer, :double or :boolean
38
                  pin_list:               [:string, ''],
39
                  samples:                [:integer, 1],
40
                  precharge_voltage:      [:voltage, 0],
41
                  settling_time:          [:time, 0],
42
                  # An optional parameter that sets the limits name in the 'testmethodlimits' section
43
                  # of the generated .tf file.  Defaults to 'Functional' if not provided.
44
                  test_name:              [:string, 'HashExample'],
45
                  # An optional 3rd parameter can be supplied to provide an array of allowed values. If supplied,
46
                  # Origen will raise an error upon an attempt to set it to an unlisted value.
47
                  tester_state:           [:string, 'CONNECTED', %w(CONNECTED UNCHANGED DISCONNECTED)],
48
                  force_mode:             [:string, 'VOLT', %w(VOLT CURR)],
49
                  # The name of another parameter can be supplied as the type argument, meaning that the type
50
                  # here will be either :current or :voltage depending on the value of :force_mode
51
                  # force_value: [:force_mode, 3800.mV],
52
                  # In cases where the C++ library has deviated from standard attribute naming conventions
53
                  # (camel-cased with lower cased first character), the absolute attribute name can be given
54
                  # as a string.
55
                  # The Origen accessor for these will be the underscored version, with '.' characters
56
                  # converted to underscores e.g. tm.an_unusual_name
57
                  'hashParameter':        [{ param_name0: [:string, 'NO'], param_name1: [:integer, 0] }],
58
                  'hashParameter2':       [{ param_name0: [:string, 'NO'], param_name1: [:integer, 0] }],
59
                  'nestedHashParameter':  [{
60
                    param_name0:          [:string, ''],
61
                    param_list_strings:   [:list_strings, %w(E1 E2)],
62
                    param_list_classes:   [:list_classes, %w(E1 E2)],
63
                    param_func_call:      [:string, 'setupRef(FQN)'],
64
                    'param_group.param0': [:string, ''],
65
                    param_name1:          [{
66
                      param_name_int:       [:integer, 0],
67
                      param_name_double:    [:double,  0],
68
                      param_list_strings:   [:list_strings, %w(E1 E2)],
69
                      param_list_classes:   [:list_classes, %w(E1 E2)],
70
                      'param_group.param1': [:string, '']
71
                    }]
72
                  }],
73
                  'nestedHashParameter2': [{
74
                    param_name0: [:string, ''],
75
                    param_name1: [{
76
                      param_name_int: [:integer, 0]
77
                    }]
78
                  }]
79
                }
80
        add_tml :my_type_check,
462✔
81
                class_name:         'MyTypeCheck',
82

83
                # Here is a test definition.
84
                # The identifier should be lower-cased and underscored, in-keeping with Ruby naming conventions.
85
                # By default the class name will be the camel-cased version of this identifier, so 'myTest' in
86
                # this case.
87
                my_type_check_test: {
88
                  # [OPTIONAL] The C++ test method class name can be overridden from the default like this:
89
                  class_name:        'MyHashExampleClass',
90
                  int:               [:integer, 1],
91
                  double:            [:double,  1.0],
92
                  int_no_default:    [:integer],
93
                  double_no_default: [:double]
94
                }
95
      end
96

97
      def add_charz
6✔
98
        add_charz_routine :routine1 do |routine|
600✔
99
          routine.name = '_cz__rt1'
600✔
100
        end
101
        add_charz_routine :routine2 do |routine|
600✔
102
          routine.name = '_cz__rt2'
600✔
103
        end
104
        add_charz_routine :routine3 do |routine|
600✔
105
          routine.name = '_cz__rt3'
600✔
106
        end
107
        add_charz_routine :routine4 do |routine|
600✔
108
          routine.name = '_cz__rt4'
600✔
109
        end
110
        add_charz_routine :routine5 do |routine|
600✔
111
          routine.name = '_cz__rt5'
600✔
112
        end
113
        add_charz_routine :routine6 do |routine|
600✔
114
          routine.name = '_cz__rt6'
600✔
115
        end
116
        add_charz_profile :cz do |profile|
600✔
117
          profile.routines = [:routine3]
600✔
118
        end
119
        add_charz_profile :cz_only do |profile|
600✔
120
          profile.charz_only = true
600✔
121
          profile.routines = [:routine1]
600✔
122
        end
123
        add_charz_profile :simple_gates do |profile|
600✔
124
          profile.flags = :my_flag
600✔
125
          profile.enables = :my_enable
600✔
126
          profile.routines = [:routine1]
600✔
127
        end
128
        add_charz_profile :complex_gates do |profile|
600✔
129
          profile.flags = { ['$MyFlag1'] => [:routine1, :routine2], ['$MyFlag2'] => [:routine3], '$MyFlag3' => :routine4 }
600✔
130
          profile.enables = { ['$MyEnable1'] => [:routine1], ['$MyEnable2'] => [:routine2, :routine3], '$MyEnable3' => :routine5 }
600✔
131
          profile.routines = [:routine1, :routine2, :routine3, :routine4, :routine5, :routine6]
600✔
132
        end
133

134
        add_charz_profile :simple_anded_flags do |profile|
600✔
135
          profile.and_flags = true
600✔
136
          profile.routines = [:routine1]
600✔
137
        end
138

139
        add_charz_profile :simple_anded_enables do |profile|
600✔
140
          profile.and_enables = true
600✔
141
          profile.routines = [:routine1]
600✔
142
        end
143

144
        add_charz_profile :complex_anded_flags do |profile|
600✔
145
          profile.and_flags = true
600✔
146
          profile.enables = :my_enable
600✔
147
          profile.routines = [:routine1]
600✔
148
        end
149

150
        add_charz_profile :complex_anded_enables do |profile|
600✔
151
          profile.and_enables = true
600✔
152
          profile.flags = :my_flag
600✔
153
          profile.routines = [:routine1]
600✔
154
        end
155
      end
156

157
      # Test that the block form of flow control methods like this can
158
      # be overridden by an interface
159
      def if_job(*jobs)
6✔
160
        jobs = jobs.flatten
252✔
161
        jobs.delete(:prb9)
252✔
162
        super
252✔
163
      end
164
      alias_method :if_jobs, :if_job
6✔
165

166
      def log(msg)
6✔
167
        if tester.j750? || tester.uflex?
4,266✔
168
          flow.logprint(msg)
1,758✔
169
        else
170
          flow.log(msg)
2,508✔
171
        end
172
      end
173

174
      def func(name, options = {})
6✔
175
        options = {
12,762✔
176
          duration: :static
177
        }.merge(options)
178
        number = options[:number]
12,762✔
179

180
        if tester.j750? || tester.uflex?
12,762✔
181
          block_loop(name, options) do |block, i, group|
5,172✔
182
            options[:number] = number + i if number && i
5,316✔
183
            ins = test_instances.functional(name)
5,316✔
184
            ins.set_wait_flags(:a) if options[:duration] == :dynamic
5,316✔
185
            ins.pin_levels = options.delete(:pin_levels) if options[:pin_levels]
5,316✔
186
            if group
5,316✔
187
              pname = "#{name}_b#{i}_pset"
216✔
188
              patsets.add(pname, [{ pattern: "#{name}_b#{i}.PAT" },
216✔
189
                                  { pattern: 'nvm_global_subs.PAT', start_label: 'subr' }])
190
              ins.pattern = pname
216✔
191
              flow.test(group, options) if i == 0
216✔
192
            else
193
              pname = "#{name}_pset"
5,100✔
194
              patsets.add(pname, [{ pattern: "#{name}.PAT" },
5,100✔
195
                                  { pattern: 'nvm_global_subs.PAT', start_label: 'subr' }])
196
              ins.pattern = pname
5,100✔
197
              if options[:cz_setup]
5,100✔
198
                flow.cz(ins, options[:cz_setup], options)
90✔
199
              else
200
                flow.test(ins, options)
5,010✔
201
              end
202
            end
203
          end
204

205
        elsif tester.v93k?
7,590✔
206
          block_loop(name, options) do |block, i|
7,590✔
207
            options[:number] = number + i if number && i
7,926✔
208
            tm = test_methods.ac_tml.ac_test.functional_test
7,926✔
209
            ts = test_suites.run(name, options)
7,926✔
210
            ts.test_method = tm
7,926✔
211
            if tester.smt8?
7,926✔
212
              ts.spec = options.delete(:pin_levels) if options[:pin_levels]
3,540✔
213
              ts.spec ||= 'specs.Nominal'
3,540✔
214
            else
215
              ts.levels = options.delete(:pin_levels) if options[:pin_levels]
4,386✔
216
            end
217
            if block
7,926✔
218
              ts.pattern = "#{name}_b#{i}"
504✔
219
            else
220
              ts.pattern = name.to_s
7,422✔
221
              #    if options[:cz_setup]
222
              #      flow.cz(ins, options[:cz_setup], options)
223
              #    else
224
              #    end
225
            end
226
            flow.test ts, options
7,926✔
227
          end
228
        end
229
      end
230

231
      def func_with_charz(name, options = {})
6✔
232
        options = {
282✔
233
          duration: :static
234
        }.merge(options)
235

236
        if tester.v93k?
282✔
237
          if tester.smt7?
282✔
238
            tm = test_methods.ac_tml.ac_test.functional_test
282✔
239
            ts = test_suites.run(name, options)
282✔
240
            ts.test_method = tm
282✔
241
            ts.pattern = 'charz_example'
282✔
242

243
            test_level_charz = false
282✔
244
            if options[:charz]
282✔
245
              charz_on(*options[:charz])
12✔
246
              test_level_charz = true
12✔
247
            end
248

249
            unless charz_only? && !options[:charz_test]
282✔
250
              options[:parent_test_name] = name
276✔
251
              set_conditional_charz_id(options)
276✔
252
              flow.test ts, options
276✔
253
            end
254

255
            unless options[:charz_test]
282✔
256
              insert_charz_tests(options.merge(parent_test_name: name, charz_test: true)) do |options|
96✔
257
                charz_name = :"#{name}_#{charz_routines[options[:current_routine]].name}"
186✔
258
                func_with_charz(charz_name, options)
186✔
259
              end
260
            end
261

262
            charz_off if test_level_charz
282✔
263
          else
UNCOV
264
            fail 'Only SMT7 is Implemented for Charz'
×
265
          end
266
        else
UNCOV
267
          fail "Tester #{tester.name} Not Yet Implemented for Charz"
×
268
        end
269
      end
270

271
      def func_with_comment(name, options = {})
6✔
272
        if tester.v93k?
36✔
273
          options = {
36✔
274
            duration: :static
275
          }.merge(options)
276
          number = options[:number]
36✔
277

278
          block_loop(name, options) do |block, i|
36✔
279
            options[:number] = number + i if number && i
36✔
280
            tm = test_methods.ac_tml.ac_test.functional_test
36✔
281
            ts = test_suites.run(name, options)
36✔
282
            ts.test_method = tm
36✔
283
            ts.levels = options.delete(:pin_levels) if options[:pin_levels]
36✔
284
            ts.comment = options.delete(:comment) || flow.active_description
36✔
285
            if block
36✔
UNCOV
286
              ts.pattern = "#{name}_b#{i}"
×
287
            else
288
              ts.pattern = name.to_s
36✔
289
              #    if options[:cz_setup]
290
              #      flow.cz(ins, options[:cz_setup], options)
291
              #    else
292
              #    end
293
            end
294
            flow.test ts, options
36✔
295
          end
296
        else
UNCOV
297
          func(name, options)
×
298
        end
299
      end
300

301
      def double_int_type_check(name, options = {})
6✔
302
        number = options[:number]
60✔
303
        if tester.v93k?
60✔
304
          block_loop(name, options) do |block, i|
42✔
305
            options[:number] = number + i if number && i
42✔
306
            tm = test_methods.my_type_check.my_type_check_test
42✔
307
            tm.int    = '1'
42✔
308
            tm.double = '1.0'
42✔
309
            tm.int_no_default = ''
42✔
310
            tm.double_no_default = ''
42✔
311
            ts = test_suites.run(name, options)
42✔
312
            ts.test_method = tm
42✔
313
            flow.test ts, options
42✔
314
          end
315
        end
316
      end
317

318
      def my_hash_test(name, options = {})
6✔
319
        number = options[:number]
12✔
320

321
        if tester.v93k? && tester.smt8?
12✔
322
          block_loop(name, options) do |block, i|
12✔
323
            options[:number] = number + i if number && i
12✔
324
            tm = test_methods.my_hash_tml.my_hash_test
12✔
325
            tm.hashParameter = {
12✔
326
              param1: {}
327
            }
328
            tm.nestedHashParameter = {
12✔
329
              my_param_name0: {
330
                param_name0:        'hello',
331
                param_group_param0: 'test_group',
332
                param_name1:        {
333
                  my_param_name1: {
334
                    param_name_int:     '1',
335
                    param_name_double:  '1.0',
336
                    param_group_param1: 'test_nested_group'
337
                  },
338
                  my_param_name2: {
339
                    param_name_int:    2,
340
                    param_name_double: 2.0
341
                  },
342
                  my_param_name3: {
343
                    param_name_int: 3
344
                  }
345
                }
346
              }
347
            }
348
            tm.nestedHashParameter2 = {
12✔
349
              my_param_name4: {
350
                param_name0: 'goodbye'
351
              },
352
              my_param_name5: {
353
                param_name0: 'goodbye forever'
354
              }
355
            }
356
            tm.samples = '2'
12✔
357
            ts = test_suites.run(name, options)
12✔
358
            ts.test_method = tm
12✔
359
            ts.spec = options.delete(:pin_levels) if options[:pin_levels]
12✔
360
            ts.spec ||= 'specs.Nominal'
12✔
361
            flow.test ts, options
12✔
362
          end
363
        end
364
      end
365

366
      def my_override_spec_test(name, options = {})
6✔
367
        number = options[:number]
12✔
368

369
        if tester.v93k? && tester.smt8?
12✔
370
          tm = test_methods.ac_tml.ac_test.functional_test
12✔
371
          ts = test_suites.run(name, options)
12✔
372
          ts.test_method = tm
12✔
373
          ts.spec = options.delete(:pin_levels) if options[:pin_levels]
12✔
374
          ts.spec ||= 'specs.Nominal'
12✔
375
          ts.pattern = 'pat1'
12✔
376
          ts.burst = 'sequence1'
12✔
377
          ts.spec_path = 'myCustomSpecPath'
12✔
378
          ts.seq_path  = 'myCustomSeqPath'
12✔
379
          ts.spec_namespace = 'myCustomSpecNamespace'
12✔
380
          ts.seq_namespace  = 'myCustomSeqNamespace'
12✔
381
          flow.test ts, options
12✔
382
        end
383
      end
384

385
      def block_loop(name, options)
6✔
386
        if options[:by_block]
12,864✔
387
          if tester.j750? || tester.uflex?
240✔
388
            test_instances.group do |group|
72✔
389
              group.name = name
72✔
390
              $dut.blocks.each_with_index do |block, i|
72✔
391
                yield block, i, group
216✔
392
              end
393
            end
394
          elsif tester.v93k?
168✔
395
            flow.group name, options do
168✔
396
              $dut.blocks.each_with_index do |block, i|
168✔
397
                yield block, i
504✔
398
              end
399
            end
400
          end
401
        else
402
          yield
12,624✔
403
        end
404
      end
405

406
      def shmoo(name, targets, options = {})
6✔
407
        if tester.v93k? && tester.smt8?
60✔
408
          targets = [targets] unless targets.is_a?(Array)
60✔
409
          st = shmoo_tests.run(name, { targets: targets }.merge(options))
60✔
410
          flow.test st, options
60✔
411
        end
412
      end
413

414
      def por(options = {})
6✔
415
        options = {
60✔
416
          instance_not_available: true
417
        }.merge(options)
418
        if tester.j750? || tester.uflex?
60✔
419
          flow.test('por_ins', options)
18✔
420
        else
421
          func('por_ins', options)
42✔
422
        end
423
      end
424

425
      def para(name, options = {})
6✔
426
        options = {
36✔
427
          high_voltage: false
428
        }.merge(options)
429

430
        if tester.j750?
36✔
431
          if options.delete(:high_voltage)
12✔
432
            ins = test_instances.bpmu(name)
12✔
433
          else
UNCOV
434
            ins = test_instances.ppmu(name)
×
435
          end
436
          ins.dc_category = 'NVM_PARA'
12✔
437
          flow.test(ins, options)
12✔
438
          patsets.add("#{name}_pset", pattern: "#{name}.PAT")
12✔
439
        end
440
      end
441

442
      # OR 2 IDS together into 1 flag
443
      def or_ids(options = {})
6✔
UNCOV
444
        flow.or_flags(options[:id1], options[:id2], options)
×
445
      end
446

447
      def nop(options = {})
6✔
UNCOV
448
        flow.nop options
×
449
      end
450

451
      def mto_memory(name, options = {})
6✔
452
        options = {
60✔
453
          duration: :static
454
        }.merge(options)
455

456
        if tester.j750?
60✔
457
          block_loop(name, options) do |block, i, group|
12✔
458
            ins = test_instances.mto_memory(name)
12✔
459
            ins.set_wait_flags(:a) if options[:duration] == :dynamic
12✔
460
            ins.pin_levels = options.delete(:pin_levels) if options[:pin_levels]
12✔
461
            if group
12✔
462
              pname = "#{name}_b#{i}_pset"
×
UNCOV
463
              patsets.add(pname, [{ pattern: "#{name}_b#{i}.PAT" },
×
464
                                  { pattern: 'nvm_global_subs.PAT', start_label: 'subr' }])
465
              ins.pattern = pname
×
UNCOV
466
              flow.test(group, options) if i == 0
×
467
            else
468
              pname = "#{name}_pset"
12✔
469
              patsets.add(pname, [{ pattern: "#{name}.PAT" },
12✔
470
                                  { pattern: 'nvm_global_subs.PAT', start_label: 'subr' }])
471
              ins.pattern = pname
12✔
472
              if options[:cz_setup]
12✔
UNCOV
473
                flow.cz(ins, options[:cz_setup], options)
×
474
              else
475
                flow.test(ins, options)
12✔
476
              end
477
            end
478
          end
479
        end
480
      end
481

482
      def meas_multi_limits(name, options = {})
6✔
483
        options = {
24✔
484
          duration: :static
485
        }.merge(options)
486

487
        name = "measmulti_#{name}" unless name.to_s =~ /measmulti/
24✔
488

489
        if tester.uflex?
24✔
490
          ins = test_instances.functional(name)
24✔
491
          ins.set_wait_flags(:a) if options[:duration] == :dynamic
24✔
492
          ins.pin_levels = options.delete(:pin_levels) if options[:pin_levels]
24✔
493
          ins.defer_limits = options[:defer_limits]
24✔
494

495
          # some made up sub test limits
496
          options[:sub_tests] = [sub_test('limit1', lo: 0, hi: 7), sub_test('limit2', lo: 3, hi: 8)]
24✔
497

498
          pname = "#{name}_pset"
24✔
499
          patsets.add(pname, [{ pattern: "#{name}.PAT" },
24✔
500
                              { pattern: 'nvm_global_subs.PAT', start_label: 'subr' }])
501
          ins.pattern = pname
24✔
502

503
          flow.test(ins, options)
24✔
504
        end
505
      end
506

507
      def meas(name, options = {})
6✔
508
        options = {
996✔
509
          duration: :static
510
        }.merge(options)
511

512
        name = "meas_#{name}" unless name.to_s =~ /meas/
996✔
513

514
        if tester.j750? || tester.uflex?
996✔
515
          if tester.uflex?
426✔
516
            if options[:pins] == :dcvi
150✔
517
              ins = test_instances.dcvi_powersupply(name)
6✔
518
              ins.set_wait_flags(:a) # set wait flag for tester handshake with patterns
6✔
519
              ins.relay_mode = 1 # tlPowered - keep power on
6✔
520
            else
521
              ins = test_instances.functional(name)
144✔
522
              ins.set_wait_flags(:a) if options[:duration] == :dynamic
144✔
523
              ins.scale = options[:scale]
144✔
524
              ins.units = options[:units]
144✔
525
            end
526
            ins.pin_levels = options.delete(:pin_levels) if options[:pin_levels]
150✔
527
            ins.lo_limit = options[:lo_limit]
150✔
528
            ins.hi_limit = options[:hi_limit]
150✔
529
            ins.defer_limits = options[:defer_limits]
150✔
530
          else
531
            if options[:pins] == :hi_v
276✔
532
              ins = test_instances.board_pmu(name)
12✔
533
            elsif options[:pins] == :power
264✔
534
              ins = test_instances.powersupply(name)
12✔
535
            else
536
              ins = test_instances.pin_pmu(name)
252✔
537
            end
538
            ins.set_wait_flags(:a) if options[:duration] == :dynamic
276✔
539
            ins.pin_levels = options.delete(:pin_levels) if options[:pin_levels]
276✔
540
            ins.lo_limit = options[:lo_limit]
276✔
541
            ins.hi_limit = options[:hi_limit]
276✔
542
          end
543

544
          pname = "#{name}_pset"
426✔
545
          patsets.add(pname, [{ pattern: "#{name}.PAT" },
426✔
546
                              { pattern: 'nvm_global_subs.PAT', start_label: 'subr' }])
547
          ins.pattern = pname
426✔
548
          if options[:cz_setup]
426✔
UNCOV
549
            flow.cz(ins, options[:cz_setup], options)
×
550
          else
551
            flow.test(ins, options)
426✔
552
          end
553

554
        elsif tester.v93k?
570✔
555
          tm = test_methods.dc_tml.dc_test.general_pmu
570✔
556
          ts = test_suites.run(name, options)
570✔
557
          ts.test_method = tm
570✔
558
          if tester.smt8?
570✔
559
            ts.spec = options.delete(:pin_levels) if options[:pin_levels]
168✔
560
            ts.spec ||= 'specs.Nominal'
168✔
561
          else
562
            ts.levels = options.delete(:pin_levels) if options[:pin_levels]
402✔
563
          end
564
          ts.lo_limit = options[:lo_limit] if options[:lo_limit]
570✔
565
          ts.hi_limit = options[:hi_limit] if options[:hi_limit]
570✔
566
          ts.pattern = name.to_s
570✔
567
          # if options[:cz_setup]
568
          #  flow.cz(ins, options[:cz_setup], options)
569
          # else
570
          #  use_limit_params = [:lo_limit, :hi_limit, :scale, :units] # define options to strip for flow.test
571
          #  options_use_limit = options.dup                           # duplicate, as modifying options directly, even an assigned copy modifies original
572
          #  flow.test(ins, options.reject! { |k, _| use_limit_params.include? k })    # set up test skipping use-limit options
573
          #  flow.use_limit(name, options_use_limit) if options_use_limit[:hi_limit] || options_use_limit[:lo_limit]  # Only use use-limit if limits present in flow
574
          # end
575
          flow.test ts, options
570✔
576
        end
577

578
        def group(name, options = {})
996✔
579
          flow.group name, options do |group|
528✔
580
            yield group
528✔
581
          end
582
        end
583

584
        ####################################################
585
        #######  UltraFLEX Pinmap Stuff ####################
586
        ####################################################
587

588
        # Assign relevant pins for pinmap sheet generation
589
        def pinmap(name, options = {})
996✔
590
          pinmap = pinmaps("#{name}")
6✔
591
          Origen.top_level.add_pin_group :JTAG, :tdi, :tdo, :tms
6✔
592
          Origen.top_level.power_pin_groups.keys.each do |grp_key|
6✔
593
            pinmap.add_power_pin(grp_key, type: 'Power', comment: "# #{grp_key}")
12✔
594
          end
595
          Origen.top_level.virtual_pins.keys.each do |util_pin|
6✔
596
            upin = Origen.top_level.virtual_pins(util_pin)
12✔
597
            case upin.type
12✔
598
            when :virtual_pin
599
              pinmap.add_utility_pin(upin.name, type: 'Utility', comment: "# #{util_pin}")
6✔
600
            when :ate_ch
601
              pinmap.add_utility_pin(upin.name, type: 'I/O', comment: "# #{util_pin}")
6✔
602
            end
603
          end
604
          Origen.top_level.pin.keys.each do |pkey|
6✔
605
            pinmap.add_pin(Origen.top_level.pin(pkey).name, type: 'I/O', comment: "# #{pkey}")
24✔
606
          end
607
          Origen.top_level.pin_groups.keys.sort.each do |gkey|
6✔
608
            # Do not include pins that are aliased to themselves
609
            Origen.top_level.pin(gkey).each do |pin|
6✔
610
              pinmap.add_group_pin(gkey, Origen.top_level.pin(pin.id).name, type: 'I/O', comment: "# #{gkey}")
18✔
611
            end
612
          end
613
        end
614

615
        # Assign relevant edges in preparation for edgeset/timeset sheet generation
616
        def edge(category, pin, options = {})
996✔
617
          options = {
618
            d_src:   'PAT',     # source of the channel drive data (e.g. pattern, drive_hi, drive_lo, etc.)
24✔
619
            d_fmt:   'NR',      # drive data format (NR, RL, RH, etc.)
620
            d0_edge: '',        # time at which the input drive is turned on
621
            d1_edge: '',        # time of the initial data drive edge
622
            d2_edge: '',        # time of the return format data drive edge
623
            d3_edge: '',        # time at which the input drive is turned off
624
            c_mode:  'Edge',    # output compare mode
625
            c1_edge: '',        # time of the initial output compare edge
626
            c2_edge: '',        # time of the final output compare edge (window compare)
627
            t_res:   'Machine', # timing resolution (possibly ATE-specific)
628
            clk_per: ''         # clock period equation - for use with MCG
629
          }.merge(options)
630

631
          @edge_collection = edges
24✔
632
          @edge_collection.add(category, pin, options)
24✔
633
        end
634

635
        def edge_collection
996✔
UNCOV
636
          @edge_collection
×
637
        end
638

639
        def edgeset(sheet_name, options = {})
996✔
640
          options = {
641
            edgeset: :es_default,
96✔
642
            period:  'cycle',        # tester cycle period
643
            t_mode:  'Machine'       # edgeset timing mode (possibly ATE-specific)
644
          }.merge(options)
645
          edgeset = options.delete(:edgeset)
96✔
646
          pin = options.delete(:pin)
96✔
647
          edge = options.delete(:edge)
96✔
648

649
          @edgeset = edgesets(sheet_name, options)
96✔
650
          @edgeset.add(edgeset, pin, edge, options)
96✔
651
          collect_ac_specs(@edgeset.es[edgeset].spec_sheet, edge)
96✔
652
        end
653

654
        def timeset(sheet_name, options = {})
996✔
655
          options = {
96✔
656
            timeset:   :default,
657
            master_ts: :default
658
          }.merge(options)
659
          timeset = options.delete(:timeset)
96✔
660
          pin = options.delete(:pin)
96✔
661
          eset = options.delete(:eset)
96✔
662

663
          @timeset = timesets(sheet_name, options)
96✔
664
          @timeset.add(timeset, pin, eset, options)
96✔
665
        end
666

667
        def ac_specset(sheet_name, expression, options = {})
996✔
668
          options = {
669
            specset: :default,
24✔
670
            nom:     { typ: nil }
671
          }.merge(options)
672

673
          ss = ac_specsets(sheet_name)
24✔
674
          add_ac_specs(ss, expression, options)
24✔
675
        end
676

677
        # Collects AC Spec object(s) from the given expression and adds them to the given Specset
678
        def collect_ac_specs(ssname, edge, options = {})
996✔
679
          options = {
680
            nom: { typ: nil }
96✔
681
          }.merge(options)
682

683
          # Create a Specsets object from the UFlex program generator API
684
          ss = ac_specsets(ssname.to_sym)
96✔
685
          add_ac_specs(ss, edge.clk_per, options)
96✔
686
          add_ac_specs(ss, edge.d0_edge, options)
96✔
687
          add_ac_specs(ss, edge.d1_edge, options)
96✔
688
          add_ac_specs(ss, edge.d2_edge, options)
96✔
689
          add_ac_specs(ss, edge.d3_edge, options)
96✔
690
          add_ac_specs(ss, edge.c1_edge, options)
96✔
691
          add_ac_specs(ss, edge.c2_edge, options)
96✔
692
        end
693

694
        # Adds new AC Spec object(s) to the given Specset
695
        def add_ac_specs(ss, expression, options = {})
996✔
696
          options = {
696✔
697
            specset: :default
698
          }.merge(options)
699

700
          return unless expression.is_a? String
696✔
701

702
          # collect all variable names within the expression
703
          vars = expression.scan(/[a-zA-Z]\w+/).map(&:to_sym)
696✔
704
          vars.each do |var|
696✔
705
            next if var =~ /^(d0_edge|d1_edge|d2_edge|d3_edge|c1_edge|c2_edge)$/
444✔
706
            # The substitutions below are used for backward compatibility
707
            next if var =~ /^(d_on|d_data|d_ret|d_off|c_open|c_close)$/
348✔
708
            next if var =~ /^(nS|uS|mS|S)$/i
348✔
709
            next if ss.ac_specsets.key?(options[:specset]) && ss.ac_specsets[options[:specset]].include?(var)
348✔
710

711
            ss.add(var, options)
54✔
712
          end
713
        end
714

715
        # Assign relevant power supply levels in preparation for levelset sheet generation
716
        def pwr_level(category, options = {})
996✔
717
          options = {
6✔
718
            vmain: 1.8,              # Main supply voltage
719
            valt:  1.8,              # Alternate supply voltage
720
            ifold: 1,                # Supply clamp current
721
            delay: 0                 # Supply power-up delay
722
          }.merge(options)
723

724
          @level_collection = levels
6✔
725
          @level_collection.add_power_level(category, options)
6✔
726
        end
727

728
        # Assign relevant single-ended pin levels in preparation for levelset sheet generation
729
        def pin_level_se(category, options = {})
996✔
730
          options = {
731
            vil:       0,            # Input drive low
12✔
732
            vih:       1.8,            # Input drive high
733
            vol:       1.0,            # Output compare low
734
            voh:       0.8,            # Output compare high
735
            vcl:       -1,            # Voltage clamp low
736
            vch:       2.5,            # Voltage clamp high
737
            vt:        0.9,            # Termination voltage
738
            voutlotyp: 0,            #
739
            vouthityp: 0,            #
740
            dmode:     'Largeswing-VT' # Driver mode
741
          }.merge(options)
742

743
          @level_collection = levels
12✔
744
          @level_collection.add_se_pin_level(category, options)
12✔
745
        end
746

747
        def level_collection
996✔
UNCOV
748
          @level_collection
×
749
        end
750

751
        def levelset(sheet_name, options = {})
996✔
752
          pin = options.delete(:pin)
36✔
753
          level = options.delete(:level)
36✔
754

755
          @levelset = levelsets(sheet_name)
36✔
756
          @levelset.add(sheet_name, pin, level, options)
36✔
757
          collect_dc_specs(@levelset.spec_sheet, level)
36✔
758
        end
759

760
        def dc_specset(sheet_name, expression, options = {})
996✔
761
          options = {
762
            min: { min:  nil },
24✔
763
            nom: { typ:  nil },
764
            max: { max:  nil }
765
          }.merge(options)
766

767
          ss = dc_specsets(sheet_name.to_sym)
24✔
768
          add_dc_specs(ss, expression, options)
24✔
769
        end
770

771
        # Collects DC Spec object(s) from the given expression and adds them to the given Specset
772
        def collect_dc_specs(ssname, level, options = {})
996✔
773
          options = {
774
            nom: { typ:  nil },
36✔
775
            min: { min:  nil },
776
            max: { max:  nil }
777
          }.merge(options)
778

779
          # Create a Specsets object from the UFlex program generator API
780
          ss = dc_specsets(ssname.to_sym)
36✔
781
          if level.respond_to?(:vmain)
36✔
782
            add_dc_specs(ss, level.vmain, options)
12✔
783
            add_dc_specs(ss, level.valt, options)
12✔
784
            add_dc_specs(ss, level.ifold, options)
12✔
785
          elsif level.respond_to?(:vil)
24✔
786
            add_dc_specs(ss, level.vil, options)
24✔
787
            add_dc_specs(ss, level.vih, options)
24✔
788
            add_dc_specs(ss, level.vol, options)
24✔
789
            add_dc_specs(ss, level.voh, options)
24✔
790
            add_dc_specs(ss, level.vcl, options)
24✔
791
            add_dc_specs(ss, level.vch, options)
24✔
792
            add_dc_specs(ss, level.vt, options)
24✔
793
            add_dc_specs(ss, level.voutlotyp, options)
24✔
794
            add_dc_specs(ss, level.vouthityp, options)
24✔
795
          end
796
        end
797

798
        # Adds new DC Spec object(s) to the given Specset
799
        def add_dc_specs(ss, expression, options = {})
996✔
800
          options = {
276✔
801
            specset: :default
802
          }.merge(options)
803

804
          return unless expression.is_a? String
276✔
805

806
          vars = expression.scan(/[a-zA-Z]\w+/).map(&:to_sym)
276✔
807
          vars.each do |var|
276✔
808
            next if var =~ /^(nA|uA|mA|A|nV|uV|mV|V)$/i
228✔
809

810
            ss.add(var, options)
228✔
811
          end
812
        end
813

814
        def global_spec(var, options = {})
996✔
815
          options = {
24✔
816
            job:     nil,
817
            value:   nil,
818
            comment: nil
819
          }.merge(options)
820

821
          global_specs('SpecsGlobal').add(var, job: options[:job], value: options[:value], comment: options[:comment])
24✔
822
        end
823

824
        def job_def(jname, options = {})
996✔
825
          options = {
826
            pinmap:         pinmap_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
24✔
827
            instances:      test_instance_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
48✔
828
            flows:          flow_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
96✔
829
            ac_specs:       ac_specset_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
12✔
830
            dc_specs:       dc_specset_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
12✔
831
            patsets:        patset_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
48✔
UNCOV
832
            patgroups:      patgroup_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
×
833
            bintables:      [],
834
            cz:             [],
835
            test_procs:     [],
836
            mix_sig_timing: [],
837
            wave_defs:      [],
838
            psets:          [],
839
            sigs_port_map:  [],
840
            fract_bus:      [],
841
            comment:        nil
842
          }.merge(options)
843

844
          program_jobs('Jobs').add(jname, options)
12✔
845
        end
846

847
        def reference(reference, options = {})
996✔
848
          options = {
12✔
849
            comment: nil
850
          }.merge(options)
851

852
          references('Refs').add(reference, options)
12✔
853
        end
854
      end
855
    end
856
  end
857
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc