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,107 @@
|
|
1
|
+
module OrigenTesters
|
2
|
+
module PatternCompilers
|
3
|
+
class V93KPatternCompiler
|
4
|
+
module DigCapAPI
|
5
|
+
class DigCap
|
6
|
+
attr_accessor :owner, :pins, :vps, :nrf, :char
|
7
|
+
|
8
|
+
def initialize(owner, options)
|
9
|
+
@owner = owner
|
10
|
+
@pins = nil
|
11
|
+
|
12
|
+
if options && options[:pins] && options[:vps]
|
13
|
+
@pins = options[:pins] # required: pins to be captured
|
14
|
+
@vps = options[:vps] # required: vecotrs per sample
|
15
|
+
@nrf = options[:nrf] || 1 # optional: nr_frames (defaults to 1)
|
16
|
+
@char = options[:char] || 'C' # optional: vector character representing capture
|
17
|
+
elsif options
|
18
|
+
fail 'Must specifiy pins and vps for digcap setup!'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def render_aiv_lines
|
23
|
+
lines = []
|
24
|
+
lines << ''
|
25
|
+
lines << 'AI_DIGCAP_SETTINGS {'
|
26
|
+
lines << render_digcap_header
|
27
|
+
avc_files.each do |f|
|
28
|
+
if vec_per_frame[f.to_sym] > 0
|
29
|
+
lines << render_digcap_entry(f)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
lines << '};'
|
33
|
+
lines
|
34
|
+
end
|
35
|
+
|
36
|
+
def capture_string
|
37
|
+
" #{char * num_pins} "
|
38
|
+
end
|
39
|
+
|
40
|
+
def num_pins
|
41
|
+
if pins.is_a? String
|
42
|
+
pins.split(' ').size
|
43
|
+
elsif pins.is_a? Symbol
|
44
|
+
dut.pins(pins).size
|
45
|
+
elsif pins.is_a? Array
|
46
|
+
fail 'Digcap Pins does not support array yet'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def enabled?
|
51
|
+
pins.nil? ? false : true
|
52
|
+
end
|
53
|
+
|
54
|
+
def empty?
|
55
|
+
vec_per_frame.each do |k, v|
|
56
|
+
return false if v > 0
|
57
|
+
end
|
58
|
+
true # digcap setup but no avc contain capture vectors
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def render_digcap_header
|
64
|
+
line = 'variable'.ljust(max_filename_size + 4)
|
65
|
+
line += ' '
|
66
|
+
line += 'label'.ljust(max_filename_size)
|
67
|
+
line += ' '
|
68
|
+
line += 'vec_per_frame vec_per_sample nr_frames {pins};'
|
69
|
+
line
|
70
|
+
end
|
71
|
+
|
72
|
+
def render_digcap_entry(pattern)
|
73
|
+
line = "#{pattern}_var".ljust(max_filename_size + 4)
|
74
|
+
line += ' '
|
75
|
+
line += "#{pattern}".ljust(max_filename_size)
|
76
|
+
line += ' '
|
77
|
+
line += "#{vec_per_frame[pattern.to_sym]}".ljust(15)
|
78
|
+
line += "#{vps}".ljust(16)
|
79
|
+
line += "#{nrf}".ljust(11)
|
80
|
+
line += "{#{pins}};"
|
81
|
+
line
|
82
|
+
end
|
83
|
+
|
84
|
+
def avc_files
|
85
|
+
owner.avc_files
|
86
|
+
end
|
87
|
+
|
88
|
+
def max_filename_size
|
89
|
+
owner.max_avcfilename_size
|
90
|
+
end
|
91
|
+
|
92
|
+
def vec_per_frame
|
93
|
+
owner.vec_per_frame
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def digcap
|
98
|
+
@digcap ||= DigCap.new(self, @user_options[:digcap])
|
99
|
+
end
|
100
|
+
|
101
|
+
def digcap?
|
102
|
+
digcap.enabled?
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module OrigenTesters
|
2
|
+
module PatternCompilers
|
3
|
+
class V93KPatternCompiler
|
4
|
+
module MultiportAPI
|
5
|
+
class Multiport
|
6
|
+
attr_accessor :port_in_focus, :port_bursts, :prefix, :postfix
|
7
|
+
|
8
|
+
def initialize(options)
|
9
|
+
@port_in_focus = nil
|
10
|
+
|
11
|
+
if options && options[:port_in_focus]
|
12
|
+
@port_in_focus = options[:port_in_focus]
|
13
|
+
@port_bursts = options[:port_bursts]
|
14
|
+
@prefix = options[:prefix].nil? ? '' : "#{options[:prefix]}_"
|
15
|
+
@postfix = options[:postfix].nil? ? '' : "_#{options[:postfix]}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def render_aiv_lines(pattern)
|
20
|
+
mpb_entry = []
|
21
|
+
mpb_entry << ''
|
22
|
+
mpb_entry << render_mpb_header(pattern)
|
23
|
+
mpb_entry << render_mpb_port_line(pattern)
|
24
|
+
mpb_entry << render_mpb_burst_line(pattern)
|
25
|
+
mpb_entry
|
26
|
+
end
|
27
|
+
|
28
|
+
def enabled?
|
29
|
+
port_in_focus.nil? ? false : true
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def render_mpb_header(pattern)
|
35
|
+
"MULTI_PORT_BURST #{prefix}#{pattern}#{postfix}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def render_mpb_port_line(pattern)
|
39
|
+
line = 'PORTS '
|
40
|
+
line += port_in_focus.to_s
|
41
|
+
line += mpb_padding(port_in_focus.to_s, pattern, 0)
|
42
|
+
if port_bursts
|
43
|
+
port_bursts.each do |k, v|
|
44
|
+
line += k.to_s
|
45
|
+
line += mpb_padding(k.to_s, v.to_s, 0)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
line
|
49
|
+
end
|
50
|
+
|
51
|
+
def render_mpb_burst_line(pattern)
|
52
|
+
line = ' '
|
53
|
+
line += pattern.to_s
|
54
|
+
line += mpb_padding(port_in_focus.to_s, pattern, 1)
|
55
|
+
if port_bursts
|
56
|
+
port_bursts.each do |k, v|
|
57
|
+
line += v.to_s
|
58
|
+
line += mpb_padding(k.to_s, v.to_s, 1)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
line
|
62
|
+
end
|
63
|
+
|
64
|
+
def mpb_padding(str0, str1, index = 0)
|
65
|
+
width = str0.size > str1.size ? str0.size : str1.size
|
66
|
+
index == 0 ? ' ' * (width + 2 - str0.size) : ' ' * (width + 2 - str1.size)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def multiport
|
71
|
+
@multiport ||= Multiport.new(@user_options[:multiport])
|
72
|
+
end
|
73
|
+
|
74
|
+
def multiport?
|
75
|
+
multiport.enabled?
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: origen_testers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.15.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen McGinty
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-11-
|
11
|
+
date: 2017-11-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: origen
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.26.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.26.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: require_all
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -233,8 +233,16 @@ files:
|
|
233
233
|
- lib/origen_testers/parser/searchable_hash.rb
|
234
234
|
- lib/origen_testers/pattern_compilers.rb
|
235
235
|
- lib/origen_testers/pattern_compilers/assembler.rb
|
236
|
+
- lib/origen_testers/pattern_compilers/base.rb
|
237
|
+
- lib/origen_testers/pattern_compilers/igxl_based.rb
|
238
|
+
- lib/origen_testers/pattern_compilers/j750.rb
|
236
239
|
- lib/origen_testers/pattern_compilers/job.rb
|
237
|
-
- lib/origen_testers/pattern_compilers/
|
240
|
+
- lib/origen_testers/pattern_compilers/runner.rb
|
241
|
+
- lib/origen_testers/pattern_compilers/templates/template.aiv.erb
|
242
|
+
- lib/origen_testers/pattern_compilers/ultraflex.rb
|
243
|
+
- lib/origen_testers/pattern_compilers/v93k.rb
|
244
|
+
- lib/origen_testers/pattern_compilers/v93k/digcap.rb
|
245
|
+
- lib/origen_testers/pattern_compilers/v93k/multiport.rb
|
238
246
|
- lib/origen_testers/program_generators.rb
|
239
247
|
- lib/origen_testers/smartest_based_tester.rb
|
240
248
|
- lib/origen_testers/smartest_based_tester/base.rb
|
@@ -348,7 +356,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
348
356
|
version: 1.8.11
|
349
357
|
requirements: []
|
350
358
|
rubyforge_project:
|
351
|
-
rubygems_version: 2.
|
359
|
+
rubygems_version: 2.6.7
|
352
360
|
signing_key:
|
353
361
|
specification_version: 4
|
354
362
|
summary: This plugin provides Origen tester models to drive ATE type testers like
|
@@ -1,599 +0,0 @@
|
|
1
|
-
module OrigenTesters
|
2
|
-
module PatternCompilers
|
3
|
-
class UltraFlexPatternCompiler
|
4
|
-
require 'pathname'
|
5
|
-
require_relative 'assembler'
|
6
|
-
require_relative 'job'
|
7
|
-
|
8
|
-
# Linux compiler executable path
|
9
|
-
LINUX_PATTERN_COMPILER = "#{Origen.root!}/bin/latest/bin/atpcompiler"
|
10
|
-
# LINUX_PATTERN_COMPILER = "#{Origen.root!}/bin/latest/bin/atpcompiler"
|
11
|
-
|
12
|
-
# Windows compiler executable path
|
13
|
-
WINDOWS_PATTERN_COMPILER = "#{ENV['IGXLROOT']}/bin/apc.exe"
|
14
|
-
|
15
|
-
# Linux compiler preamble
|
16
|
-
ATPC_SETUP = "#{Origen.root!}/bin/latest/etc/atpcrc.csh"
|
17
|
-
|
18
|
-
# ID will allow users to set default configurations for the compiler for unique pattern types
|
19
|
-
attr_accessor :id
|
20
|
-
|
21
|
-
# Compiler commands array
|
22
|
-
attr_accessor :jobs
|
23
|
-
|
24
|
-
def initialize(id, options = {})
|
25
|
-
@id = id
|
26
|
-
@id = @id.to_sym
|
27
|
-
|
28
|
-
@user_options = {
|
29
|
-
path: nil, # required: will be passed in or parsed from a .list file
|
30
|
-
reference_directory: nil, # optional: will be set to @path or Origen.app.config.pattern_output_directory
|
31
|
-
target: nil, # optional: allows user to temporarily set target and run compilation
|
32
|
-
recursive: false # optional: controls whether to look for patterns in a directory recursively
|
33
|
-
}
|
34
|
-
@job_options = {
|
35
|
-
compiler: running_on_windows? ? WINDOWS_PATTERN_COMPILER : LINUX_PATTERN_COMPILER, # required
|
36
|
-
id: @id, # required
|
37
|
-
pinmap_workbook: $dut.pinmap, # required: will default to $dut.pinmap
|
38
|
-
location: :local, # optional: controls whether the commands go to the LSF or run locally
|
39
|
-
clean: false, # optional: controls whether compiler log files are deleted after compilation
|
40
|
-
output_directory: nil, # optional:
|
41
|
-
verbose: false # optional: controls whether the compiler output gets put to STDOUT
|
42
|
-
}
|
43
|
-
@compiler_options = { # Set all of these compiler options that don't have args to true/flase. if true then send compiler '-opt'
|
44
|
-
import_all_undefineds: false, # automatically import all undefined symbols. the key is mis-spelled but correct!
|
45
|
-
cpp: false, # runs C++ preprocessor on pattern file
|
46
|
-
comments: false, # saves comments in binary file for tools visibility. pass '-comments' if set to true
|
47
|
-
# pass nothing if set to false
|
48
|
-
nocompress: false, # do not compress pattern data blocks
|
49
|
-
suppress_log: false, # disables output to main log file
|
50
|
-
multiinst: false, # indicates more than one instrument is connected to a single pin
|
51
|
-
lock: false, # prevents pattern from being reverse compiled or opened in PatternTool
|
52
|
-
stdin: false, # Compile data from standard input. Do not use -cpp or specify any pattern file(s) when using this option.
|
53
|
-
debug: false, # generate intermediate file(s) to simplify debug ( application dependent )
|
54
|
-
template: false, # generate setup template
|
55
|
-
timestamp: false, # enable log timestamp
|
56
|
-
}
|
57
|
-
@compiler_options_with_args = {
|
58
|
-
output: nil, # Output filename, compiler defaults to <pattern name>.PAT
|
59
|
-
pinmap_sheet: nil, # <sheetname>
|
60
|
-
digital_inst: nil, # 'HSD4G', 'HSDM', or 'HSDMQ'
|
61
|
-
opcode_mode: nil, # HSDM mode: 'single' | 'dual'. HSDMQ mode: 'single' | 'dual' | 'quad'
|
62
|
-
pat_version: nil, # version of pattern file to compile
|
63
|
-
scan_type: nil, # type of scan data
|
64
|
-
max_errors: nil, # <n>, defaults to 200 on compiler side, valu eof 0 will never abort compilation
|
65
|
-
logfile: nil, # <filename>, directs any compiler messages to <filename>. will default to output directory if nil
|
66
|
-
define: nil, # defines values of macros passed to C++ preprocessor.
|
67
|
-
# can only be defined once per pattern with space delimited list
|
68
|
-
includes: nil, # include paths to be passed to C- preprocessor.
|
69
|
-
post_processor: nil, # <pathname> customer's post-process executable.
|
70
|
-
# need to pass 'post-processor' to compiler
|
71
|
-
post_processor_args: nil, # <args> customer's post-process executable arguments
|
72
|
-
# need to pass 'post-processor_args' to compiler
|
73
|
-
cdl_cache: nil, # 'yes' | 'no', turns on/off CDL caching, default on compiler side is 'yes'
|
74
|
-
init_pattern: nil, # <pattern>, uses the specified pattern module/file/set as an init patterns
|
75
|
-
check_set_msb: nil, # 'yes' | 'no', turns on/off check the 'set' or 'set_infinite' opcode
|
76
|
-
# is preceded by a 'set_msb' or 'set_msb_infinite' opcode. compiler default is 'yes'
|
77
|
-
time_domain: nil, # <time domain>, specifies time domain for pins in patterns
|
78
|
-
allow_mto_dash: nil, # Turn on/off support for channel data runtime repeat,i.e. vector dash in MTO patterns. Default value is "no".
|
79
|
-
check_vm_min_size: nil, # Turns on/off the check on minimum size of a VM pattern. Default value is "yes".
|
80
|
-
check_vm_mod_size: nil, # Turns on/off the check on a VM pattern module size. Default value is "yes".
|
81
|
-
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".
|
82
|
-
allow_mixed_1x2x: nil, # Turns on/off the support of mixed 1x/2x pin groups. Default value is "no".
|
83
|
-
allow_differential: nil, # Turns on/off support for differential pins. Default value is "yes".
|
84
|
-
allow_scan_in_srm: nil, # Allow/disallow scan vectors in SRM pattern modules. Default value is "no".
|
85
|
-
vm_block_size: nil, # Specifies uncompressed size in bytes of a pattern data block
|
86
|
-
setup: nil, # path to setup file
|
87
|
-
}
|
88
|
-
|
89
|
-
@user_options.update_common(options)
|
90
|
-
@job_options.update_common(options)
|
91
|
-
@compiler_options.update_common(options)
|
92
|
-
@compiler_options_with_args.update_common(options)
|
93
|
-
|
94
|
-
# Check to make sure @compiler_options and @compiler_options_with_args do not have any keys in common
|
95
|
-
fail "Error: @compiler_options and @compiler_options_with_args share keys #{@compiler_options.intersections(@compiler_options_with_args)}. They should be mutually exclusive, exiting..." if @compiler_options.intersect? @compiler_options_with_args
|
96
|
-
|
97
|
-
# Convert any path related options to Pathname object and expand the path
|
98
|
-
unless @user_options[:path].nil?
|
99
|
-
if @user_options[:path].is_a? Pathname
|
100
|
-
@path = @user_options[:path]
|
101
|
-
else
|
102
|
-
@path = Pathname.new(@user_options[:path])
|
103
|
-
end
|
104
|
-
@path = @path.expand_path
|
105
|
-
# path is set but output_directory is not so set output_directory to path
|
106
|
-
@job_options[:output_directory] = @path if @job_options[:output_directory].nil?
|
107
|
-
end
|
108
|
-
|
109
|
-
set_reference_directory
|
110
|
-
|
111
|
-
if @job_options[:output_directory].nil?
|
112
|
-
fail 'Output directory is not set!'
|
113
|
-
else
|
114
|
-
@job_options[:output_directory] = convert_to_pathname(@job_options[:output_directory])
|
115
|
-
# output_directory can not exist, will create for user
|
116
|
-
unless @job_options[:output_directory].directory?
|
117
|
-
puts "Output directory #{@job_options[:output_directory]} does not exist, creating it..."
|
118
|
-
FileUtils.mkdir_p(@job_options[:output_directory])
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
# Pinmap is required
|
123
|
-
if @job_options[:pinmap_workbook].nil?
|
124
|
-
# Check if the app has $dut.pinmap defined
|
125
|
-
if File.exist? $dut.pinmap
|
126
|
-
@job_options[:pinmap_workbook] = $dut.pinmap
|
127
|
-
else
|
128
|
-
fail 'Pinmap is not defined! Pass as an option or set $dut.pinmap.'
|
129
|
-
end
|
130
|
-
end
|
131
|
-
@job_options[:pinmap_workbook] = convert_to_pathname(@job_options[:pinmap_workbook])
|
132
|
-
fail 'Pinmap is not a file' unless @job_options[:pinmap_workbook].file?
|
133
|
-
|
134
|
-
# Logfile is optional
|
135
|
-
unless @compiler_options[:logfile].nil?
|
136
|
-
@compiler_options[:logfile] = convert_to_pathname(@compiler_options[:logfile])
|
137
|
-
fail 'Pinmap is not a file' unless @job_options[:pinmap_workbook].file?
|
138
|
-
end
|
139
|
-
|
140
|
-
# Check if the LSF is setup in the application
|
141
|
-
if Origen.app.config.lsf.project.nil? || Origen.app.config.lsf.project.empty?
|
142
|
-
puts 'LSF is not set at Origen.app.config.lsf.project, changing to local compilation'
|
143
|
-
@job_options[:location] = :local
|
144
|
-
end
|
145
|
-
|
146
|
-
# Compiler jobs
|
147
|
-
@jobs = []
|
148
|
-
|
149
|
-
# .atp/.atp.gz files found
|
150
|
-
@files = []
|
151
|
-
end
|
152
|
-
|
153
|
-
# Return the id/name of the compiler instance
|
154
|
-
def name
|
155
|
-
@id
|
156
|
-
end
|
157
|
-
|
158
|
-
# Return the compiler instance pinmap
|
159
|
-
def pinmap
|
160
|
-
@job_options[:pinmap_workbook]
|
161
|
-
end
|
162
|
-
|
163
|
-
# Allow users to search for a pattern in the job queue or default
|
164
|
-
# to return all jobs
|
165
|
-
def jobs(search = nil)
|
166
|
-
found = false
|
167
|
-
if search.nil?
|
168
|
-
inspect_jobs
|
169
|
-
found = true
|
170
|
-
elsif search.is_a? String
|
171
|
-
@jobs.each_with_index do |job, index|
|
172
|
-
if job.pattern.to_s.match(search)
|
173
|
-
inspect_jobs(index)
|
174
|
-
found = true
|
175
|
-
else
|
176
|
-
puts "No match found for #{search}"
|
177
|
-
end
|
178
|
-
end
|
179
|
-
elsif search.is_a? Regexp
|
180
|
-
@jobs.each_with_index do |job, index|
|
181
|
-
if search.match(job.pattern.to_s)
|
182
|
-
inspect_jobs(index)
|
183
|
-
found = true
|
184
|
-
else
|
185
|
-
puts "No match found for #{search}"
|
186
|
-
end
|
187
|
-
end
|
188
|
-
elsif search.is_a? Integer
|
189
|
-
if @jobs[search].nil?
|
190
|
-
puts "The compiler queue does not contain a job at index #{search}"
|
191
|
-
else
|
192
|
-
inspect_jobs(search)
|
193
|
-
found = true
|
194
|
-
end
|
195
|
-
else
|
196
|
-
fail 'Search argument must be of type String, Regexp, or Integer'
|
197
|
-
end
|
198
|
-
found
|
199
|
-
end
|
200
|
-
|
201
|
-
# Finds the patterns and creates a compiler job for each one found.
|
202
|
-
# Handles singles files (.atp, .atp.gz, or .list) and directories (recursively or flat)
|
203
|
-
def find_jobs(path = @path)
|
204
|
-
fail 'Pattern path is set to nil, pass in a valid file (.atp or .atp.gz) or a valid directory' if path.nil?
|
205
|
-
@path = Pathname.new(path)
|
206
|
-
fail 'Pattern path does not exist, pass in a valid file (.atp or .atp.gz) or a valid directory' unless @path.exist?
|
207
|
-
@path = @path.expand_path
|
208
|
-
# Set the reference directory for pattern sub-dir mirroring
|
209
|
-
set_reference_directory
|
210
|
-
Origen.profile 'Linux pattern compiler finds patterns' do
|
211
|
-
# Check if the path is a file or a directory
|
212
|
-
if @path.directory?
|
213
|
-
# Get all of the patterns inside this dir or inside this directory recursively
|
214
|
-
# Check if the recursive arg was passed
|
215
|
-
if @user_options[:recursive] == true
|
216
|
-
process_directory(@path, @files, true)
|
217
|
-
else # Just grab the files found inside this directory
|
218
|
-
process_directory(@path, @files, false)
|
219
|
-
end
|
220
|
-
elsif @path.file? # Found a file so no searching is necessary
|
221
|
-
process_file(@path, @files)
|
222
|
-
else # Didn't find a directory or a file so user must want a search for this arg string * NOT SUPPORTED YET
|
223
|
-
fail 'Error: Did not find a file or directory to compile, exiting...'
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
Origen.profile 'Linux pattern compiler creates jobs' do
|
228
|
-
@files.each do |f|
|
229
|
-
rel_dir = Pathname.new("#{f.dirname.to_s[@user_options[:reference_directory].to_s.size..-1]}")
|
230
|
-
output_dir = Pathname.new("#{@job_options[:output_directory]}#{rel_dir}")
|
231
|
-
unless output_dir.directory?
|
232
|
-
puts "Output directory #{output_dir} for pattern #{f.basename} does not exist, creating it..."
|
233
|
-
FileUtils.mkdir_p(output_dir)
|
234
|
-
end
|
235
|
-
current_job_options = @job_options.merge(@compiler_options_with_args)
|
236
|
-
current_job_options[:output_directory] = output_dir
|
237
|
-
@jobs << Job.new(f, current_job_options, @compiler_options)
|
238
|
-
current_job_options = {}
|
239
|
-
end
|
240
|
-
end
|
241
|
-
@files = []
|
242
|
-
if empty?
|
243
|
-
empty_msg
|
244
|
-
else
|
245
|
-
inspect_jobs
|
246
|
-
end
|
247
|
-
end
|
248
|
-
alias_method :find, :find_jobs
|
249
|
-
|
250
|
-
# Executes the compiler for each job in the queue
|
251
|
-
def run(list = nil, options = {})
|
252
|
-
fail "Error: the tester #{Origen.tester} is not an Ultrflex tester,exiting..." unless is_ultraflex?
|
253
|
-
fail "Error: application #{Origen.app.name} is running on Windows, to run the pattern compiler you must be on a Linux machine" if running_on_windows?
|
254
|
-
|
255
|
-
# Check if there was a pattern list passed as an argument
|
256
|
-
# If so, then compile the patterns inside it.
|
257
|
-
# Otherwise compile the jobs in the queue
|
258
|
-
if list.nil?
|
259
|
-
if empty?
|
260
|
-
empty_msg
|
261
|
-
return
|
262
|
-
end
|
263
|
-
@jobs.each do |job|
|
264
|
-
fail "Error: compiler #{job.id} not ready for pattern #{job.name}" unless job.ready?
|
265
|
-
if job.location == :lsf
|
266
|
-
Origen.app.lsf.submit(ATPC_SETUP + '; ' + job.cmd)
|
267
|
-
else
|
268
|
-
Origen.profile "Linux pattern compiler compiles pattern #{job.pattern}" do
|
269
|
-
system job.cmd
|
270
|
-
end
|
271
|
-
end
|
272
|
-
end
|
273
|
-
if @job_options[:location] == :local
|
274
|
-
if @job_options[:clean] == true
|
275
|
-
puts 'Log file :clean option set to true, deleting log files'
|
276
|
-
clean_output
|
277
|
-
end
|
278
|
-
end
|
279
|
-
# Clear @jobs
|
280
|
-
clear
|
281
|
-
else
|
282
|
-
list = convert_to_pathname(list)
|
283
|
-
fail "Error: pattern list #{list} does not exist, exiting..." unless list.file?
|
284
|
-
File.open(list, 'r') do |file|
|
285
|
-
while (line = file.gets)
|
286
|
-
current_job_options = @job_options.merge(@compiler_options_with_args)
|
287
|
-
current_job_options.update_common(options)
|
288
|
-
# puts "current job options is #{current_job_options}"
|
289
|
-
compiler_opts = {}
|
290
|
-
line.strip!
|
291
|
-
pattern = line.match(/^(\S+)\s+(.*)/).captures[0]
|
292
|
-
unless File.file? pattern
|
293
|
-
puts "Warning: Pattern #{pattern} does not exist, skipping..."
|
294
|
-
next
|
295
|
-
end
|
296
|
-
pattern = convert_to_pathname(pattern)
|
297
|
-
line.match(/^\S+\s+(.*)/).captures[0].split(/\s+/).each do |e|
|
298
|
-
opt, arg = e.split(':')
|
299
|
-
opt.gsub!('-', '')
|
300
|
-
if arg.nil?
|
301
|
-
compiler_opts[opt.to_sym] = true
|
302
|
-
else
|
303
|
-
# Check for some specific options
|
304
|
-
case opt
|
305
|
-
when 'pinmap_workbook'
|
306
|
-
current_job_options[opt.to_sym] = Pathname.new(arg)
|
307
|
-
when 'output'
|
308
|
-
dot_pat = Pathname.new(arg)
|
309
|
-
current_job_options[:output_directory] = dot_pat.dirname
|
310
|
-
else
|
311
|
-
current_job_options[opt.to_sym] = arg
|
312
|
-
end
|
313
|
-
end
|
314
|
-
end
|
315
|
-
@jobs << Job.new(pattern, current_job_options, compiler_opts)
|
316
|
-
inspect_jobs
|
317
|
-
end
|
318
|
-
end
|
319
|
-
run
|
320
|
-
# Clear @jobs
|
321
|
-
clear
|
322
|
-
end
|
323
|
-
end
|
324
|
-
|
325
|
-
# Clear the job queue
|
326
|
-
def clear
|
327
|
-
@jobs = []
|
328
|
-
@files = []
|
329
|
-
end
|
330
|
-
|
331
|
-
# Output all of the jobs into a pattern list so it can be compiled later
|
332
|
-
# Must be executed after the 'find_jobs' method and before the 'run' method
|
333
|
-
# or @jobs will be empty
|
334
|
-
def to_list(options = {})
|
335
|
-
options = {
|
336
|
-
name: @id,
|
337
|
-
output_directory: Dir.pwd,
|
338
|
-
expand: true,
|
339
|
-
force: false
|
340
|
-
}.update_common(options)
|
341
|
-
list = "#{options[:output_directory]}/#{options[:name]}.list"
|
342
|
-
list = convert_to_pathname(list)
|
343
|
-
if empty?
|
344
|
-
empty_msg
|
345
|
-
return
|
346
|
-
end
|
347
|
-
if list.file?
|
348
|
-
if options[:force] == true
|
349
|
-
puts "Pattern list file #{list} already exists, deleting it..."
|
350
|
-
list.delete
|
351
|
-
else
|
352
|
-
fail "Pattern list file #{list} already exists, exiting..."
|
353
|
-
end
|
354
|
-
end
|
355
|
-
File.open(list, 'w') do |patlist|
|
356
|
-
@jobs.each do |job|
|
357
|
-
if options[:expand] == true
|
358
|
-
pinmap = job.pinmap_workbook
|
359
|
-
dot_pat_name = "#{job.output_directory}/#{job.pattern.basename.to_s.split('.').first}.PAT"
|
360
|
-
dot_atp_name = job.pattern
|
361
|
-
else
|
362
|
-
pinmap = job.pinmap_workbook.basename
|
363
|
-
dot_pat_name = "#{job.pattern.basename.to_s.split('.').first}.PAT"
|
364
|
-
dot_atp_name = job.pattern.basename
|
365
|
-
end
|
366
|
-
patlist.print("#{dot_atp_name} -pinmap_workbook:#{pinmap} -output:#{dot_pat_name}")
|
367
|
-
job.compiler_options.each_key { |k| patlist.print(" -#{k}") }
|
368
|
-
job.compiler_options_with_args.each_pair { |k, v| patlist.print(" -#{k}:#{v}") }
|
369
|
-
patlist.puts('')
|
370
|
-
end
|
371
|
-
end
|
372
|
-
end
|
373
|
-
|
374
|
-
# For future checks on incorrect or incompatible arguments to compiler options
|
375
|
-
def options_ok?
|
376
|
-
end
|
377
|
-
|
378
|
-
def ready?
|
379
|
-
ready = true
|
380
|
-
paths_contain_data = true
|
381
|
-
# check for nil
|
382
|
-
ready = paths_contain_data && !@job_options[:output_directory].nil? &&
|
383
|
-
!@user_options[:reference_directory].nil? &&
|
384
|
-
!@path.nil? &&
|
385
|
-
!@job_options[:pinmap_workbook].nil?
|
386
|
-
ready && @job_options[:output_directory].directory? &&
|
387
|
-
@user_options[:reference_directory].directory? &&
|
388
|
-
@path.exist? &&
|
389
|
-
@job_options[:pinmap_workbook].file? &&
|
390
|
-
[true, false].include?(@job_options[:clean]) &&
|
391
|
-
[:local, :lsf].include?(@job_options[:location]) &&
|
392
|
-
File.exist?(@job_options[:compiler])
|
393
|
-
end
|
394
|
-
|
395
|
-
def bad_options
|
396
|
-
bad = []
|
397
|
-
options = {
|
398
|
-
output_directory: @job_options[:output_directory],
|
399
|
-
reference_directory: @user_options[:reference_directory],
|
400
|
-
path: @path,
|
401
|
-
pinmap_workbook: @job_options[:pinmap_workbook],
|
402
|
-
clean: @job_options[:clean],
|
403
|
-
location: @job_options[:location],
|
404
|
-
compiler: @job_options[:compiler]
|
405
|
-
}
|
406
|
-
options.each do |k, v|
|
407
|
-
bad << k if v.nil?
|
408
|
-
if v.is_a? String # compiler
|
409
|
-
v = Pathname.new(v)
|
410
|
-
bad << k unless v.file?
|
411
|
-
elsif v.is_a? Symbol # clean
|
412
|
-
bad << k unless [:local, :lsf].include? v
|
413
|
-
elsif v.is_a? Pathname
|
414
|
-
if k.match(/directory/)
|
415
|
-
bad << k unless v.directory?
|
416
|
-
elsif k == :path
|
417
|
-
bad << k unless v.exist?
|
418
|
-
else # pinmap
|
419
|
-
bad << k unless v.file?
|
420
|
-
end
|
421
|
-
end
|
422
|
-
end
|
423
|
-
bad
|
424
|
-
end
|
425
|
-
alias_method :bad_opts, :bad_options
|
426
|
-
|
427
|
-
# Output the compiler options to the console
|
428
|
-
def inspect_options(verbose = nil)
|
429
|
-
desc = []
|
430
|
-
# Find the longest option argument string
|
431
|
-
my_job_options = @job_options
|
432
|
-
my_job_options.delete(:compiler)
|
433
|
-
all_arguments = @user_options.values + my_job_options.values + @compiler_options.values + @compiler_options_with_args.values
|
434
|
-
min_argument_padding = 'Argument'.length + 2
|
435
|
-
argument_padding = all_arguments.max_by { |e| e.to_s.length }.to_s.length + 3
|
436
|
-
argument_padding = min_argument_padding if argument_padding < min_argument_padding
|
437
|
-
puts "\n"
|
438
|
-
header = '| Option ' + '| Argument'.ljust(argument_padding) + '| Required |'
|
439
|
-
desc << header
|
440
|
-
desc << '-' * header.length
|
441
|
-
[@user_options, my_job_options, @compiler_options, @compiler_options_with_args].each do |opt|
|
442
|
-
opt.each_pair do |k, v|
|
443
|
-
if k.match(/pinmap_workbook|path|id|directory|clean|location|recursive/i)
|
444
|
-
req = 'true '
|
445
|
-
else
|
446
|
-
next if v.nil? || v == false
|
447
|
-
req = 'false'
|
448
|
-
end
|
449
|
-
desc << "| #{k}".ljust(22) + "| #{v}".ljust(argument_padding) + "| #{req} |"
|
450
|
-
end
|
451
|
-
end
|
452
|
-
puts desc
|
453
|
-
end
|
454
|
-
|
455
|
-
# Output the compiler jobs in the queue to the console
|
456
|
-
def inspect_jobs(index = nil)
|
457
|
-
return empty_msg if empty?
|
458
|
-
desc = []
|
459
|
-
puts "\n"
|
460
|
-
@jobs.each_with_index do |j, i|
|
461
|
-
unless index.nil?
|
462
|
-
next unless i == index
|
463
|
-
end
|
464
|
-
desc << '| Job: ' + "#{i + 1} ".rjust(8) + '|' + 'Pattern:'.rjust(18) + " #{j.pattern.basename}".ljust(100) + '|'
|
465
|
-
desc << '| |' + 'Compiler ID:'.rjust(18) + " #{j.id}".ljust(100) + '|'
|
466
|
-
desc << '| |' + 'Pinmap:'.rjust(18) + " #{j.pinmap_workbook}".ljust(100) + '|'
|
467
|
-
desc << '| |' + '.atp directory:'.rjust(18) + " #{j.pattern.dirname}".ljust(100) + '|'
|
468
|
-
desc << '| |' + '.pat directory:'.rjust(18) + " #{j.output_directory}".ljust(100) + '|'
|
469
|
-
desc << '| |' + 'LSF:'.rjust(18) + " #{j.location == :lsf ? true : false}".ljust(100) + '|'
|
470
|
-
desc << '| |' + 'Delete log files:'.rjust(18) + " #{j.clean}".ljust(100) + '|'
|
471
|
-
desc << '| |' + 'Verbose:'.rjust(18) + " #{j.verbose}".ljust(100) + '|'
|
472
|
-
fragment = '| |' + 'Compiler args:'.rjust(18)
|
473
|
-
overflow_fragment = '| |' + ' '.rjust(18)
|
474
|
-
compiler_args = []
|
475
|
-
compiler_fragment = ''
|
476
|
-
j.compiler_options.each_key do |k|
|
477
|
-
if compiler_fragment.size + " -#{k}".size >= 100
|
478
|
-
compiler_args << compiler_fragment
|
479
|
-
compiler_fragment = nil
|
480
|
-
end
|
481
|
-
compiler_fragment += " -#{k}"
|
482
|
-
end
|
483
|
-
compiler_args << compiler_fragment unless compiler_fragment.nil?
|
484
|
-
compiler_fragment = ''
|
485
|
-
j.compiler_options_with_args.each_pair do |k, v|
|
486
|
-
if compiler_fragment.size + " -#{k}:#{v}".size >= 100
|
487
|
-
compiler_args << compiler_fragment
|
488
|
-
compiler_fragment = nil
|
489
|
-
end
|
490
|
-
compiler_fragment += " -#{k}:#{v}"
|
491
|
-
end
|
492
|
-
compiler_args << compiler_fragment unless compiler_fragment.nil?
|
493
|
-
if compiler_args.join.length <= 100
|
494
|
-
desc << fragment + "#{compiler_args.join}".ljust(100) + '|'
|
495
|
-
else
|
496
|
-
# Need to cycle through compiler args and build a fragment <= 100 characters
|
497
|
-
# and print it. Keep going until the remaining args is <= 100 and print again
|
498
|
-
char_cnt = 0
|
499
|
-
line_cnt = 0
|
500
|
-
args = []
|
501
|
-
compiler_args = compiler_args.join.strip.split(/\s+/)
|
502
|
-
until compiler_args.empty?
|
503
|
-
args = compiler_args.select { |e| (char_cnt += e.length + 1) < 100 }
|
504
|
-
# remove the args that fit on the first line
|
505
|
-
compiler_args -= args
|
506
|
-
if line_cnt == 0
|
507
|
-
desc << fragment + " #{args.join(' ')}".ljust(100) + '|'
|
508
|
-
else
|
509
|
-
desc << overflow_fragment + " #{args.join(' ')}".ljust(100) + '|'
|
510
|
-
end
|
511
|
-
args = []
|
512
|
-
line_cnt += 1
|
513
|
-
char_cnt = 0
|
514
|
-
end
|
515
|
-
end
|
516
|
-
desc << '-' * desc.first.size
|
517
|
-
end
|
518
|
-
puts desc.flatten.join("\n")
|
519
|
-
end
|
520
|
-
|
521
|
-
# Returns the number of jobs in the compiler
|
522
|
-
def count
|
523
|
-
@jobs.size
|
524
|
-
end
|
525
|
-
|
526
|
-
# Checks if the compiler queue is empty
|
527
|
-
def empty?
|
528
|
-
@jobs.empty?
|
529
|
-
end
|
530
|
-
|
531
|
-
private
|
532
|
-
|
533
|
-
def running_on_windows?
|
534
|
-
RUBY_PLATFORM == 'i386-mingw32'
|
535
|
-
end
|
536
|
-
|
537
|
-
def empty_msg
|
538
|
-
puts "No compiler jobs created, check the compiler options\n" if self.empty?
|
539
|
-
end
|
540
|
-
|
541
|
-
def convert_to_pathname(opt)
|
542
|
-
if opt.is_a? String
|
543
|
-
opt = Pathname.new(opt)
|
544
|
-
opt = opt.expand_path
|
545
|
-
elsif opt.is_a? Pathname
|
546
|
-
opt = opt.expand_path
|
547
|
-
else
|
548
|
-
fail "Option #{opt} is not a String, cannot convert to Pathname"
|
549
|
-
end
|
550
|
-
opt
|
551
|
-
end
|
552
|
-
|
553
|
-
def set_reference_directory
|
554
|
-
if @user_options[:reference_directory].nil?
|
555
|
-
# Nothing passed for reference directory so set it to Origen.app.config.pattern_output_directory if valid
|
556
|
-
if File.directory? Origen.app.config.pattern_output_directory
|
557
|
-
@user_options[:reference_directory] = Pathname.new(Origen.app.config.pattern_output_directory)
|
558
|
-
elsif @path
|
559
|
-
if @path.directory?
|
560
|
-
@user_options[:reference_directory] = @path
|
561
|
-
else
|
562
|
-
@user_options[:reference_directory] = @path.dirname
|
563
|
-
end
|
564
|
-
end
|
565
|
-
elsif File.directory?(@user_options[:reference_directory])
|
566
|
-
@user_options[:reference_directory] = Pathname.new(@user_options[:reference_directory])
|
567
|
-
else
|
568
|
-
debug 'Reference directory not set, creating it...'
|
569
|
-
@user_options[:reference_directory] = Pathname.new(@user_options[:reference_directory])
|
570
|
-
FileUtils.mkdir_p(@user_options[:reference_directory])
|
571
|
-
end
|
572
|
-
@user_options[:reference_directory] = @user_options[:reference_directory].expand_path
|
573
|
-
# reference_directory must be a subset of @path. if it is not then set to @path if @path exists
|
574
|
-
unless @path.nil?
|
575
|
-
if @path.directory?
|
576
|
-
@user_options[:reference_directory] = @path unless @path.to_s.include? @user_options[:reference_directory].to_s
|
577
|
-
elsif @path.file?
|
578
|
-
@user_options[:reference_directory] = @path.dirname
|
579
|
-
else
|
580
|
-
debug "Path is set to #{@path} which is not a valid directory or file!"
|
581
|
-
end
|
582
|
-
end
|
583
|
-
end
|
584
|
-
|
585
|
-
# Check if the current tester is an Ultraflex
|
586
|
-
def is_ultraflex?
|
587
|
-
platform == :ultraflex ? true : false
|
588
|
-
end
|
589
|
-
|
590
|
-
def platform
|
591
|
-
if $tester.nil?
|
592
|
-
fail 'No tester instantiated, $tester is set to nil'
|
593
|
-
else
|
594
|
-
$tester.class.to_s.downcase.split('::').last.to_sym
|
595
|
-
end
|
596
|
-
end
|
597
|
-
end
|
598
|
-
end
|
599
|
-
end
|