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,348 @@
1
+ module OrigenTesters
2
+ module PatternCompilers
3
+ class IGXLBasedPatternCompiler < BasePatternCompiler
4
+ def initialize(id, options = {})
5
+ super
6
+
7
+ # The following are pattern compiler options that are common between all IGXL platforms, these
8
+ # are added onto the base options. Specifc IGXL platforms can add on additional options
9
+ # in their respective initialize methods.
10
+ @user_options = {}.merge(@user_options)
11
+
12
+ @job_options = {
13
+ pinmap_workbook: dut.pinmap, # required: will default to $dut.pinmap
14
+ }.merge(@job_options)
15
+
16
+ # These are compiler options that are common to both the UltraFLEX and J750 compilers
17
+ # Set all of these compiler options that don't have args to true/flase. if true then send compiler '-opt'
18
+ @compiler_options = {
19
+ comments: false, # preserves comments in pattern binary
20
+ cpp: false, # runs C++ preprocessor on pattern file
21
+ debug: false, # generate intermediate file(s) to simplify debug ( application dependent )
22
+ import_all_undefineds: false, # automatically import all undefined symbols. the key is mis-spelled but correct!
23
+ suppress_log: false, # disables output to main log file
24
+ template: false, # generate setup template
25
+ timestamp: false, # enable log timestamp
26
+ }.merge(@compiler_options)
27
+
28
+ # These are compiler options that are common to both the UltraFLEX and J750 compilers
29
+ @compiler_options_with_args = {
30
+ define: nil, # Define macro values to be passed to C-preprocessor
31
+ digital_inst: nil, # Name of digital instrument
32
+ logfile: nil, # Messages go to <filename> instead of <infile> log
33
+ opcode_mode: nil, # Patgen opcode mode, specific to digital instrument
34
+ output: nil, # Name of output file
35
+ pinmap_sheet: nil, # Name of workbook containing pinmap
36
+ # pinmap_workbook: nil, # Name of sheet in workbook which contains pinmap (moved to @job_options)
37
+ setup: nil, # path to setup file
38
+ }.merge(@compiler_options_with_args)
39
+ end
40
+
41
+ def verify_pinmap_is_specified
42
+ if @job_options[:pinmap_workbook].nil?
43
+ # Check if the app has dut.pinmap defined
44
+ if dut.pinmap && File.exist?(dut.pinmap)
45
+ @job_options[:pinmap_workbook] = dut.pinmap
46
+ else
47
+ fail 'Pinmap is not defined! Pass as an option or set $dut.pinmap.'
48
+ end
49
+ end
50
+ @job_options[:pinmap_workbook] = convert_to_pathname(@job_options[:pinmap_workbook])
51
+ fail 'Pinmap is not a file!' unless @job_options[:pinmap_workbook].file?
52
+ end
53
+
54
+ # Return the compiler instance pinmap
55
+ def pinmap
56
+ @job_options[:pinmap_workbook]
57
+ end
58
+
59
+ # Executes the compiler for each job in the queue
60
+ def run(list = nil, options = {})
61
+ # Check if there was a pattern list passed as an argument
62
+ # If so, then compile the patterns inside it.
63
+ # Otherwise compile the jobs in the queue
64
+ if list.nil?
65
+ if empty?
66
+ empty_msg
67
+ return
68
+ end
69
+ @jobs.each do |job|
70
+ fail "Error: compiler #{job.id} not ready for pattern #{job.name}" unless job.ready?
71
+ if job.location == :lsf
72
+ Origen.app.lsf.submit(ATPC_SETUP + '; ' + job.cmd)
73
+ else
74
+ Origen.profile "Linux pattern compiler compiles pattern #{job.pattern}" do
75
+ system job.cmd
76
+ end
77
+ end
78
+ end
79
+ if @job_options[:location] == :local
80
+ if @job_options[:clean] == true
81
+ puts 'Log file :clean option set to true, deleting log files'
82
+ clean_output
83
+ end
84
+ end
85
+ # Clear @jobs
86
+ clear
87
+ else
88
+ list = convert_to_pathname(list)
89
+ fail "Error: pattern list #{list} does not exist, exiting..." unless list.file?
90
+ File.open(list, 'r') do |file|
91
+ while (line = file.gets)
92
+ current_job_options = @job_options.merge(@compiler_options_with_args)
93
+ current_job_options.update_common(options)
94
+ # puts "current job options is #{current_job_options}"
95
+ compiler_opts = {}
96
+ line.strip!
97
+ pattern = line.match(/^(\S+)\s+(.*)/).captures[0]
98
+ unless File.file? pattern
99
+ puts "Warning: Pattern #{pattern} does not exist, skipping..."
100
+ next
101
+ end
102
+ pattern = convert_to_pathname(pattern)
103
+ line.match(/^\S+\s+(.*)/).captures[0].split(/\s+/).each do |e|
104
+ opt, arg = e.split(':')
105
+ opt.gsub!('-', '')
106
+ if arg.nil?
107
+ compiler_opts[opt.to_sym] = true
108
+ else
109
+ # Check for some specific options
110
+ case opt
111
+ when 'pinmap_workbook'
112
+ current_job_options[opt.to_sym] = Pathname.new(arg)
113
+ when 'output'
114
+ dot_pat = Pathname.new(arg)
115
+ current_job_options[:output_directory] = dot_pat.dirname
116
+ else
117
+ current_job_options[opt.to_sym] = arg
118
+ end
119
+ end
120
+ end
121
+ @jobs << Job.new(pattern, current_job_options, compiler_opts)
122
+ inspect_jobs
123
+ end
124
+ end
125
+ run
126
+ # Clear @jobs
127
+ clear
128
+ end
129
+ end
130
+
131
+ # Finds the patterns and creates a compiler job for each one found.
132
+ # Handles singles files (.atp, .atp.gz, or .list) and directories (recursively or flat)
133
+ def find_jobs(path = @path)
134
+ fail 'Pattern path is set to nil, pass in a valid file (.atp or .atp.gz) or a valid directory' if path.nil?
135
+ @path = Pathname.new(path)
136
+ fail 'Pattern path does not exist, pass in a valid file (.atp or .atp.gz) or a valid directory' unless @path.exist?
137
+ @path = @path.expand_path
138
+ # Set the reference directory for pattern sub-dir mirroring
139
+ set_reference_directory
140
+ Origen.profile 'Linux pattern compiler finds patterns' do
141
+ # Check if the path is a file or a directory
142
+ if @path.directory?
143
+ # Get all of the patterns inside this dir or inside this directory recursively
144
+ process_directory(@path, @files, @user_options[:recursive])
145
+ elsif @path.file? # Found a file so no searching is necessary
146
+ process_file(@path, @files)
147
+ else # Didn't find a directory or a file so user must want a search for this arg string * NOT SUPPORTED YET
148
+ fail 'Error: Did not find a file or directory to compile, exiting...'
149
+ end
150
+ end
151
+
152
+ Origen.profile 'Linux pattern compiler creates jobs' do
153
+ @files.each do |f|
154
+ rel_dir = Pathname.new("#{f.dirname.to_s[@user_options[:reference_directory].to_s.size..-1]}")
155
+ if @job_options[:output_directory].nil?
156
+ # job output dir not specified, create a unique (hash) based on path/compiler_name
157
+ s = Digest::MD5.new
158
+ s << @user_options[:reference_directory].to_s
159
+ s << @id.to_s
160
+ out = "#{@user_options[:reference_directory]}/job_#{@id}_#{s.to_s[0..6].upcase}#{rel_dir}"
161
+ output_dir = Pathname.new(out)
162
+ else
163
+ output_dir = Pathname.new("#{@job_options[:output_directory]}#{rel_dir}")
164
+ end
165
+ unless output_dir.directory?
166
+ puts "Output directory #{output_dir} for pattern #{f.basename} does not exist, creating it..."
167
+ FileUtils.mkdir_p(output_dir)
168
+ end
169
+ current_job_options = @job_options.merge(@compiler_options_with_args)
170
+ current_job_options[:output_directory] = output_dir
171
+ @jobs << Job.new(f, current_job_options, @compiler_options)
172
+ current_job_options = {}
173
+ end
174
+ end
175
+ @files = []
176
+ if empty?
177
+ empty_msg
178
+ else
179
+ inspect_jobs
180
+ end
181
+ end
182
+
183
+ # Output all of the jobs into a pattern list so it can be compiled later
184
+ # Must be executed after the 'find_jobs' method and before the 'run' method
185
+ # or @jobs will be empty
186
+ def to_list(options = {})
187
+ options = {
188
+ name: @id,
189
+ output_directory: Dir.pwd,
190
+ expand: true,
191
+ force: false
192
+ }.update_common(options)
193
+ list = "#{options[:output_directory]}/#{options[:name]}.list"
194
+ list = convert_to_pathname(list)
195
+ if empty?
196
+ empty_msg
197
+ return
198
+ end
199
+ if list.file?
200
+ if options[:force] == true
201
+ puts "Pattern list file #{list} already exists, deleting it..."
202
+ list.delete
203
+ else
204
+ fail "Pattern list file #{list} already exists, exiting..."
205
+ end
206
+ end
207
+ File.open(list, 'w') do |patlist|
208
+ @jobs.each do |job|
209
+ if options[:expand] == true
210
+ pinmap = job.pinmap_workbook
211
+ dot_pat_name = "#{job.output_directory}/#{job.pattern.basename.to_s.split('.').first}.PAT"
212
+ dot_atp_name = job.pattern
213
+ else
214
+ pinmap = job.pinmap_workbook.basename
215
+ dot_pat_name = "#{job.pattern.basename.to_s.split('.').first}.PAT"
216
+ dot_atp_name = job.pattern.basename
217
+ end
218
+ patlist.print("#{dot_atp_name} -pinmap_workbook:#{pinmap} -output:#{dot_pat_name}")
219
+ job.compiler_options.each_key { |k| patlist.print(" -#{k}") }
220
+ job.compiler_options_with_args.each_pair { |k, v| patlist.print(" -#{k}:#{v}") }
221
+ patlist.puts('')
222
+ end
223
+ end
224
+ end
225
+
226
+ # alias_method :find, :find_jobs
227
+ #
228
+ # Output the compiler jobs in the queue to the console
229
+ def inspect_jobs(index = nil)
230
+ return empty_msg if empty?
231
+ desc = []
232
+ puts "\n"
233
+ @jobs.each_with_index do |j, i|
234
+ unless index.nil?
235
+ next unless i == index
236
+ end
237
+ desc << '| Job: ' + "#{i + 1} ".rjust(8) + '|' + 'Pattern:'.rjust(18) + " #{j.pattern.basename}".ljust(120) + '|'
238
+ desc << '| |' + 'Compiler ID:'.rjust(18) + " #{j.id} ".ljust(120) + '|'
239
+ desc << '| |' + 'Pinmap:'.rjust(18) + " #{j.pinmap_workbook} ".ljust(120) + '|'
240
+ desc << '| |' + '.atp directory:'.rjust(18) + " #{j.pattern.dirname} ".ljust(120) + '|'
241
+ desc << '| |' + '.pat directory:'.rjust(18) + " #{j.output_directory} ".ljust(120) + '|'
242
+ desc << '| |' + 'LSF:'.rjust(18) + " #{j.location == :lsf ? true : false} ".ljust(120) + '|'
243
+ desc << '| |' + 'Delete log files:'.rjust(18) + " #{j.clean} ".ljust(120) + '|'
244
+ desc << '| |' + 'Verbose:'.rjust(18) + " #{j.verbose} ".ljust(120) + '|'
245
+ fragment = '| |' + 'Compiler args:'.rjust(18)
246
+ overflow_fragment = '| |' + ' '.rjust(18)
247
+ compiler_args = []
248
+ compiler_fragment = ''
249
+ j.compiler_options.each_key do |k|
250
+ if compiler_fragment.size + " -#{k}".size >= 120
251
+ compiler_args << compiler_fragment
252
+ compiler_fragment = nil
253
+ end
254
+ compiler_fragment += " -#{k}"
255
+ end
256
+ compiler_args << compiler_fragment unless compiler_fragment.nil?
257
+ compiler_fragment = ''
258
+ j.compiler_options_with_args.each_pair do |k, v|
259
+ if compiler_fragment.size + " -#{k}:#{v}".size >= 120
260
+ compiler_args << compiler_fragment
261
+ compiler_fragment = nil
262
+ end
263
+ compiler_fragment += " -#{k}:#{v}"
264
+ end
265
+ compiler_args << compiler_fragment unless compiler_fragment.nil?
266
+ if compiler_args.join.length <= 120
267
+ desc << fragment + "#{compiler_args.join}".ljust(120) + '|'
268
+ else
269
+ # Need to cycle through compiler args and build a fragment <= 100 characters
270
+ # and print it. Keep going until the remaining args is <= 100 and print again
271
+ char_cnt = 0
272
+ line_cnt = 0
273
+ args = []
274
+ compiler_args = compiler_args.join.strip.split(/\s+/)
275
+ until compiler_args.empty?
276
+ args = compiler_args.select { |e| (char_cnt += e.length + 1) < 120 }
277
+ # remove the args that fit on the first line
278
+ compiler_args -= args
279
+ if line_cnt == 0
280
+ desc << fragment + " #{args.join(' ')}".ljust(120) + '|'
281
+ else
282
+ desc << overflow_fragment + " #{args.join(' ')}".ljust(120) + '|'
283
+ end
284
+ args = []
285
+ line_cnt += 1
286
+ char_cnt = 0
287
+ end
288
+ end
289
+ desc << '-' * desc.first.size
290
+ end
291
+ puts desc.flatten.join("\n")
292
+ end
293
+ # For future checks on incorrect or incompatible arguments to compiler options
294
+ def options_ok?
295
+ end
296
+
297
+ def ready?
298
+ ready = true
299
+ paths_contain_data = true
300
+ ready &= paths_contain_data
301
+ ready &= !@job_options[:output_directory].nil?
302
+ ready &= !@user_options[:reference_directory].nil?
303
+ ready &= !@path.nil?
304
+ ready &= !@job_options[:pinmap_workbook].nil?
305
+ ready &= @job_options[:output_directory].directory?
306
+ ready &= @user_options[:reference_directory].directory?
307
+ ready &= @path.exist?
308
+ ready &= @job_options[:pinmap_workbook].file?
309
+ ready &= [true, false].include?(@job_options[:clean])
310
+ ready &= [:local, :lsf].include?(@job_options[:location])
311
+ ready &= File.exist?(@job_options[:compiler])
312
+ ready
313
+ end
314
+
315
+ def bad_options
316
+ bad = []
317
+ options = {
318
+ output_directory: @job_options[:output_directory],
319
+ reference_directory: @user_options[:reference_directory],
320
+ path: @path,
321
+ pinmap_workbook: @job_options[:pinmap_workbook],
322
+ clean: @job_options[:clean],
323
+ location: @job_options[:location],
324
+ compiler: @job_options[:compiler]
325
+ }
326
+ options.each do |k, v|
327
+ bad << k if v.nil?
328
+ if v.is_a? String # compiler
329
+ v = Pathname.new(v)
330
+ bad << k unless v.file?
331
+ elsif v.is_a? Symbol # clean
332
+ bad << k unless [:local, :lsf].include? v
333
+ elsif v.is_a? Pathname
334
+ if k.match(/directory/)
335
+ bad << k unless v.directory?
336
+ elsif k == :path
337
+ bad << k unless v.exist?
338
+ else # pinmap
339
+ bad << k unless v.file?
340
+ end
341
+ end
342
+ end
343
+ bad
344
+ end
345
+ alias_method :bad_opts, :bad_options
346
+ end
347
+ end
348
+ end
@@ -0,0 +1,80 @@
1
+ module OrigenTesters
2
+ module PatternCompilers
3
+ class J750PatternCompiler < IGXLBasedPatternCompiler
4
+ # Linux compiler executable path
5
+ def self.linux_compiler
6
+ Origen.site_config.origen_testers[:j750_linux_pattern_compiler]
7
+ end
8
+
9
+ # Windows compiler executable path
10
+ def self.windows_compiler
11
+ Origen.site_config.origen_testers[:j750_windows_pattern_compiler]
12
+ end
13
+
14
+ # Pre-compile environment setup if necessary
15
+ def self.atpc_setup
16
+ Origen.site_config.origen_testers[:j750_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: :j750,
43
+ compiler: self.class.compiler, # required
44
+ }.merge(@job_options)
45
+
46
+ # These are compiler options that are specific to J750 compiler (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
+ compress: false, # Compress the compiled output file.
50
+ extended: false, # Compiles the pattern for extended mode.
51
+ scan_parallel: false, # Expands scan vectors into parallel SVM/LVM vectors.
52
+ svm_only: false, # Compile all vectors in the file for SVM.
53
+ svm_subr_only: false, # Only SVM subroutines in file being used.
54
+ }.merge(@compiler_options)
55
+
56
+ # These are compiler options that are specific to J750 compiler (builds on options from IGXL-Based)
57
+ @compiler_options_with_args = {
58
+ i: nil, # Includes paths to be passed to C++ preprocessor.
59
+ lvm_size: nil, # Number of LVM vectors to allow in a single pattern.
60
+ max_errors: nil, # Number of errors that will cause compilation of the pattern file to be aborted.
61
+ min_period: nil, # Minimum period, in seconds, that will be used during a pattern burst.
62
+ }.merge(@compiler_options_with_args)
63
+
64
+ update_common_options(options) # Update common options with default (see BasePatternCompiler)
65
+ verify_pinmap_is_specified # verify pinmap specified correctly - IGXL specific
66
+ clean_and_verify_options # Standard cleaning and verifying (see BasePatternCompiler)
67
+ end
68
+
69
+ # Executes the compiler for each job in the queue
70
+ def run(list = nil, options = {})
71
+ fail "Error: the tester #{Origen.tester} is not an J750 tester,exiting..." unless is_j750?
72
+ msg = "Error: application #{Origen.app.name} is running on Windows, "
73
+ msg += 'to run the pattern compiler you must be on a Linux machine'
74
+ fail msg if Origen.running_on_windows?
75
+
76
+ super
77
+ end
78
+ end
79
+ end
80
+ end
@@ -19,9 +19,27 @@ module OrigenTesters
19
19
  # Output directory for the .PAT file
20
20
  attr_accessor :output_directory
21
21
 
22
- # Pinmap file
22
+ # Pinmap file (IGXL-Based)
23
23
  attr_accessor :pinmap_workbook
24
24
 
25
+ # Pinmap file (Smartest-Based)
26
+ attr_accessor :pinconfig
27
+
28
+ # Pinmap file (Smartest-Based)
29
+ attr_accessor :avc_dir
30
+
31
+ # Pinmap file (Smartest-Based)
32
+ attr_accessor :binl_dir
33
+
34
+ # Pattern count - should be 1 for IGXL; number of AVC files listed in AIV file for Smartest
35
+ attr_accessor :count
36
+
37
+ # tmf file (Smartest-Based)
38
+ attr_accessor :tmf
39
+
40
+ # aiv2b options (Smartest-Based)
41
+ attr_accessor :aiv2b_opts
42
+
25
43
  # Compiler options where only the opt has to be passed as '-opt'
26
44
  attr_accessor :compiler_options
27
45
 
@@ -33,6 +51,7 @@ module OrigenTesters
33
51
 
34
52
  def initialize(pattern, options_with_args, options)
35
53
  @pattern = pattern
54
+ @tester = options_with_args.delete(:tester)
36
55
  @compiler = options_with_args.delete(:compiler)
37
56
  @id = options_with_args.delete(:id)
38
57
  @location = options_with_args.delete(:location)
@@ -40,6 +59,12 @@ module OrigenTesters
40
59
  @verbose = options_with_args.delete(:verbose)
41
60
  @output_directory = options_with_args.delete(:output_directory)
42
61
  @pinmap_workbook = options_with_args.delete(:pinmap_workbook)
62
+ @pinconfig = options_with_args.delete(:pinconfig)
63
+ @avc_dir = options_with_args.delete(:avc_dir)
64
+ @binl_dir = options_with_args.delete(:binl_dir)
65
+ @count = options_with_args.delete(:count) || 1
66
+ @tmf = options_with_args.delete(:tmf)
67
+ @aiv2b_opts = options_with_args.delete(:aiv2b_opts)
43
68
  @compiler_options_with_args = options_with_args.delete_if { |k, v| v.nil? } # Whatever's left has to be valid compiler options
44
69
  @compiler_options = options.delete_if { |k, v| v == false }
45
70
  end
@@ -50,10 +75,17 @@ module OrigenTesters
50
75
 
51
76
  def cmd
52
77
  cmd = ''
53
- cmd = "#{@compiler} -pinmap_workbook:#{@pinmap_workbook} -output:#{@output_directory}/#{@pattern.basename.to_s.split('.').first}.PAT #{@pattern} "
54
- # add in any remaining compiler options
55
- compiler_options.each_key { |k| cmd += "-#{k} " }
56
- compiler_options_with_args.each_pair { |k, v| cmd += "-#{k}:#{v} " }
78
+ case @tester
79
+ when :v93k
80
+ cmd = "#{resolve_compiler_location} #{@pattern} "
81
+ when :ultraflex, :j750
82
+ cmd = "#{resolve_compiler_location} -pinmap_workbook:#{@pinmap_workbook} -output:#{@output_directory}/#{@pattern.basename.to_s.split('.').first}.PAT #{@pattern} "
83
+ # add in any remaining compiler options
84
+ compiler_options.each_key { |k| cmd += "-#{k} " }
85
+ compiler_options_with_args.each_pair { |k, v| cmd += "-#{k}:#{v} " }
86
+ else
87
+ fail 'Unsupported tester'
88
+ end
57
89
  if @verbose
58
90
  cmd += ';'
59
91
  else
@@ -66,12 +98,20 @@ module OrigenTesters
66
98
  cmd
67
99
  end
68
100
 
101
+ def resolve_compiler_location
102
+ Pathname.new(@compiler).absolute? ? @compiler : eval('"' + @compiler + '"')
103
+ end
104
+
69
105
  def ready?
70
106
  ready = true
71
- ready && @output_directory.directory? &&
72
- @pattern.file? && @pinmap_workbook.file? &&
73
- [true, false].include?(@clean) &&
74
- [:local, :lsf].include?(@location)
107
+ ready &= @output_directory.directory?
108
+ ready &= @pattern.file?
109
+ ready &= @pinmap_workbook.file? if @tester == :ultraflex || @tester == :j750
110
+ ready &= @pinconfig.file? if @tester == :v93k
111
+ ready &= @tmf.file? if @tester == :v93k
112
+ ready &= [true, false].include?(@clean)
113
+ ready &= [:local, :lsf].include?(@location)
114
+ ready
75
115
  end
76
116
 
77
117
  private