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.
- checksums.yaml +4 -4
- data/config/shared_commands.rb +11 -19
- data/config/version.rb +1 -1
- data/lib/origen_testers.rb +2 -0
- data/lib/origen_testers/callback_handlers.rb +7 -25
- data/lib/origen_testers/origen_ext/generator.rb +1 -1
- data/lib/origen_testers/pattern_compilers.rb +120 -66
- data/lib/origen_testers/pattern_compilers/assembler.rb +7 -3
- data/lib/origen_testers/pattern_compilers/base.rb +266 -0
- data/lib/origen_testers/pattern_compilers/igxl_based.rb +348 -0
- data/lib/origen_testers/pattern_compilers/j750.rb +80 -0
- data/lib/origen_testers/pattern_compilers/job.rb +49 -9
- data/lib/origen_testers/pattern_compilers/runner.rb +40 -0
- data/lib/origen_testers/pattern_compilers/templates/template.aiv.erb +31 -0
- data/lib/origen_testers/pattern_compilers/ultraflex.rb +92 -0
- data/lib/origen_testers/pattern_compilers/v93k.rb +455 -0
- data/lib/origen_testers/pattern_compilers/v93k/digcap.rb +107 -0
- data/lib/origen_testers/pattern_compilers/v93k/multiport.rb +80 -0
- metadata +14 -6
- data/lib/origen_testers/pattern_compilers/ultraflex_pattern_compiler.rb +0 -599
@@ -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
|