origen_testers 0.14.0 → 0.15.0

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.
@@ -0,0 +1,40 @@
1
+ module OrigenTesters
2
+ module PatternCompilers
3
+ module Runner
4
+ # Run the pattern (or list) through the (specified) compiler
5
+ def self.run_compiler(pattern, options = {})
6
+ compiler = nil
7
+ if options[:compiler_instance]
8
+ compiler = options[:compiler_instance]
9
+ unless dut.pattern_compilers.include? compiler
10
+ fail_msg = "Pattern Compiler instance '#{compiler}' does not exist for this tester, "
11
+ fail_msg += "choose from \(#{dut.pattern_compilers.keys.join(', ')}\) or change tester target."
12
+ fail fail_msg
13
+ end
14
+ else
15
+ if dut.pattern_compilers.count == 1
16
+ # Only one compiler defined (for current platform), use that one
17
+ compiler = dut.pattern_compilers.keys[0]
18
+ else
19
+ # Multiple compilers defined, used one assigned to default or named :default, otherwise fail
20
+ if dut.default_pattern_compiler
21
+ compiler = dut.default_pattern_compiler
22
+ elsif dut.pattern_compilers.keys.include? :default
23
+ compiler = :default
24
+ else
25
+ fail_msg = "No 'default' Pattern Compiler defined, choose from "
26
+ fail_msg += "\(#{dut.pattern_compilers.keys.join(', ')}\) or set one to be the default."
27
+ fail fail_msg
28
+ end
29
+ end
30
+ end
31
+
32
+ Origen.log.info "Compiling... #{pattern}"
33
+
34
+ # Everything is verified and ready, last thing to do is COMPILE
35
+ dut.pattern_compilers[compiler].find_jobs(pattern)
36
+ dut.pattern_compilers[compiler].run
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,31 @@
1
+ AI_DIR_FILE
2
+ tmp_dir <%= tmp_dir %>
3
+ tmf_dir ./
4
+ vbc_dir ./
5
+ avc_dir <%= avc_dir %>
6
+ pinconfig_file <%= pinconfig_file.to_s %>
7
+ single_binary_pattern_dir <%= binl_dir %>
8
+
9
+ <%= render_aiv2b_options_line %>
10
+
11
+ <%= render_aiv_patterns_header %>
12
+ % @avc_files.each do |f|
13
+ <%= render_aiv_patterns_entry(f) %>
14
+ % end
15
+ %
16
+ % # MULTIPORT ENTRIES (if necessary)
17
+ % if multiport?
18
+ % @avc_files.each do |f|
19
+ % multiport.render_aiv_lines(f).each do |line|
20
+ <%= line %>
21
+ % end
22
+ % end
23
+ % end
24
+ %
25
+ % # DIGCAP SETTINGS (if necessary)
26
+ % if digcap? && !digcap.empty?
27
+ % digcap.render_aiv_lines.each do |line|
28
+ <%= line %>
29
+ % end
30
+ % end
31
+
@@ -0,0 +1,92 @@
1
+ module OrigenTesters
2
+ module PatternCompilers
3
+ class UltraFLEXPatternCompiler < IGXLBasedPatternCompiler
4
+ # Linux compiler executable path
5
+ def self.linux_compiler
6
+ Origen.site_config.origen_testers[:uflex_linux_pattern_compiler]
7
+ end
8
+
9
+ # Windows compiler executable path
10
+ def self.windows_compiler
11
+ Origen.site_config.origen_testers[:uflex_windows_pattern_compiler]
12
+ end
13
+
14
+ # Pre-compile environment setup if necessary
15
+ def self.atpc_setup
16
+ Origen.site_config.origen_testers[:uflex_atpc_setup]
17
+ end
18
+
19
+ # Resolves to correct compiler based on operating system
20
+ def self.compiler
21
+ Origen.running_on_windows? ? windows_compiler : linux_compiler
22
+ end
23
+
24
+ def self.compiler_cmd
25
+ Pathname.new(compiler).absolute? ? compiler : eval('"' + compiler + '"')
26
+ end
27
+
28
+ def self.compiler_options
29
+ "#{compiler_cmd} -help"
30
+ end
31
+
32
+ def self.compiler_version
33
+ "#{compiler_cmd} -version"
34
+ end
35
+
36
+ def initialize(id, options = {})
37
+ super
38
+
39
+ @user_options = {}.merge(@user_options)
40
+
41
+ @job_options = {
42
+ tester: :ultraflex,
43
+ compiler: self.class.compiler, # required
44
+ }.merge(@job_options)
45
+
46
+ # These are compiler options that are specific to UltraFLEX (builds on options from IGXL-Based)
47
+ # Set all of these compiler options that don't have args to true/flase. if true then send compiler '-opt'
48
+ @compiler_options = {
49
+ lock: false, # prevents pattern from being reverse compiled or opened in PatternTool
50
+ multiinst: false, # indicates more than one instrument is connected to a single pin
51
+ nocompress: false, # do not compress pattern data blocks
52
+ stdin: false, # Compile data from standard input. Do not use -cpp or specify any pattern file(s) when using this option.
53
+ }.merge(@compiler_options)
54
+
55
+ # These are compiler options that are specific to UltraFLEX (builds on options from IGXL-Based)
56
+ @compiler_options_with_args = {
57
+ pat_version: nil, # version of pattern file to compile
58
+ scan_type: nil, # type of scan data
59
+ includes: nil, # include paths to be passed to C- preprocessor.
60
+ post_processor: nil, # <pathname> customer's post-process executable.
61
+ post_processor_args: nil, # <args> customer's post-process executable arguments
62
+ cdl_cache: nil, # 'yes' | 'no', turns on/off CDL caching, default on compiler side is 'yes'
63
+ init_pattern: nil, # <pattern>, uses the specified pattern module/file/set as an init patterns
64
+ check_set_msb: nil, # 'yes' | 'no', turns on/off check the 'set' or 'set_infinite' opcode
65
+ time_domain: nil, # <time domain>, specifies time domain for pins in patterns
66
+ allow_mto_dash: nil, # Turn on/off support for channel data runtime repeat,i.e. vector dash in MTO patterns. Default value is "no".
67
+ check_vm_min_size: nil, # Turns on/off the check on minimum size of a VM pattern. Default value is "yes".
68
+ check_vm_mod_size: nil, # Turns on/off the check on a VM pattern module size. Default value is "yes".
69
+ check_oob_size: nil, # Turns on/off the check on size of OOB regions. Yes means size must be modulo 10. Default value is "no".
70
+ allow_mixed_1x2x: nil, # Turns on/off the support of mixed 1x/2x pin groups. Default value is "no".
71
+ allow_differential: nil, # Turns on/off support for differential pins. Default value is "yes".
72
+ allow_scan_in_srm: nil, # Allow/disallow scan vectors in SRM pattern modules. Default value is "no".
73
+ vm_block_size: nil, # Specifies uncompressed size in bytes of a pattern data block
74
+ }.merge(@compiler_options_with_args)
75
+
76
+ update_common_options(options) # Update common options with default (see BasePatternCompiler)
77
+ verify_pinmap_is_specified # verify pinmap specified correctly - IGXL specific
78
+ clean_and_verify_options # Standard cleaning and verifying (see BasePatternCompiler)
79
+ end
80
+
81
+ # Executes the compiler for each job in the queue
82
+ def run(list = nil, options = {})
83
+ fail "Error: the tester #{Origen.tester} is not an Ultrflex tester,exiting..." unless is_ultraflex?
84
+ msg = "Error: application #{Origen.app.name} is running on Windows, "
85
+ msg += 'to run the pattern compiler you must be on a Linux machine'
86
+ fail msg if Origen.running_on_windows?
87
+
88
+ super
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,455 @@
1
+ module OrigenTesters
2
+ module PatternCompilers
3
+ class V93KPatternCompiler < BasePatternCompiler
4
+ require_relative 'v93k/multiport'
5
+ include MultiportAPI
6
+ require_relative 'v93k/digcap'
7
+ include DigCapAPI
8
+
9
+ attr_reader :avc_files, :max_avcfilename_size, :vec_per_frame
10
+
11
+ TEMPLATE = "#{Origen.root!}/lib/origen_testers/pattern_compilers/templates/template.aiv.erb"
12
+
13
+ # Linux compiler executable path
14
+ def self.linux_compiler
15
+ Origen.site_config.origen_testers[:v93k_linux_pattern_compiler]
16
+ end
17
+
18
+ # Windows compiler executable path - not available for V93K
19
+ def self.windows_compiler
20
+ nil
21
+ end
22
+
23
+ # Resolves to correct compiler (linux is only available)
24
+ def self.compiler
25
+ linux_compiler
26
+ end
27
+
28
+ def self.compiler_cmd
29
+ Pathname.new(compiler).absolute? ? compiler : eval('"' + compiler + '"')
30
+ end
31
+
32
+ def self.compiler_options
33
+ "#{compiler_cmd} -h"
34
+ end
35
+
36
+ def self.compiler_version
37
+ "#{compiler_cmd} -V"
38
+ end
39
+
40
+ def initialize(id, options = {})
41
+ super
42
+
43
+ @user_options = {
44
+ config_dir: nil, # Common directory where all configs can be stored
45
+ pinconfig_dir: nil, # Can override common config_dir if pinconfig stored elsewhere
46
+ pinconfig: nil, # Can specify just file name (to use config_dir/pinconfig_dir), or give full path
47
+ tmf_dir: nil, # Can override common config_dir if tmf stored elsewhere
48
+ tmf: nil, # Can specify just file name (to use config_dir/tmf_dir), or give full path
49
+ vbc_dir: nil, # Can override common config_dir if vbc stored elsewhere
50
+ vbc: nil, # Can specify just file name (to use config_dir/vbc_dir), or give full path
51
+ incl_dir: nil,
52
+ includes: [], # Array of files that will be copied into tmp job workspace before compilation
53
+ tmp_dir: nil,
54
+ avc_dir: nil,
55
+ binl_dir: nil,
56
+ multiport: nil, # Optional hash for multiport settings: port_bursts, port_in_focus, prefix, postfix
57
+ digcap: nil, # Optional hash for digcap settings: pins, vps, nrf, char
58
+ }.merge(@user_options)
59
+
60
+ @job_options = {
61
+ tester: :v93k,
62
+ compiler: self.class.compiler, # required
63
+ }.merge(@job_options)
64
+
65
+ @compiler_options = {
66
+
67
+ }.merge(@compiler_options)
68
+
69
+ @compiler_options_with_args = {
70
+ aiv2b_opts: nil
71
+ }.merge(@compiler_options_with_args)
72
+
73
+ @avc_files = []
74
+ @vec_per_frame = {}
75
+
76
+ update_common_options(options) # Update common options with default (see BasePatternCompiler)
77
+ verify_pinconfig_is_specified # Verify pinconfig specified correctly - Smartest specific
78
+ verify_tmf_is_specified # Verify tmf specified correctly - Smartest specific
79
+ clean_and_verify_options # Standard cleaning and verifying (see BasePatternCompiler)
80
+ end
81
+
82
+ def pinconfig_file
83
+ @pinconfig_file ||= build_file(:pinconfig)
84
+ end
85
+
86
+ def tmf_file
87
+ @tmf_file ||= build_file(:tmf)
88
+ end
89
+
90
+ def vbc_file
91
+ @vbc_file ||= build_file(:vbc)
92
+ end
93
+
94
+ def verify_pinconfig_is_specified
95
+ fail 'Pinconfig file is not defined! Pass as an option.' if pinconfig_file.nil?
96
+ fail 'Pinconfig is not a file!' unless pinconfig_file.file?
97
+ end
98
+
99
+ def verify_tmf_is_specified
100
+ fail 'Timing Map File (tmf) is not defined! Pass as an option.' if tmf_file.nil?
101
+ fail 'Timing Map File (tmf) is not a file!' unless tmf_file.file?
102
+ end
103
+
104
+ # Executes the compiler for each job in the queue
105
+ def run(aiv = nil, options = {})
106
+ aiv, options = nil, aiv if aiv.is_a? Hash
107
+
108
+ fail "Error: the tester #{Origen.tester} is not an V93K tester, exiting..." unless is_v93k?
109
+
110
+ msg = "Error: application #{Origen.app.name} is running on Windows, "
111
+ msg += 'to run the pattern compiler you must be on a Linux machine'
112
+ fail msg if Origen.running_on_windows?
113
+
114
+ # Check if there was a pattern list passed as an argument
115
+ # If so, then compile the patterns inside it.
116
+ # Otherwise compile the jobs in the queue
117
+ if aiv.nil?
118
+ if empty?
119
+ empty_msg
120
+ return
121
+ end
122
+ @jobs.each do |job|
123
+ unless options[:ignore_ready]
124
+ fail "Error: compiler #{job.id} not ready for pattern #{job.name}" unless job.ready?
125
+ end
126
+ if job.location == :lsf
127
+ # puts "#{self.class.aiv_setup} ; #{job.cmd}"
128
+ # Origen.app.lsf.submit(self.class.aiv_setup + '; ' + job.cmd)
129
+ Origen.app.lsf.submit(job.cmd)
130
+ else
131
+ Origen.profile "Linux pattern compiler compiles pattern #{job.pattern}" do
132
+ Dir.chdir(job.output_directory) do
133
+ # puts "#{job.cmd}"
134
+ system job.cmd
135
+ end
136
+ end
137
+ end
138
+ end
139
+ if @job_options[:location] == :local
140
+ if @job_options[:clean] == true
141
+ puts 'Log file :clean option set to true, deleting log files'
142
+ clean_output
143
+ end
144
+ end
145
+ # Clear @jobs
146
+ clear
147
+
148
+ else
149
+ # Assumes .aiv file and all workspace collateral has been built up
150
+ aiv = convert_to_pathname(aiv)
151
+ fail 'File does not exist! Please specify existing aiv file.' unless aiv.file?
152
+ current_job_options = @job_options.merge(@compiler_options_with_args)
153
+ current_job_options = current_job_options.merge(extract_job_options_from_aiv(aiv))
154
+ current_job_options = current_job_options.merge(options)
155
+ current_job_options[:output_directory] = aiv.dirname
156
+
157
+ @jobs << Job.new(Pathname.new(aiv), current_job_options, @compiler_options)
158
+ inspect_jobs
159
+ run(options)
160
+ end
161
+ end
162
+
163
+ # Output the compiler jobs in the queue to the console
164
+ def inspect_jobs(index = nil)
165
+ return empty_msg if empty?
166
+ desc = []
167
+ puts "\n"
168
+ @jobs.each_with_index do |j, i|
169
+ unless index.nil?
170
+ next unless i == index
171
+ end
172
+ desc << '| Job: ' + " #{i + 1} ".rjust(8) + '|' + 'Pattern/AIV:'.rjust(18) + " #{j.pattern.basename}".ljust(125) + '|'
173
+ desc << '| |' + 'Compiler ID:'.rjust(18) + " #{j.id} ".ljust(125) + '|'
174
+ desc << '| |' + 'AVC Files:'.rjust(18) + " #{j.count} ".ljust(125) + '|'
175
+ desc << '| |' + 'Output Directory:'.rjust(18) + " #{j.output_directory} ".ljust(125) + '|'
176
+ desc << '| |' + '.avc directory:'.rjust(18) + " #{j.avc_dir} ".ljust(125) + '|'
177
+ desc << '| |' + '.binl directory:'.rjust(18) + " #{j.binl_dir} ".ljust(125) + '|'
178
+ desc << '| |' + 'LSF:'.rjust(18) + " #{j.location == :lsf ? true : false} ".ljust(125) + '|'
179
+ desc << '| |' + 'Delete log files:'.rjust(18) + " #{j.clean} ".ljust(125) + '|'
180
+ desc << '| |' + 'Verbose:'.rjust(18) + " #{j.verbose} ".ljust(125) + '|'
181
+ if j.aiv2b_opts && j.aiv2b_opts.is_a?(String)
182
+ aiv2b_opts = j.aiv2b_opts.gsub('AI_V2B_OPTIONS ', '')
183
+ else
184
+ aiv2b_opts = render_aiv2b_options_line.gsub('AI_V2B_OPTIONS', '')
185
+ end
186
+ desc << '| |' + 'AI_V2B Options:'.rjust(18) + " #{aiv2b_opts} ".ljust(125) + '|'
187
+ desc << '-' * desc.first.size
188
+ end
189
+ puts desc.flatten.join("\n")
190
+ end
191
+
192
+ # Finds the patterns and creates a compiler job for each one found.
193
+ # Handles singles files (.atp, .atp.gz, or .list) and directories (recursively or flat)
194
+ def find_jobs(p = @path)
195
+ # First-level verification: file/directory was given and exists
196
+ msg = 'Pass in a valid file (.avc, .avc.gz, .list) or a valid directory'
197
+ fail "Pattern path is set to nil! #{msg}" if p.nil?
198
+ path = Pathname.new(p)
199
+ fail "Pattern path does not exist! #{msg}" unless path.exist?
200
+ path = path.expand_path
201
+
202
+ # Set the reference directory for pattern sub-dir mirroring
203
+ set_reference_directory
204
+
205
+ # Collect file, list, or directory (recursively)
206
+ Origen.profile 'Linux pattern compiler finds patterns' do
207
+ if path.directory?
208
+ # Get all of the patterns inside this dir or inside this directory recursively
209
+ process_directory(path, @files, @user_options[:recursive])
210
+ else
211
+ # Found a file so no searching is necessary, process as single pattern or list
212
+ process_file(path, @files)
213
+ end
214
+ end
215
+
216
+ fail "Did not fild a valid file to compile! #{msg}" if @files.empty?
217
+
218
+ Origen.profile 'Linux pattern compiler creates job' do
219
+ # For V93K, only single AIV file is really sent to the compiler, but need list of all
220
+ # avc files that will be compiled using that aiv file, so keep a separate array.
221
+ @max_avcfilename_size = 0
222
+ @files.each do |f|
223
+ @avc_files << Pathname.new(f).basename.sub_ext('').to_s
224
+ @max_avcfilename_size = @avc_files[-1].size > @max_avcfilename_size ? @avc_files[-1].size : @max_avcfilename_size
225
+ end
226
+
227
+ rel_dir = Pathname.new("#{path.dirname.to_s[@user_options[:reference_directory].to_s.size..-1]}")
228
+
229
+ # Resolve output directory
230
+ if @job_options[:output_directory].nil?
231
+ # job output dir not specified, create a unique (hash) based on path/compiler_name
232
+ s = Digest::MD5.new
233
+ s << @user_options[:reference_directory].to_s
234
+ s << @id.to_s
235
+ out = "#{@user_options[:reference_directory]}/job_#{@id}_#{s.to_s[0..6].upcase}#{rel_dir}"
236
+ job_output_dir = Pathname.new(out)
237
+ else
238
+ job_output_dir = Pathname.new("#{@job_options[:output_directory]}#{rel_dir}")
239
+ end
240
+
241
+ # Create any necessary output directories before trying to compile
242
+ unless job_output_dir.directory?
243
+ puts "Output directory #{job_output_dir} does not exist, creating it..."
244
+ FileUtils.mkdir_p(job_output_dir)
245
+ end
246
+
247
+ job_avc_dir = avc_dir.absolute? ? avc_dir : Pathname.new("#{job_output_dir}/#{avc_dir}").cleanpath
248
+ unless job_avc_dir.directory?
249
+ puts "AVC Output directory #{job_avc_dir} does not exist, creating it..."
250
+ FileUtils.mkdir_p(job_avc_dir)
251
+ end
252
+ job_binl_dir = binl_dir.absolute? ? binl_dir : Pathname.new("#{job_output_dir}/#{binl_dir}").cleanpath
253
+ unless job_binl_dir.directory?
254
+ puts "BINL Output directory #{job_binl_dir} does not exist, creating it..."
255
+ FileUtils.mkdir_p(job_binl_dir)
256
+ end
257
+
258
+ # Move AVC files into job space (through pre-processor)
259
+ @files.each do |file|
260
+ contents = File.open(file, 'rb') { |f| f.read }
261
+ new_contents = preprocess_avc(contents)
262
+ new_avc_file = Pathname.new("#{job_avc_dir}/#{Pathname.new(file).basename}").cleanpath
263
+ File.open(new_avc_file, 'w') { |f| f.write(new_contents) }
264
+ avc_key = Pathname.new(file).basename.sub_ext('').to_s.to_sym
265
+ @vec_per_frame[avc_key] = digcap? ? avc_digcap_vpf(new_contents) : 0
266
+ end
267
+
268
+ # Generate the AIV file using the template with all the pattern compiler parameters
269
+ aiv_file = "#{job_output_dir}/#{path.basename.to_s.split('.')[0]}.aiv"
270
+ Origen.log.info "Creating... #{aiv_file}"
271
+ contents = Origen.compile(self.class::TEMPLATE, scope: self, preserve_target: true)
272
+ File.open(aiv_file, 'w') { |f| f.write(contents) }
273
+
274
+ # Copy Timing Map File to local AIV workspace
275
+ dest = Pathname.new("#{job_output_dir}/#{tmf_file.basename}").cleanpath
276
+ FileUtils.cp tmf_file, dest
277
+
278
+ # Copy VBC file to local AIV workspace (if specified)
279
+ if vbc_file
280
+ dest = Pathname.new("#{job_output_dir}/#{vbc_file.basename}").cleanpath
281
+ FileUtils.cp vbc_file, dest
282
+ end
283
+
284
+ # Copy any extra files needed (includes)
285
+ @user_options[:includes].each do |incl|
286
+ src = build_file(:incl, incl)
287
+ dest = Pathname.new("#{job_output_dir}/#{src.basename}").cleanpath
288
+ FileUtils.cp src, dest
289
+ end
290
+
291
+ # Gather up job options
292
+ current_job_options = @job_options.merge(@compiler_options_with_args)
293
+ current_job_options[:output_directory] = job_output_dir
294
+ current_job_options[:pinconfig] = pinconfig_file
295
+ current_job_options[:tmf] = tmf_file
296
+ current_job_options[:count] = @avc_files.count
297
+ current_job_options[:avc_dir] = avc_dir
298
+ current_job_options[:binl_dir] = binl_dir
299
+
300
+ # Create new job
301
+ @jobs << Job.new(Pathname.new(aiv_file), current_job_options, @compiler_options)
302
+ current_job_options = {}
303
+ end
304
+
305
+ # Clear files and avc_files now that job has successfully been queued
306
+ @files = []
307
+ @avc_files = []
308
+ @vec_per_frame = {}
309
+ inspect_jobs
310
+ end
311
+
312
+ # Given the file contents, parse and calculate number of capture vectors
313
+ def avc_digcap_vpf(contents)
314
+ capture_vectors = 0
315
+ contents.each_line do |line|
316
+ capture_vectors += 1 if /#{digcap.capture_string}/.match(line)
317
+ end
318
+ capture_vectors
319
+ end
320
+
321
+ def avc_dir
322
+ @avc_dir ||= begin
323
+ if @user_options[:avc_dir]
324
+ clean_path(@user_options[:avc_dir].to_s)
325
+ else
326
+ Pathname.new('./AVC') # default value
327
+ end
328
+ end
329
+ end
330
+
331
+ def binl_dir
332
+ @binl_dir ||= begin
333
+ if @user_options[:binl_dir]
334
+ clean_path(@user_options[:binl_dir].to_s)
335
+ else
336
+ Pathname.new('./BINL') # default value
337
+ end
338
+ end
339
+ end
340
+
341
+ def tmp_dir
342
+ @tmp_dir ||= begin
343
+ if @user_options[:tmp_dir]
344
+ clean_path(@user_options[:tmp_dir].to_s)
345
+ else
346
+ Pathname.new('./tmp') # default value
347
+ end
348
+ end
349
+ end
350
+
351
+ # Given path string, return Pathname object with cleaned up path
352
+ def clean_path(path_str)
353
+ path = Pathname.new(path_str).cleanpath
354
+ if path.absolute?
355
+ return path
356
+ else
357
+ return Pathname.new("./#{path}")
358
+ end
359
+ end
360
+
361
+ # Placeholder - TopLevel can monkey patch this method to do more
362
+ # sophisticated AVC modification prior to compilation
363
+ def preprocess_avc(contents)
364
+ new_contents = contents # no manipulation done here
365
+ new_contents
366
+ end
367
+
368
+ def render_aiv2b_options_line
369
+ line = 'AI_V2B_OPTIONS'
370
+ if @compiler_options_with_args[:aiv2b_opts]
371
+ if @compiler_options_with_args[:aiv2b_opts].is_a? Array
372
+ @compiler_options_with_args[:aiv2b_opts].each do |opt|
373
+ line += " #{opt}"
374
+ end
375
+ elsif @compiler_options_with_args[:aiv2b_opts].is_a? String
376
+ line += " #{@compiler_options[:aiv2b]}"
377
+ else
378
+ fail 'aiv2b options must be an array or string'
379
+ end
380
+ end
381
+ line += " -c #{vbc_file.basename}" if vbc_file
382
+ line
383
+ end
384
+
385
+ def render_aiv_patterns_header
386
+ line = 'PATTERNS '
387
+ line += 'name'.ljust(max_avcfilename_size + 2)
388
+ line += 'port'.ljust(multiport.port_in_focus.size + 2) if multiport?
389
+ line += 'tmf_file'
390
+ line
391
+ end
392
+
393
+ def render_aiv_patterns_entry(pattern)
394
+ line = ' '
395
+ line += "#{pattern}".ljust(max_avcfilename_size + 2)
396
+ line += "#{multiport.port_in_focus}".ljust(multiport.port_in_focus.size + 2) if multiport?
397
+ line += "#{tmf_file.basename}"
398
+ line
399
+ end
400
+
401
+ private
402
+
403
+ def extract_job_options_from_aiv(file)
404
+ options = {}
405
+ contents = File.open(file, 'rb') { |f| f.read }
406
+ count = 0
407
+ counting = false
408
+ contents.each_line do |line|
409
+ if match = line.match(/^avc_dir\s*(\S*)/)
410
+ options[:avc_dir] = match.captures[0]
411
+ end
412
+ if match = line.match(/^pinconfig_file\s*(\S*)/)
413
+ options[:pinconfig] = Pathname.new(match.captures[0])
414
+ end
415
+ if match = line.match(/^single_binary_pattern_dir\s*(\S*)/)
416
+ options[:binl_dir] = match.captures[0]
417
+ end
418
+ if match = line.match(/^AI_V2B_OPTIONS/)
419
+ options[:aiv2b_opts] = match.captures[0]
420
+ end
421
+ if counting
422
+ if line.match(/\w+/)
423
+ count += 1
424
+ else
425
+ counting = false
426
+ end
427
+ end
428
+ if match = line.match(/^PATTERNS/)
429
+ counting = true
430
+ end
431
+ end
432
+ options[:count] = count
433
+ options
434
+ end
435
+
436
+ def build_file(type, fstr = nil)
437
+ type_dir = "#{type}_dir".to_sym
438
+ fstr ||= @user_options[type]
439
+ if fstr.nil?
440
+ nil
441
+ else
442
+ if Pathname.new(fstr).absolute?
443
+ Pathname.new(fstr)
444
+ elsif @user_options[type_dir]
445
+ Pathname.new("#{@user_options[type_dir]}/#{fstr}").cleanpath
446
+ elsif @user_options[:config_dir]
447
+ Pathname.new("#{@user_options[:config_dir]}/#{fstr}").cleanpath
448
+ else
449
+ Pathname.new("#{Origen.root!}/#{fstr}").cleanpath
450
+ end
451
+ end
452
+ end
453
+ end
454
+ end
455
+ end