origen_testers 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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