origen_testers 0.8.7 → 0.8.8

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
  SHA1:
3
- metadata.gz: b0f226f6dedd573e39ddba26d36a52588d89cfaf
4
- data.tar.gz: edf5678acb10070388405fba3b820c4fd96172a7
3
+ metadata.gz: 998b72183aa2ba05c1b7c722f8d5a115a4b3183e
4
+ data.tar.gz: 170fdc986ae9fe25548971444613839179cbed50
5
5
  SHA512:
6
- metadata.gz: b15f679c0ccb26a23fbb09523d245b3761e2d081ce18bdccac93dc2945df51baf8346f6bfdc21f378ae28ee62d76d8aeb0ad3dfac9ac46f3bb5f8ae286092240
7
- data.tar.gz: 758b94cc1811e3e750991031e13f5070c53b274a59e99dec84948496ddb1e29da55e5537ba0d0a9beb0a62f7b8f04787e65cf5b7d1b03fd9d5e3648455ff5f20
6
+ metadata.gz: 37d879d8076ccb8d116b10b5d412198c5482f548a5be9f9dd24e22eaa89ecd642dd2e7dd71c2e59f366abc9334ed006b373cf4df3ee32dd751f72d19a26c07ef
7
+ data.tar.gz: 85388069884b1ac81087492cf44e57d18fdba487e05727783e52e8b35d79165ebf90e9dbdfc52fa1181075501c6c45793e9e13fbbc60f41fa075444a43397b27
@@ -7,9 +7,6 @@ require "origen_testers/test/block.rb"
7
7
  require "origen_testers/test/dut2.rb"
8
8
  require "origen_testers/test/nvm.rb"
9
9
 
10
- require "origen_testers/test/j750_interface"
11
- require "origen_testers/test/ultraflex_interface"
12
- require "origen_testers/test/j750_hpt_interface"
13
- require "origen_testers/test/v93k_interface"
10
+ require "origen_testers/test/interface"
14
11
  require "origen_testers/test/basic_interface"
15
12
  require "origen_testers/test/custom_test_interface"
@@ -1,7 +1,7 @@
1
1
  module OrigenTesters
2
2
  MAJOR = 0
3
3
  MINOR = 8
4
- BUGFIX = 7
4
+ BUGFIX = 8
5
5
  DEV = nil
6
6
 
7
7
  VERSION = [MAJOR, MINOR, BUGFIX].join(".") + (DEV ? ".pre#{DEV}" : '')
@@ -1,3 +1,4 @@
1
+ require 'origen_testers/igxl_based_tester/ultraflex/ate_hardware'
1
2
  module OrigenTesters
2
3
  module IGXLBasedTester
3
4
  class UltraFLEX < Base
@@ -587,6 +588,22 @@ module OrigenTesters
587
588
  end
588
589
  end
589
590
  alias_method :store!, :store_next_cycle
591
+
592
+ # ate_hardware stores "key" UltraFLEX hardware information needed for test program generation
593
+ # Instrument types available for ppmu: "HSD-M", "HSD-U", "HSD-4G", and "HSS-6G".
594
+ # Sample usage: $tester.ate_hardware("HSD-U").ppmu
595
+ # Instrument types available for supply: "VSM", "VSMx2", "VSMx4", "HexVS", "HexVSx2", "HexVSx4",
596
+ # "HexVSx6", "HexVS+x2", "HexVS+x4", "HexVS+x6", "HDVS1", "HDVS1x2", "HDVS1x4", "VHDVS",
597
+ # "VHDVS_HC", "VHDVSx2", "VHDVS_HCx2", "VHDVS_HCx4", "VHDVS_HCx8", "VHDVS+", "VHDVS_HC+",
598
+ # "VHDVS+x2", "VHDVS_HC+x2", "VHDVS_HC+x4", and "VHDVS_HC+x8".
599
+ # HDVS1 is also known as HDVS. VHDVS is also known as UVS256.
600
+ # x2 is Merged2, x4 is Merged4, x6 is Merged6. _HC is High-Current.
601
+ # + is High-Accuracy.
602
+ # Sample usage: $tester.ate_hardware("VSM").supply
603
+ # Sample usage: $tester.ate_hardware("HSD-M").ppmu
604
+ def ate_hardware(instrumentname = '')
605
+ @ate_hardware = ATEHardware.new(instrumentname)
606
+ end
590
607
  end
591
608
  end
592
609
  UltraFLEX = IGXLBasedTester::UltraFLEX
@@ -1,6 +1,6 @@
1
1
  module OrigenTesters
2
2
  module IGXLBasedTester
3
- class UltraFLEX
3
+ class UltraFLEX < Base
4
4
  class ATEHardware
5
5
  attr_accessor :instrument
6
6
 
@@ -944,22 +944,6 @@ module OrigenTesters
944
944
  end
945
945
  end
946
946
  end
947
-
948
- # ate_hardware stores "key" UltraFLEX hardware information needed for test program generation
949
- # Instrument types available for ppmu: "HSD-M", "HSD-U", "HSD-4G", and "HSS-6G".
950
- # Sample usage: $tester.ate_hardware("HSD-U").ppmu
951
- # Instrument types available for supply: "VSM", "VSMx2", "VSMx4", "HexVS", "HexVSx2", "HexVSx4",
952
- # "HexVSx6", "HexVS+x2", "HexVS+x4", "HexVS+x6", "HDVS1", "HDVS1x2", "HDVS1x4", "VHDVS",
953
- # "VHDVS_HC", "VHDVSx2", "VHDVS_HCx2", "VHDVS_HCx4", "VHDVS_HCx8", "VHDVS+", "VHDVS_HC+",
954
- # "VHDVS+x2", "VHDVS_HC+x2", "VHDVS_HC+x4", and "VHDVS_HC+x8".
955
- # HDVS1 is also known as HDVS. VHDVS is also known as UVS256.
956
- # x2 is Merged2, x4 is Merged4, x6 is Merged6. _HC is High-Current.
957
- # + is High-Accuracy.
958
- # Sample usage: $tester.ate_hardware("VSM").supply
959
- # Sample usage: $tester.ate_hardware("HSD-M").ppmu
960
- def ate_hardware(instrumentname = '')
961
- @ate_hardware = ATEHardware.new(instrumentname)
962
- end
963
947
  end
964
948
  end
965
949
  end
@@ -7,11 +7,11 @@ module OrigenTesters
7
7
 
8
8
  included do
9
9
  Origen.add_interface(self)
10
+ end
10
11
 
11
- (ATP::AST::Builder::CONDITION_KEYS + [:group, :bin, :pass, :fail, :test, :log]).each do |method|
12
- define_method method do |*args, &block|
13
- flow.send(method, *args, &block)
14
- end
12
+ (ATP::AST::Builder::CONDITION_KEYS + [:group, :bin, :pass, :fail, :test, :log]).each do |method|
13
+ define_method method do |*args, &block|
14
+ flow.send(method, *args, &block)
15
15
  end
16
16
  end
17
17
 
@@ -7,6 +7,7 @@ module OrigenTesters
7
7
  # the Testers plugin.
8
8
  module ProgramGenerators
9
9
  extend ActiveSupport::Concern
10
+ include Interface
10
11
 
11
12
  PLATFORMS = [J750, J750_HPT, UltraFLEX, V93K]
12
13
 
@@ -41,6 +41,17 @@ module OrigenTesters
41
41
  @blocks = [Block.new(0, self), Block.new(1, self), Block.new(2, self)]
42
42
  end
43
43
 
44
+ def on_create
45
+ if tester && tester.uflex?
46
+ tester.assign_dc_instr_pins([hv_supply_pin, lv_supply_pin])
47
+ tester.assign_digsrc_pins(digsrc_pins)
48
+ tester.apply_digsrc_settings(digsrc_settings)
49
+ tester.assign_digcap_pins(digcap_pins)
50
+ tester.apply_digcap_settings(digcap_settings)
51
+ tester.memory_test_en = true
52
+ end
53
+ end
54
+
44
55
  def startup(options)
45
56
  $tester.set_timeset('tp0', 60)
46
57
  end
@@ -0,0 +1,503 @@
1
+ module OrigenTesters
2
+ module Test
3
+ class Interface
4
+ include OrigenTesters::ProgramGenerators
5
+
6
+ # Options passed to Flow.create and Library.create will be passed in here, use as
7
+ # desired to configure your interface
8
+ def initialize(options = {})
9
+ end
10
+
11
+ # Test that the block form of flow control methods like this can
12
+ # be overridden by an interface
13
+ def if_job(*jobs)
14
+ jobs = jobs.flatten
15
+ jobs.delete(:prb9)
16
+ super
17
+ end
18
+ alias_method :if_jobs, :if_job
19
+
20
+ def log(msg)
21
+ if tester.j750? || tester.uflex?
22
+ flow.logprint(msg)
23
+ else
24
+ flow.log(msg)
25
+ end
26
+ end
27
+
28
+ def func(name, options = {})
29
+ options = {
30
+ duration: :static
31
+ }.merge(options)
32
+
33
+ if tester.j750? || tester.uflex?
34
+ block_loop(name, options) do |block, i, group|
35
+ ins = test_instances.functional(name)
36
+ ins.set_wait_flags(:a) if options[:duration] == :dynamic
37
+ ins.pin_levels = options.delete(:pin_levels) if options[:pin_levels]
38
+ if group
39
+ pname = "#{name}_b#{i}_pset"
40
+ patsets.add(pname, [{ pattern: "#{name}_b#{i}.PAT" },
41
+ { pattern: 'nvm_global_subs.PAT', start_label: 'subr' }])
42
+ ins.pattern = pname
43
+ flow.test(group, options) if i == 0
44
+ else
45
+ pname = "#{name}_pset"
46
+ patsets.add(pname, [{ pattern: "#{name}.PAT" },
47
+ { pattern: 'nvm_global_subs.PAT', start_label: 'subr' }])
48
+ ins.pattern = pname
49
+ if options[:cz_setup]
50
+ flow.cz(ins, options[:cz_setup], options)
51
+ else
52
+ flow.test(ins, options)
53
+ end
54
+ end
55
+ end
56
+
57
+ elsif tester.v93k?
58
+ block_loop(name, options) do |block, i|
59
+ tm = test_methods.ac_tml.ac_test.functional_test
60
+ ts = test_suites.run(name, options)
61
+ ts.test_method = tm
62
+ ts.levels = options.delete(:pin_levels) if options[:pin_levels]
63
+ if block
64
+ ts.pattern = "#{name}_b#{i}"
65
+ else
66
+ ts.pattern = name.to_s
67
+ # if options[:cz_setup]
68
+ # flow.cz(ins, options[:cz_setup], options)
69
+ # else
70
+ # end
71
+ end
72
+ flow.test ts, options
73
+ end
74
+ end
75
+ end
76
+
77
+ def block_loop(name, options)
78
+ if options[:by_block]
79
+ if tester.j750? || tester.uflex?
80
+ test_instances.group do |group|
81
+ group.name = name
82
+ $dut.blocks.each_with_index do |block, i|
83
+ yield block, i, group
84
+ end
85
+ end
86
+ elsif tester.v93k?
87
+ flow.group name, options do
88
+ $dut.blocks.each_with_index do |block, i|
89
+ yield block, i
90
+ end
91
+ end
92
+ end
93
+ else
94
+ yield
95
+ end
96
+ end
97
+
98
+ def por(options = {})
99
+ options = {
100
+ instance_not_available: true
101
+ }.merge(options)
102
+ if tester.j750? || tester.uflex?
103
+ flow.test('por_ins', options)
104
+ else
105
+ func('por_ins', options)
106
+ end
107
+ end
108
+
109
+ def para(name, options = {})
110
+ options = {
111
+ high_voltage: false
112
+ }.merge(options)
113
+
114
+ if tester.j750?
115
+ if options.delete(:high_voltage)
116
+ ins = test_instances.bpmu(name)
117
+ else
118
+ ins = test_instances.ppmu(name)
119
+ end
120
+ ins.dc_category = 'NVM_PARA'
121
+ flow.test(ins, options)
122
+ patsets.add("#{name}_pset", pattern: "#{name}.PAT")
123
+ end
124
+ end
125
+
126
+ # OR 2 IDS together into 1 flag
127
+ def or_ids(options = {})
128
+ flow.or_flags(options[:id1], options[:id2], options)
129
+ end
130
+
131
+ def nop(options = {})
132
+ flow.nop options
133
+ end
134
+
135
+ def mto_memory(name, options = {})
136
+ options = {
137
+ duration: :static
138
+ }.merge(options)
139
+
140
+ if tester.j750?
141
+ block_loop(name, options) do |block, i, group|
142
+ ins = test_instances.mto_memory(name)
143
+ ins.set_wait_flags(:a) if options[:duration] == :dynamic
144
+ ins.pin_levels = options.delete(:pin_levels) if options[:pin_levels]
145
+ if group
146
+ pname = "#{name}_b#{i}_pset"
147
+ patsets.add(pname, [{ pattern: "#{name}_b#{i}.PAT" },
148
+ { pattern: 'nvm_global_subs.PAT', start_label: 'subr' }])
149
+ ins.pattern = pname
150
+ flow.test(group, options) if i == 0
151
+ else
152
+ pname = "#{name}_pset"
153
+ patsets.add(pname, [{ pattern: "#{name}.PAT" },
154
+ { pattern: 'nvm_global_subs.PAT', start_label: 'subr' }])
155
+ ins.pattern = pname
156
+ if options[:cz_setup]
157
+ flow.cz(ins, options[:cz_setup], options)
158
+ else
159
+ flow.test(ins, options)
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
165
+
166
+ def meas(name, options = {})
167
+ options = {
168
+ duration: :static
169
+ }.merge(options)
170
+
171
+ name = "meas_#{name}" unless name.to_s =~ /meas/
172
+
173
+ if tester.j750? || tester.uflex?
174
+ if tester.uflex?
175
+ ins = test_instances.functional(name)
176
+ ins.set_wait_flags(:a) if options[:duration] == :dynamic
177
+ ins.pin_levels = options.delete(:pin_levels) if options[:pin_levels]
178
+ ins.lo_limit = options[:lo_limit]
179
+ ins.hi_limit = options[:hi_limit]
180
+ ins.scale = options[:scale]
181
+ ins.units = options[:units]
182
+ ins.defer_limits = options[:defer_limits]
183
+ else
184
+ if options[:pins] == :hi_v
185
+ ins = test_instances.board_pmu(name)
186
+ elsif options[:pins] == :power
187
+ ins = test_instances.powersupply(name)
188
+ else
189
+ ins = test_instances.pin_pmu(name)
190
+ end
191
+ ins.set_wait_flags(:a) if options[:duration] == :dynamic
192
+ ins.pin_levels = options.delete(:pin_levels) if options[:pin_levels]
193
+ ins.lo_limit = options[:lo_limit]
194
+ ins.hi_limit = options[:hi_limit]
195
+ end
196
+
197
+ pname = "#{name}_pset"
198
+ patsets.add(pname, [{ pattern: "#{name}.PAT" },
199
+ { pattern: 'nvm_global_subs.PAT', start_label: 'subr' }])
200
+ ins.pattern = pname
201
+ if options[:cz_setup]
202
+ flow.cz(ins, options[:cz_setup], options)
203
+ else
204
+ flow.test(ins, options)
205
+ end
206
+
207
+ elsif tester.v93k?
208
+ tm = test_methods.dc_tml.dc_test.general_pmu
209
+ ts = test_suites.run(name, options)
210
+ ts.test_method = tm
211
+ ts.levels = options.delete(:pin_levels) if options[:pin_levels]
212
+ ts.lo_limit = options[:lo_limit] if options[:lo_limit]
213
+ ts.hi_limit = options[:hi_limit] if options[:hi_limit]
214
+ ts.pattern = name.to_s
215
+ # if options[:cz_setup]
216
+ # flow.cz(ins, options[:cz_setup], options)
217
+ # else
218
+ # use_limit_params = [:lo_limit, :hi_limit, :scale, :units] # define options to strip for flow.test
219
+ # options_use_limit = options.dup # duplicate, as modifying options directly, even an assigned copy modifies original
220
+ # flow.test(ins, options.reject! { |k, _| use_limit_params.include? k }) # set up test skipping use-limit options
221
+ # 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
222
+ # end
223
+ flow.test ts, options
224
+ end
225
+
226
+ def group(name, options = {})
227
+ flow.group name, options do |group|
228
+ yield group
229
+ end
230
+ end
231
+
232
+ ####################################################
233
+ ####### UltraFLEX Pinmap Stuff ####################
234
+ ####################################################
235
+
236
+ # Assign relevant pins for pinmap sheet generation
237
+ def pinmap(name, options = {})
238
+ pinmap = pinmaps("#{name}")
239
+ Origen.top_level.add_pin_group :JTAG, :tdi, :tdo, :tms
240
+ Origen.top_level.power_pin_groups.keys.each do |grp_key|
241
+ pinmap.add_power_pin(grp_key, type: 'Power', comment: "# #{grp_key}")
242
+ end
243
+ Origen.top_level.virtual_pins.keys.each do |util_pin|
244
+ upin = Origen.top_level.virtual_pins(util_pin)
245
+ case upin.type
246
+ when :virtual_pin
247
+ pinmap.add_utility_pin(upin.name, type: 'Utility', comment: "# #{util_pin}")
248
+ when :ate_ch
249
+ pinmap.add_utility_pin(upin.name, type: 'I/O', comment: "# #{util_pin}")
250
+ end
251
+ end
252
+ Origen.top_level.pin.keys.each do |pkey|
253
+ pinmap.add_pin(Origen.top_level.pin(pkey).name, type: 'I/O', comment: "# #{pkey}")
254
+ end
255
+ Origen.top_level.pin_groups.keys.sort.each do |gkey|
256
+ # Do not include pins that are aliased to themselves
257
+ Origen.top_level.pin(gkey).each do |pin|
258
+ pinmap.add_group_pin(gkey, Origen.top_level.pin(pin.id).name, type: 'I/O', comment: "# #{gkey}")
259
+ end
260
+ end
261
+ end
262
+
263
+ # Assign relevant edges in preparation for edgeset/timeset sheet generation
264
+ def edge(category, pin, options = {})
265
+ options = {
266
+ d_src: 'PAT', # source of the channel drive data (e.g. pattern, drive_hi, drive_lo, etc.)
267
+ d_fmt: 'NR', # drive data format (NR, RL, RH, etc.)
268
+ d0_edge: '', # time at which the input drive is turned on
269
+ d1_edge: '', # time of the initial data drive edge
270
+ d2_edge: '', # time of the return format data drive edge
271
+ d3_edge: '', # time at which the input drive is turned off
272
+ c_mode: 'Edge', # output compare mode
273
+ c1_edge: '', # time of the initial output compare edge
274
+ c2_edge: '', # time of the final output compare edge (window compare)
275
+ t_res: 'Machine', # timing resolution (possibly ATE-specific)
276
+ clk_per: '' # clock period equation - for use with MCG
277
+ }.merge(options)
278
+
279
+ @edge_collection = edges
280
+ @edge_collection.add(category, pin, options)
281
+ end
282
+
283
+ def edge_collection
284
+ @edge_collection
285
+ end
286
+
287
+ def edgeset(sheet_name, options = {})
288
+ options = {
289
+ edgeset: :es_default,
290
+ period: 'cycle', # tester cycle period
291
+ t_mode: 'Machine' # edgeset timing mode (possibly ATE-specific)
292
+ }.merge(options)
293
+ edgeset = options.delete(:edgeset)
294
+ pin = options.delete(:pin)
295
+ edge = options.delete(:edge)
296
+
297
+ @edgeset = edgesets(sheet_name, options)
298
+ @edgeset.add(edgeset, pin, edge, options)
299
+ collect_ac_specs(@edgeset.es[edgeset].spec_sheet, edge)
300
+ end
301
+
302
+ def timeset(sheet_name, options = {})
303
+ options = {
304
+ timeset: :default,
305
+ master_ts: :default
306
+ }.merge(options)
307
+ timeset = options.delete(:timeset)
308
+ pin = options.delete(:pin)
309
+ eset = options.delete(:eset)
310
+
311
+ @timeset = timesets(sheet_name, options)
312
+ @timeset.add(timeset, pin, eset, options)
313
+ end
314
+
315
+ def ac_specset(sheet_name, expression, options = {})
316
+ options = {
317
+ specset: :default,
318
+ nom: { typ: nil }
319
+ }.merge(options)
320
+
321
+ ss = ac_specsets(sheet_name)
322
+ add_ac_specs(ss, expression, options)
323
+ end
324
+
325
+ # Collects AC Spec object(s) from the given expression and adds them to the given Specset
326
+ def collect_ac_specs(ssname, edge, options = {})
327
+ options = {
328
+ nom: { typ: nil }
329
+ }.merge(options)
330
+
331
+ # Create a Specsets object from the UFlex program generator API
332
+ ss = ac_specsets(ssname.to_sym)
333
+ add_ac_specs(ss, edge.clk_per, options)
334
+ add_ac_specs(ss, edge.d0_edge, options)
335
+ add_ac_specs(ss, edge.d1_edge, options)
336
+ add_ac_specs(ss, edge.d2_edge, options)
337
+ add_ac_specs(ss, edge.d3_edge, options)
338
+ add_ac_specs(ss, edge.c1_edge, options)
339
+ add_ac_specs(ss, edge.c2_edge, options)
340
+ end
341
+
342
+ # Adds new AC Spec object(s) to the given Specset
343
+ def add_ac_specs(ss, expression, options = {})
344
+ options = {
345
+ specset: :default
346
+ }.merge(options)
347
+
348
+ return unless expression.is_a? String
349
+ # collect all variable names within the expression
350
+ vars = expression.scan(/[a-zA-Z][\w]+/).map(&:to_sym)
351
+ vars.each do |var|
352
+ next if var =~ /^(d0_edge|d1_edge|d2_edge|d3_edge|c1_edge|c2_edge)$/
353
+ # The substitutions below are used for backward compatibility
354
+ next if var =~ /^(d_on|d_data|d_ret|d_off|c_open|c_close)$/
355
+ next if var =~ /^(nS|uS|mS|S)$/i
356
+ next if ss.ac_specsets.key?(options[:specset]) && ss.ac_specsets[options[:specset]].include?(var)
357
+
358
+ ss.add(var, options)
359
+ end
360
+ end
361
+
362
+ # Assign relevant power supply levels in preparation for levelset sheet generation
363
+ def pwr_level(category, options = {})
364
+ options = {
365
+ vmain: 1.8, # Main supply voltage
366
+ valt: 1.8, # Alternate supply voltage
367
+ ifold: 1, # Supply clamp current
368
+ delay: 0 # Supply power-up delay
369
+ }.merge(options)
370
+
371
+ @level_collection = levels
372
+ @level_collection.add_power_level(category, options)
373
+ end
374
+
375
+ # Assign relevant single-ended pin levels in preparation for levelset sheet generation
376
+ def pin_level_se(category, options = {})
377
+ options = {
378
+ vil: 0, # Input drive low
379
+ vih: 1.8, # Input drive high
380
+ vol: 1.0, # Output compare low
381
+ voh: 0.8, # Output compare high
382
+ vcl: -1, # Voltage clamp low
383
+ vch: 2.5, # Voltage clamp high
384
+ vt: 0.9, # Termination voltage
385
+ voutlotyp: 0, #
386
+ vouthityp: 0, #
387
+ dmode: 'Largeswing-VT' # Driver mode
388
+ }.merge(options)
389
+
390
+ @level_collection = levels
391
+ @level_collection.add_se_pin_level(category, options)
392
+ end
393
+
394
+ def level_collection
395
+ @level_collection
396
+ end
397
+
398
+ def levelset(sheet_name, options = {})
399
+ pin = options.delete(:pin)
400
+ level = options.delete(:level)
401
+
402
+ @levelset = levelsets(sheet_name)
403
+ @levelset.add(sheet_name, pin, level, options)
404
+ collect_dc_specs(@levelset.spec_sheet, level)
405
+ end
406
+
407
+ def dc_specset(sheet_name, expression, options = {})
408
+ options = {
409
+ min: { min: nil },
410
+ nom: { typ: nil },
411
+ max: { max: nil }
412
+ }.merge(options)
413
+
414
+ ss = dc_specsets(sheet_name.to_sym)
415
+ add_dc_specs(ss, expression, options)
416
+ end
417
+
418
+ # Collects DC Spec object(s) from the given expression and adds them to the given Specset
419
+ def collect_dc_specs(ssname, level, options = {})
420
+ options = {
421
+ nom: { typ: nil },
422
+ min: { min: nil },
423
+ max: { max: nil }
424
+ }.merge(options)
425
+
426
+ # Create a Specsets object from the UFlex program generator API
427
+ ss = dc_specsets(ssname.to_sym)
428
+ if level.respond_to?(:vmain)
429
+ add_dc_specs(ss, level.vmain, options)
430
+ add_dc_specs(ss, level.valt, options)
431
+ add_dc_specs(ss, level.ifold, options)
432
+ elsif level.respond_to?(:vil)
433
+ add_dc_specs(ss, level.vil, options)
434
+ add_dc_specs(ss, level.vih, options)
435
+ add_dc_specs(ss, level.vol, options)
436
+ add_dc_specs(ss, level.voh, options)
437
+ add_dc_specs(ss, level.vcl, options)
438
+ add_dc_specs(ss, level.vch, options)
439
+ add_dc_specs(ss, level.vt, options)
440
+ add_dc_specs(ss, level.voutlotyp, options)
441
+ add_dc_specs(ss, level.vouthityp, options)
442
+ end
443
+ end
444
+
445
+ # Adds new DC Spec object(s) to the given Specset
446
+ def add_dc_specs(ss, expression, options = {})
447
+ options = {
448
+ specset: :default
449
+ }.merge(options)
450
+
451
+ return unless expression.is_a? String
452
+ vars = expression.scan(/[a-zA-Z][\w]+/).map(&:to_sym)
453
+ vars.each do |var|
454
+ next if var =~ /^(nA|uA|mA|A|nV|uV|mV|V)$/i
455
+
456
+ ss.add(var, options)
457
+ end
458
+ end
459
+
460
+ def global_spec(var, options = {})
461
+ options = {
462
+ job: nil,
463
+ value: nil,
464
+ comment: nil
465
+ }.merge(options)
466
+
467
+ global_specs('SpecsGlobal').add(var, job: options[:job], value: options[:value], comment: options[:comment])
468
+ end
469
+
470
+ def job_def(jname, options = {})
471
+ options = {
472
+ pinmap: pinmap_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
473
+ instances: test_instance_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
474
+ flows: flow_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
475
+ ac_specs: ac_specset_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
476
+ dc_specs: dc_specset_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
477
+ patsets: patset_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
478
+ patgroups: patgroup_sheets.map { |k, v| v.filename.gsub(/\.txt$/, '') },
479
+ bintables: [],
480
+ cz: [],
481
+ test_procs: [],
482
+ mix_sig_timing: [],
483
+ wave_defs: [],
484
+ psets: [],
485
+ sigs_port_map: [],
486
+ fract_bus: [],
487
+ comment: nil
488
+ }.merge(options)
489
+
490
+ program_jobs('Jobs').add(jname, options)
491
+ end
492
+
493
+ def reference(reference, options = {})
494
+ options = {
495
+ comment: nil
496
+ }.merge(options)
497
+
498
+ references('Refs').add(reference, options)
499
+ end
500
+ end
501
+ end
502
+ end
503
+ end