Class: OrigenTesters::PatternCompilers::V93KPatternCompiler

Inherits:
BasePatternCompiler show all
Includes:
DigCapAPI, MultiportAPI
Defined in:
lib/origen_testers/pattern_compilers/v93k.rb,
lib/origen_testers/pattern_compilers/v93k/digcap.rb,
lib/origen_testers/pattern_compilers/v93k/multiport.rb

Defined Under Namespace

Modules: DigCapAPI, MultiportAPI

Constant Summary collapse

TEMPLATE =
"#{Origen.root!}/lib/origen_testers/pattern_compilers/templates/template.aiv.erb"

Instance Attribute Summary collapse

Attributes inherited from BasePatternCompiler

#id, #jobs

Class Method Summary collapse

Instance Method Summary collapse

Methods included from DigCapAPI

#digcap, #digcap?

Methods included from MultiportAPI

#multiport, #multiport?

Methods inherited from BasePatternCompiler

#clear, #count, #empty?, #inspect_options, #is_j750?, #is_ultraflex?, #is_v93k?, #name, #platform

Constructor Details

#initialize(id, options = {}) ⇒ V93KPatternCompiler

Returns a new instance of V93KPatternCompiler.



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 40

def initialize(id, options = {})
  super

  @user_options = {
    config_dir:    nil,        # Common directory where all configs can be stored
    pinconfig_dir: nil,        # Can override common config_dir if pinconfig stored elsewhere
    pinconfig:     nil,        # Can specify just file name (to use config_dir/pinconfig_dir), or give full path
    tmf_dir:       nil,        # Can override common config_dir if tmf stored elsewhere
    tmf:           nil,        # Can specify just file name (to use config_dir/tmf_dir), or give full path
    vbc_dir:       nil,        # Can override common config_dir if vbc stored elsewhere
    vbc:           nil,        # Can specify just file name (to use config_dir/vbc_dir), or give full path
    incl_dir:      nil,
    includes:      [],         # Array of files that will be copied into tmp job workspace before compilation
    tmp_dir:       nil,
    avc_dir:       nil,
    binl_dir:      nil,
    multiport:     nil,        # Optional hash for multiport settings: port_bursts, port_in_focus, prefix, postfix
    digcap:        nil,        # Optional hash for digcap settings: pins, vps, nrf, char
  }.merge(@user_options)

  @job_options = {
    tester:   :v93k,
    compiler: self.class.compiler,   # required
  }.merge(@job_options)

  @compiler_options = {

  }.merge(@compiler_options)

  @compiler_options_with_args = {
    aiv2b_opts:  nil
  }.merge(@compiler_options_with_args)

  @avc_files = []
  @vec_per_frame = {}

  update_common_options(options)      # Update common options with default (see BasePatternCompiler)
  verify_pinconfig_is_specified       # Verify pinconfig specified correctly - Smartest specific
  verify_tmf_is_specified             # Verify tmf specified correctly - Smartest specific
  clean_and_verify_options            # Standard cleaning and verifying (see BasePatternCompiler)
end

Instance Attribute Details

#avc_filesObject (readonly)

Returns the value of attribute avc_files.



9
10
11
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 9

def avc_files
  @avc_files
end

#max_avcfilename_sizeObject (readonly)

Returns the value of attribute max_avcfilename_size.



9
10
11
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 9

def max_avcfilename_size
  @max_avcfilename_size
end

#vec_per_frameObject (readonly)

Returns the value of attribute vec_per_frame.



9
10
11
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 9

def vec_per_frame
  @vec_per_frame
end

Class Method Details

.compilerObject

Resolves to correct compiler (linux is only available)



24
25
26
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 24

def self.compiler
  linux_compiler
end

.compiler_cmdObject



28
29
30
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 28

def self.compiler_cmd
  Pathname.new(compiler).absolute? ? compiler : eval('"' + compiler + '"')
end

.compiler_optionsObject



32
33
34
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 32

def self.compiler_options
  "#{compiler_cmd} -h"
end

.compiler_versionObject



36
37
38
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 36

def self.compiler_version
  "#{compiler_cmd} -V"
end

.linux_compilerObject

Linux compiler executable path



14
15
16
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 14

def self.linux_compiler
  Origen.site_config.origen_testers[:v93k_linux_pattern_compiler]
end

.windows_compilerObject

Windows compiler executable path - not available for V93K



19
20
21
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 19

def self.windows_compiler
  nil
end

Instance Method Details

#avc_digcap_vpf(contents) ⇒ Object

Given the file contents, parse and calculate number of capture vectors



313
314
315
316
317
318
319
320
321
322
323
324
325
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 313

def avc_digcap_vpf(contents)
  capture_vectors = 0
  factor = 1
  contents.each_line do |line|
    next if line.match(/^\s*\#/)
    if line.match(/^\s*SQPG\s+LBGN\s+(\d+)\s*;/)
      factor = Regexp.last_match(1).to_i
    end
    factor = 1 if line.match(/^\s*SQPG\s+LEND\s*;/)
    capture_vectors += factor if /#{digcap.capture_string}/.match(line)
  end
  capture_vectors
end

#avc_dirObject



327
328
329
330
331
332
333
334
335
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 327

def avc_dir
  @avc_dir ||= begin
    if @user_options[:avc_dir]
      clean_path(@user_options[:avc_dir].to_s)
    else
      Pathname.new('./AVC')      # default value
    end
  end
end

#binl_dirObject



337
338
339
340
341
342
343
344
345
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 337

def binl_dir
  @binl_dir ||= begin
    if @user_options[:binl_dir]
      clean_path(@user_options[:binl_dir].to_s)
    else
      Pathname.new('./BINL')     # default value
    end
  end
end

#clean_path(path_str) ⇒ Object

Given path string, return Pathname object with cleaned up path



358
359
360
361
362
363
364
365
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 358

def clean_path(path_str)
  path = Pathname.new(path_str).cleanpath
  if path.absolute?
    return path
  else
    return Pathname.new("./#{path}")
  end
end

#find_jobs(p = @path) ⇒ Object

Finds the patterns and creates a compiler job for each one found. Handles singles files (.atp, .atp.gz, or .list) and directories (recursively or flat)



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 194

def find_jobs(p = @path)
  # First-level verification: file/directory was given and exists
  msg = 'Pass in a valid file (.avc, .avc.gz, .list) or a valid directory'
  fail "Pattern path is set to nil! #{msg}" if p.nil?
  path = Pathname.new(p)
  fail "Pattern path does not exist! #{msg}" unless path.exist?
  path = path.expand_path

  # Set the reference directory for pattern sub-dir mirroring
  set_reference_directory

  # Collect file, list, or directory (recursively)
  Origen.profile 'Linux pattern compiler finds patterns' do
    if path.directory?
      # Get all of the patterns inside this dir or inside this directory recursively
      process_directory(path, @files, @user_options[:recursive])
    else
      # Found a file so no searching is necessary, process as single pattern or list
      process_file(path, @files)
    end
  end

  fail "Did not fild a valid file to compile! #{msg}" if @files.empty?

  Origen.profile 'Linux pattern compiler creates job' do
    # For V93K, only single AIV file is really sent to the compiler, but need list of all
    #   avc files that will be compiled using that aiv file, so keep a separate array.
    @max_avcfilename_size = 0
    @files.each do |f|
      @avc_files << Pathname.new(f).basename.sub_ext('').to_s
      @max_avcfilename_size = @avc_files[-1].size > @max_avcfilename_size ? @avc_files[-1].size : @max_avcfilename_size
    end

    rel_dir = Pathname.new("#{path.dirname.to_s[@user_options[:reference_directory].to_s.size..-1]}")

    # Resolve output directory
    if @job_options[:output_directory].nil?
      # job output dir not specified, create a unique (hash) based on path/compiler_name
      s = Digest::MD5.new
      s << @user_options[:reference_directory].to_s
      s << @id.to_s
      out = "#{@user_options[:reference_directory]}/job_#{@id}_#{s.to_s[0..6].upcase}#{rel_dir}"
      job_output_dir = Pathname.new(out)
    else
      job_output_dir = Pathname.new("#{@job_options[:output_directory]}#{rel_dir}")
    end

    # Create any necessary output directories before trying to compile
    unless job_output_dir.directory?
      puts "Output directory #{job_output_dir} does not exist, creating it..."
      FileUtils.mkdir_p(job_output_dir)
    end

    job_avc_dir = avc_dir.absolute? ? avc_dir : Pathname.new("#{job_output_dir}/#{avc_dir}").cleanpath
    unless job_avc_dir.directory?
      puts "AVC Output directory #{job_avc_dir} does not exist, creating it..."
      FileUtils.mkdir_p(job_avc_dir)
    end
    job_binl_dir = binl_dir.absolute? ? binl_dir : Pathname.new("#{job_output_dir}/#{binl_dir}").cleanpath
    unless job_binl_dir.directory?
      puts "BINL Output directory #{job_binl_dir} does not exist, creating it..."
      FileUtils.mkdir_p(job_binl_dir)
    end

    # Move AVC files into job space (through pre-processor)
    @files.each do |file|
      contents = File.open(file, 'rb') { |f| f.read }
      new_contents = preprocess_avc(contents)
      new_avc_file = Pathname.new("#{job_avc_dir}/#{Pathname.new(file).basename}").cleanpath
      File.open(new_avc_file, 'w') { |f| f.write(new_contents.force_encoding('UTF-8')) }
      avc_key = Pathname.new(file).basename.sub_ext('').to_s.to_sym
      @vec_per_frame[avc_key] = digcap? ? avc_digcap_vpf(new_contents) : 0
    end

    # Generate the AIV file using the template with all the pattern compiler parameters
    aiv_file = "#{job_output_dir}/#{path.basename.to_s.split('.')[0]}.aiv"
    Origen.log.info "Creating...  #{aiv_file}"
    contents = Origen.compile(self.class::TEMPLATE, scope: self, preserve_target: true)
    File.open(aiv_file, 'w') { |f| f.write(contents) }

    # Copy Timing Map File to local AIV workspace
    dest = Pathname.new("#{job_output_dir}/#{tmf_file.basename}").cleanpath
    FileUtils.cp tmf_file, dest

    # Copy VBC file to local AIV workspace (if specified)
    if vbc_file
      dest = Pathname.new("#{job_output_dir}/#{vbc_file.basename}").cleanpath
      FileUtils.cp vbc_file, dest
    end

    # Copy any extra files needed (includes)
    @user_options[:includes].each do |incl|
      src = build_file(:incl, incl)
      dest = Pathname.new("#{job_output_dir}/#{src.basename}").cleanpath
      FileUtils.cp src, dest
    end

    # Gather up job options
    current_job_options = @job_options.merge(@compiler_options_with_args)
    current_job_options[:output_directory] = job_output_dir
    current_job_options[:pinconfig] = pinconfig_file
    current_job_options[:tmf] = tmf_file
    current_job_options[:count] = @avc_files.count
    current_job_options[:avc_dir] = avc_dir
    current_job_options[:binl_dir] = binl_dir

    # Create new job
    @jobs << Job.new(Pathname.new(aiv_file), current_job_options, @compiler_options)
    current_job_options = {}
  end

  # Clear files and avc_files now that job has successfully been queued
  @files = []
  @avc_files = []
  @vec_per_frame = {}
  inspect_jobs
end

#inspect_jobs(index = nil) ⇒ Object

Output the compiler jobs in the queue to the console



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 164

def inspect_jobs(index = nil)
  return empty_msg if empty?
  desc = []
  puts "\n"
  @jobs.each_with_index do |j, i|
    unless index.nil?
      next unless i == index
    end
    desc << '| Job: ' + " #{i + 1} ".rjust(8) + '|' + 'Pattern/AIV:'.rjust(18) + " #{j.pattern.basename}".ljust(125) + '|'
    desc << '|              |' + 'Compiler ID:'.rjust(18) + " #{j.id} ".ljust(125) + '|'
    desc << '|              |' + 'AVC Files:'.rjust(18) + " #{j.count} ".ljust(125) + '|'
    desc << '|              |' + 'Output Directory:'.rjust(18) + " #{j.output_directory} ".ljust(125) + '|'
    desc << '|              |' + '.avc directory:'.rjust(18) + " #{j.avc_dir} ".ljust(125) + '|'
    desc << '|              |' + '.binl directory:'.rjust(18) + " #{j.binl_dir} ".ljust(125) + '|'
    desc << '|              |' + 'LSF:'.rjust(18) + " #{j.location == :lsf ? true : false} ".ljust(125) + '|'
    desc << '|              |' + 'Delete log files:'.rjust(18) + " #{j.clean} ".ljust(125) + '|'
    desc << '|              |' + 'Verbose:'.rjust(18) + " #{j.verbose} ".ljust(125) + '|'
    if j.aiv2b_opts && j.aiv2b_opts.is_a?(String)
      aiv2b_opts = j.aiv2b_opts.gsub('AI_V2B_OPTIONS ', '')
    else
      aiv2b_opts = render_aiv2b_options_line.gsub('AI_V2B_OPTIONS', '')
    end
    desc << '|              |' + 'AI_V2B Options:'.rjust(18) + " #{aiv2b_opts} ".ljust(125) + '|'
    desc << '-' * desc.first.size
  end
  puts desc.flatten.join("\n")
end

#pinconfig_fileObject



82
83
84
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 82

def pinconfig_file
  @pinconfig_file ||= build_file(:pinconfig)
end

#preprocess_avc(contents) ⇒ Object

Placeholder - TopLevel can monkey patch this method to do more

sophisticated AVC modification prior to compilation


369
370
371
372
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 369

def preprocess_avc(contents)
  new_contents = contents   # no manipulation done here
  new_contents
end

#render_aiv2b_options_lineObject



374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 374

def render_aiv2b_options_line
  line = 'AI_V2B_OPTIONS'
  if @compiler_options_with_args[:aiv2b_opts]
    if @compiler_options_with_args[:aiv2b_opts].is_a? Array
      @compiler_options_with_args[:aiv2b_opts].each do |opt|
        line += " #{opt}"
      end
    elsif @compiler_options_with_args[:aiv2b_opts].is_a? String
      line += " #{@compiler_options[:aiv2b]}"
    else
      fail 'aiv2b options must be an array or string'
    end
  end
  line += " -c #{vbc_file.basename}" if vbc_file
  line
end

#render_aiv_patterns_entry(pattern) ⇒ Object



399
400
401
402
403
404
405
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 399

def render_aiv_patterns_entry(pattern)
  line = '         '
  line += "#{pattern}".ljust(max_avcfilename_size + 2)
  line += "#{multiport.port_in_focus}".ljust(multiport.port_in_focus.size + 2) if multiport?
  line += "#{tmf_file.basename}"
  line
end

#render_aiv_patterns_headerObject



391
392
393
394
395
396
397
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 391

def render_aiv_patterns_header
  line = 'PATTERNS '
  line += 'name'.ljust(max_avcfilename_size + 2)
  line += 'port'.ljust(multiport.port_in_focus.size + 2) if multiport?
  line += 'tmf_file'
  line
end

#run(aiv = nil, options = {}) ⇒ Object

Executes the compiler for each job in the queue



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 105

def run(aiv = nil, options = {})
  aiv, options = nil, aiv if aiv.is_a? Hash

  fail "Error: the tester #{Origen.tester} is not an V93K tester, exiting..." unless is_v93k?

  msg = "Error: application #{Origen.app.name} is running on Windows, "
  msg += 'to run the pattern compiler you must be on a Linux machine'
  fail msg if Origen.running_on_windows?

  # Check if there was a pattern list passed as an argument
  # If so, then compile the patterns inside it.
  # Otherwise compile the jobs in the queue
  if aiv.nil?
    if empty?
      empty_msg
      return
    end
    @jobs.each do |job|
      unless options[:ignore_ready]
        fail "Error: compiler #{job.id} not ready for pattern #{job.name}" unless job.ready?
      end
      if job.location == :lsf
        # puts "#{self.class.aiv_setup} ; #{job.cmd}"
        # Origen.app.lsf.submit(self.class.aiv_setup + '; ' + job.cmd)
        Origen.app.lsf.submit(job.cmd)
      else
        Origen.profile "Linux pattern compiler compiles pattern #{job.pattern}" do
          Dir.chdir(job.output_directory) do
            # puts "#{job.cmd}"
            system job.cmd
          end
        end
      end
    end
    if @job_options[:location] == :local
      if @job_options[:clean] == true
        puts 'Log file :clean option set to true, deleting log files'
        clean_output
      end
    end
    # Clear @jobs
    clear

  else
    # Assumes .aiv file and all workspace collateral has been built up
    aiv = convert_to_pathname(aiv)
    fail 'File does not exist!  Please specify existing aiv file.' unless aiv.file?
    current_job_options = @job_options.merge(@compiler_options_with_args)
    current_job_options = current_job_options.merge(extract_job_options_from_aiv(aiv))
    current_job_options = current_job_options.merge(options)
    current_job_options[:output_directory] = aiv.dirname

    @jobs << Job.new(Pathname.new(aiv), current_job_options, @compiler_options)
    inspect_jobs
    run(options)
  end
end

#tmf_fileObject



86
87
88
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 86

def tmf_file
  @tmf_file ||= build_file(:tmf)
end

#tmp_dirObject



347
348
349
350
351
352
353
354
355
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 347

def tmp_dir
  @tmp_dir ||= begin
    if @user_options[:tmp_dir]
      clean_path(@user_options[:tmp_dir].to_s)
    else
      Pathname.new('./tmp')     # default value
    end
  end
end

#vbc_fileObject



90
91
92
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 90

def vbc_file
  @vbc_file ||= build_file(:vbc)
end

#verify_pinconfig_is_specifiedObject



94
95
96
97
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 94

def verify_pinconfig_is_specified
  fail 'Pinconfig file is not defined!  Pass as an option.' if pinconfig_file.nil?
  fail 'Pinconfig is not a file!' unless pinconfig_file.file?
end

#verify_tmf_is_specifiedObject



99
100
101
102
# File 'lib/origen_testers/pattern_compilers/v93k.rb', line 99

def verify_tmf_is_specified
  fail 'Timing Map File (tmf) is not defined!  Pass as an option.' if tmf_file.nil?
  fail 'Timing Map File (tmf) is not a file!' unless tmf_file.file?
end