origen_testers 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|