origen_testers 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (199) hide show
  1. checksums.yaml +7 -0
  2. data/config/application.rb +140 -0
  3. data/config/commands.rb +73 -0
  4. data/config/development.rb +12 -0
  5. data/config/environment.rb +1 -0
  6. data/config/shared_commands.rb +47 -0
  7. data/config/users.rb +18 -0
  8. data/config/version.rb +8 -0
  9. data/lib/commands/build.rb +69 -0
  10. data/lib/origen_testers.rb +23 -0
  11. data/lib/origen_testers/api.rb +258 -0
  12. data/lib/origen_testers/basic_test_setups.rb +105 -0
  13. data/lib/origen_testers/callback_handlers.rb +58 -0
  14. data/lib/origen_testers/generator.rb +279 -0
  15. data/lib/origen_testers/generator/flow_control_api.rb +611 -0
  16. data/lib/origen_testers/generator/identity_map.rb +23 -0
  17. data/lib/origen_testers/generator/placeholder.rb +11 -0
  18. data/lib/origen_testers/generator/test_numberer.rb +23 -0
  19. data/lib/origen_testers/igxl_based_tester.rb +12 -0
  20. data/lib/origen_testers/igxl_based_tester/base.rb +641 -0
  21. data/lib/origen_testers/igxl_based_tester/base/flow.rb +171 -0
  22. data/lib/origen_testers/igxl_based_tester/base/flow_line.rb +322 -0
  23. data/lib/origen_testers/igxl_based_tester/base/generator.rb +217 -0
  24. data/lib/origen_testers/igxl_based_tester/base/patgroup.rb +109 -0
  25. data/lib/origen_testers/igxl_based_tester/base/patgroups.rb +38 -0
  26. data/lib/origen_testers/igxl_based_tester/base/patset.rb +68 -0
  27. data/lib/origen_testers/igxl_based_tester/base/patset_pattern.rb +56 -0
  28. data/lib/origen_testers/igxl_based_tester/base/patsets.rb +38 -0
  29. data/lib/origen_testers/igxl_based_tester/base/patsubr.rb +68 -0
  30. data/lib/origen_testers/igxl_based_tester/base/patsubr_pattern.rb +56 -0
  31. data/lib/origen_testers/igxl_based_tester/base/patsubrs.rb +38 -0
  32. data/lib/origen_testers/igxl_based_tester/base/test_instance.rb +326 -0
  33. data/lib/origen_testers/igxl_based_tester/base/test_instance_group.rb +58 -0
  34. data/lib/origen_testers/igxl_based_tester/base/test_instances.rb +179 -0
  35. data/lib/origen_testers/igxl_based_tester/files.rb +43 -0
  36. data/lib/origen_testers/igxl_based_tester/j750.rb +248 -0
  37. data/lib/origen_testers/igxl_based_tester/j750/flow.rb +10 -0
  38. data/lib/origen_testers/igxl_based_tester/j750/flow_line.rb +19 -0
  39. data/lib/origen_testers/igxl_based_tester/j750/generator.rb +19 -0
  40. data/lib/origen_testers/igxl_based_tester/j750/patgroup.rb +9 -0
  41. data/lib/origen_testers/igxl_based_tester/j750/patgroups.rb +10 -0
  42. data/lib/origen_testers/igxl_based_tester/j750/patset.rb +9 -0
  43. data/lib/origen_testers/igxl_based_tester/j750/patset_pattern.rb +18 -0
  44. data/lib/origen_testers/igxl_based_tester/j750/patsets.rb +10 -0
  45. data/lib/origen_testers/igxl_based_tester/j750/patsubr.rb +9 -0
  46. data/lib/origen_testers/igxl_based_tester/j750/patsubr_pattern.rb +18 -0
  47. data/lib/origen_testers/igxl_based_tester/j750/patsubrs.rb +10 -0
  48. data/lib/origen_testers/igxl_based_tester/j750/templates/flow.txt.erb +9 -0
  49. data/lib/origen_testers/igxl_based_tester/j750/templates/instances.txt.erb +16 -0
  50. data/lib/origen_testers/igxl_based_tester/j750/templates/patgroups.txt.erb +8 -0
  51. data/lib/origen_testers/igxl_based_tester/j750/templates/patsets.txt.erb +10 -0
  52. data/lib/origen_testers/igxl_based_tester/j750/templates/patsubrs.txt.erb +10 -0
  53. data/lib/origen_testers/igxl_based_tester/j750/test_instance.rb +547 -0
  54. data/lib/origen_testers/igxl_based_tester/j750/test_instance_group.rb +9 -0
  55. data/lib/origen_testers/igxl_based_tester/j750/test_instances.rb +10 -0
  56. data/lib/origen_testers/igxl_based_tester/j750_hpt.rb +34 -0
  57. data/lib/origen_testers/igxl_based_tester/j750_hpt/flow.rb +9 -0
  58. data/lib/origen_testers/igxl_based_tester/j750_hpt/flow_line.rb +9 -0
  59. data/lib/origen_testers/igxl_based_tester/j750_hpt/generator.rb +19 -0
  60. data/lib/origen_testers/igxl_based_tester/j750_hpt/patgroup.rb +9 -0
  61. data/lib/origen_testers/igxl_based_tester/j750_hpt/patgroups.rb +9 -0
  62. data/lib/origen_testers/igxl_based_tester/j750_hpt/patset.rb +9 -0
  63. data/lib/origen_testers/igxl_based_tester/j750_hpt/patset_pattern.rb +9 -0
  64. data/lib/origen_testers/igxl_based_tester/j750_hpt/patsets.rb +9 -0
  65. data/lib/origen_testers/igxl_based_tester/j750_hpt/patsubr.rb +9 -0
  66. data/lib/origen_testers/igxl_based_tester/j750_hpt/patsubr_pattern.rb +9 -0
  67. data/lib/origen_testers/igxl_based_tester/j750_hpt/patsubrs.rb +9 -0
  68. data/lib/origen_testers/igxl_based_tester/j750_hpt/test_instance.rb +515 -0
  69. data/lib/origen_testers/igxl_based_tester/j750_hpt/test_instance_group.rb +9 -0
  70. data/lib/origen_testers/igxl_based_tester/j750_hpt/test_instances.rb +9 -0
  71. data/lib/origen_testers/igxl_based_tester/parser.rb +102 -0
  72. data/lib/origen_testers/igxl_based_tester/parser/ac_spec.rb +9 -0
  73. data/lib/origen_testers/igxl_based_tester/parser/ac_specs.rb +0 -0
  74. data/lib/origen_testers/igxl_based_tester/parser/dc_spec.rb +33 -0
  75. data/lib/origen_testers/igxl_based_tester/parser/dc_specs.rb +48 -0
  76. data/lib/origen_testers/igxl_based_tester/parser/descriptions.rb +339 -0
  77. data/lib/origen_testers/igxl_based_tester/parser/flow.rb +109 -0
  78. data/lib/origen_testers/igxl_based_tester/parser/flow_line.rb +203 -0
  79. data/lib/origen_testers/igxl_based_tester/parser/flows.rb +21 -0
  80. data/lib/origen_testers/igxl_based_tester/parser/pattern_set.rb +92 -0
  81. data/lib/origen_testers/igxl_based_tester/parser/pattern_sets.rb +31 -0
  82. data/lib/origen_testers/igxl_based_tester/parser/test_instance.rb +341 -0
  83. data/lib/origen_testers/igxl_based_tester/parser/test_instances.rb +24 -0
  84. data/lib/origen_testers/igxl_based_tester/parser/timeset.rb +13 -0
  85. data/lib/origen_testers/igxl_based_tester/parser/timesets.rb +0 -0
  86. data/lib/origen_testers/igxl_based_tester/ultraflex.rb +477 -0
  87. data/lib/origen_testers/igxl_based_tester/ultraflex/flow.rb +10 -0
  88. data/lib/origen_testers/igxl_based_tester/ultraflex/flow_line.rb +19 -0
  89. data/lib/origen_testers/igxl_based_tester/ultraflex/generator.rb +19 -0
  90. data/lib/origen_testers/igxl_based_tester/ultraflex/patgroup.rb +9 -0
  91. data/lib/origen_testers/igxl_based_tester/ultraflex/patgroups.rb +10 -0
  92. data/lib/origen_testers/igxl_based_tester/ultraflex/patset.rb +9 -0
  93. data/lib/origen_testers/igxl_based_tester/ultraflex/patset_pattern.rb +18 -0
  94. data/lib/origen_testers/igxl_based_tester/ultraflex/patsets.rb +10 -0
  95. data/lib/origen_testers/igxl_based_tester/ultraflex/patsubr.rb +9 -0
  96. data/lib/origen_testers/igxl_based_tester/ultraflex/patsubr_pattern.rb +18 -0
  97. data/lib/origen_testers/igxl_based_tester/ultraflex/patsubrs.rb +10 -0
  98. data/lib/origen_testers/igxl_based_tester/ultraflex/templates/flow.txt.erb +9 -0
  99. data/lib/origen_testers/igxl_based_tester/ultraflex/templates/instances.txt.erb +16 -0
  100. data/lib/origen_testers/igxl_based_tester/ultraflex/templates/patgroups.txt.erb +9 -0
  101. data/lib/origen_testers/igxl_based_tester/ultraflex/templates/patsets.txt.erb +10 -0
  102. data/lib/origen_testers/igxl_based_tester/ultraflex/templates/patsubrs.txt.erb +10 -0
  103. data/lib/origen_testers/igxl_based_tester/ultraflex/test_instance.rb +270 -0
  104. data/lib/origen_testers/igxl_based_tester/ultraflex/test_instance_group.rb +9 -0
  105. data/lib/origen_testers/igxl_based_tester/ultraflex/test_instances.rb +10 -0
  106. data/lib/origen_testers/interface.rb +183 -0
  107. data/lib/origen_testers/parser.rb +22 -0
  108. data/lib/origen_testers/parser/description_lookup.rb +62 -0
  109. data/lib/origen_testers/parser/searchable_array.rb +30 -0
  110. data/lib/origen_testers/parser/searchable_hash.rb +30 -0
  111. data/lib/origen_testers/pattern_compilers.rb +116 -0
  112. data/lib/origen_testers/pattern_compilers/assembler.rb +88 -0
  113. data/lib/origen_testers/pattern_compilers/job.rb +96 -0
  114. data/lib/origen_testers/pattern_compilers/ultraflex_pattern_compiler.rb +599 -0
  115. data/lib/origen_testers/program_generators.rb +55 -0
  116. data/lib/origen_testers/smartest_based_tester.rb +8 -0
  117. data/lib/origen_testers/smartest_based_tester/base.rb +411 -0
  118. data/lib/origen_testers/smartest_based_tester/base/flow.rb +188 -0
  119. data/lib/origen_testers/smartest_based_tester/base/flow_node.rb +476 -0
  120. data/lib/origen_testers/smartest_based_tester/base/generator.rb +123 -0
  121. data/lib/origen_testers/smartest_based_tester/base/pattern_compiler.rb +23 -0
  122. data/lib/origen_testers/smartest_based_tester/base/pattern_master.rb +47 -0
  123. data/lib/origen_testers/smartest_based_tester/base/test_method.rb +143 -0
  124. data/lib/origen_testers/smartest_based_tester/base/test_methods.rb +73 -0
  125. data/lib/origen_testers/smartest_based_tester/base/test_methods/ac_tml.rb +33 -0
  126. data/lib/origen_testers/smartest_based_tester/base/test_methods/base_tml.rb +38 -0
  127. data/lib/origen_testers/smartest_based_tester/base/test_methods/custom_tml.rb +19 -0
  128. data/lib/origen_testers/smartest_based_tester/base/test_methods/dc_tml.rb +147 -0
  129. data/lib/origen_testers/smartest_based_tester/base/test_methods/limits.rb +43 -0
  130. data/lib/origen_testers/smartest_based_tester/base/test_suite.rb +166 -0
  131. data/lib/origen_testers/smartest_based_tester/base/test_suites.rb +58 -0
  132. data/lib/origen_testers/smartest_based_tester/v93k.rb +8 -0
  133. data/lib/origen_testers/smartest_based_tester/v93k/builder.rb +89 -0
  134. data/lib/origen_testers/smartest_based_tester/v93k/builder/flow.rb +169 -0
  135. data/lib/origen_testers/smartest_based_tester/v93k/builder/pattern_master.rb +54 -0
  136. data/lib/origen_testers/smartest_based_tester/v93k/flow.rb +10 -0
  137. data/lib/origen_testers/smartest_based_tester/v93k/flow_node.rb +9 -0
  138. data/lib/origen_testers/smartest_based_tester/v93k/generator.rb +19 -0
  139. data/lib/origen_testers/smartest_based_tester/v93k/pattern_compiler.rb +10 -0
  140. data/lib/origen_testers/smartest_based_tester/v93k/pattern_master.rb +10 -0
  141. data/lib/origen_testers/smartest_based_tester/v93k/templates/template.aiv.erb +17 -0
  142. data/lib/origen_testers/smartest_based_tester/v93k/templates/template.flow.erb +201 -0
  143. data/lib/origen_testers/smartest_based_tester/v93k/templates/template.pmfl.erb +13 -0
  144. data/lib/origen_testers/smartest_based_tester/v93k/test_method.rb +9 -0
  145. data/lib/origen_testers/smartest_based_tester/v93k/test_methods.rb +9 -0
  146. data/lib/origen_testers/smartest_based_tester/v93k/test_suite.rb +9 -0
  147. data/lib/origen_testers/smartest_based_tester/v93k/test_suites.rb +9 -0
  148. data/lib/origen_testers/test/basic_interface.rb +17 -0
  149. data/lib/origen_testers/test/block.rb +21 -0
  150. data/lib/origen_testers/test/dut.rb +184 -0
  151. data/lib/origen_testers/test/dut2.rb +76 -0
  152. data/lib/origen_testers/test/j750_base_interface.rb +119 -0
  153. data/lib/origen_testers/test/j750_hpt_interface.rb +8 -0
  154. data/lib/origen_testers/test/j750_interface.rb +8 -0
  155. data/lib/origen_testers/test/nvm.rb +94 -0
  156. data/lib/origen_testers/test/ultraflex_interface.rb +110 -0
  157. data/lib/origen_testers/test/v93k_interface.rb +115 -0
  158. data/lib/origen_testers/timing.rb +362 -0
  159. data/lib/origen_testers/vector.rb +203 -0
  160. data/lib/origen_testers/vector_based_tester.rb +42 -0
  161. data/lib/origen_testers/vector_generator.rb +623 -0
  162. data/lib/origen_testers/vector_pipeline.rb +288 -0
  163. data/pattern/dc_instr.rb +7 -0
  164. data/pattern/delay.rb +7 -0
  165. data/pattern/mem_test.rb +8 -0
  166. data/pattern/multi_vector.rb +117 -0
  167. data/pattern/multi_vector_plus1.rb +125 -0
  168. data/pattern/nvm/j750/add_late_pins.rb +3 -0
  169. data/pattern/nvm/j750/iterator_postfix_test_x_bx.rb +8 -0
  170. data/pattern/nvm/j750/iterator_test_x_bx.rb +8 -0
  171. data/pattern/nvm/j750/j750_halt.rb +159 -0
  172. data/pattern/nvm/j750/j750_workout.rb +202 -0
  173. data/pattern/nvm/j750/timing.rb +73 -0
  174. data/pattern/nvm/v93k/v93k_workout.rb +136 -0
  175. data/pattern/read_write_reg.rb +58 -0
  176. data/pattern/reset.rb +4 -0
  177. data/pattern/subroutines.rb +38 -0
  178. data/program/_additional_erase.rb +7 -0
  179. data/program/_efa_resources.rb +7 -0
  180. data/program/_erase.rb +25 -0
  181. data/program/_erase_vfy.rb +5 -0
  182. data/program/_iv_resources.rb +10 -0
  183. data/program/basic_interface.rb +5 -0
  184. data/program/components/_prb2_main.rb +6 -0
  185. data/program/flow_control.rb +164 -0
  186. data/program/prb1.rb +226 -0
  187. data/program/prb1_resources.rb +28 -0
  188. data/program/prb2.rb +40 -0
  189. data/program/test.rb +20 -0
  190. data/templates/example.txt.erb +53 -0
  191. data/templates/j750/_vt_flow.txt.erb +8 -0
  192. data/templates/j750/_vt_instances.txt.erb +4 -0
  193. data/templates/j750/program_sheet.txt.erb +9 -0
  194. data/templates/manifest/v93k.yaml.erb +22 -0
  195. data/templates/web/index.md.erb +51 -0
  196. data/templates/web/layouts/_basic.html.erb +15 -0
  197. data/templates/web/partials/_navbar.html.erb +22 -0
  198. data/templates/web/release_notes.md.erb +5 -0
  199. metadata +332 -0
@@ -0,0 +1,88 @@
1
+ module OrigenTesters
2
+ module PatternCompilers
3
+ class UltraFlexPatternCompiler
4
+ private
5
+
6
+ # Check the file extension of a file, return status can be 'atp', 'list', or nil
7
+ def check_file_ext(file)
8
+ status = nil
9
+ ext = file.extname
10
+ name = file.basename
11
+ if ext == '.atp'
12
+ status = 'atp'
13
+ elsif ext == '.gz'
14
+ # Ensure we have a .atp.gz
15
+ sub_ext = name.to_s.split('.')[-2]
16
+ if sub_ext == 'atp'
17
+ status = 'atp'
18
+ end
19
+ elsif ext == '.list'
20
+ status = 'list'
21
+ end
22
+ status
23
+ end
24
+
25
+ # Parse a pattern list file recursively until all .atp or .atp.gz files are found
26
+ def parse_list(path, files)
27
+ list_name = path.basename
28
+ dir = path.dirname
29
+ line_number = 0
30
+ path.open('r') do |f|
31
+ while (line = f.gets)
32
+ line_number += 1
33
+ # Strip the leading and trailing whitespace for sloppy typers
34
+ line.strip!
35
+ # Skip a blank line
36
+ next if line.match(/^\s+$/)
37
+ # Check if the pattern or list exists
38
+ line_path = Pathname.new("#{dir}/#{line}")
39
+ unless line_path.file?
40
+ # puts "Skipping #{line_path.to_s} at line ##{line_number} in file #{path.to_s} because it is not a file"
41
+ next
42
+ end
43
+ # Process the file
44
+ process_file(line_path, files)
45
+ end
46
+ end
47
+ end
48
+
49
+ # Processes a file looking for a valid .atp or .list
50
+ def process_file(file, files)
51
+ # puts "processing file #{file.to_s}"
52
+ case check_file_ext(file)
53
+ when 'atp'
54
+ files << file unless files.include?(file)
55
+ when 'list'
56
+ parse_list(file, files)
57
+ end
58
+ end
59
+
60
+ # Processes a diretcory looking for files in '.' or recursively
61
+ def process_directory(dir, files, rec)
62
+ dir.children(true).each do |f|
63
+ # ignore sub-directories
64
+ if f.directory?
65
+ if rec == false
66
+ next
67
+ else
68
+ process_directory(f.expand_path, files, rec)
69
+ end
70
+ end
71
+ process_file(f.expand_path, files)
72
+ end
73
+ end
74
+
75
+ # Deletes the pattern compiler log files
76
+ def clean_output
77
+ @jobs.each do |job|
78
+ logfile = Pathname.new("#{job.pattern.dirname}/#{job.pattern.basename.to_s.chomp(job.pattern.extname)}.log")
79
+ logfile.cleanpath
80
+ if logfile.file?
81
+ # puts "Deleting log file #{logfile}"
82
+ logfile.delete
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,96 @@
1
+ module OrigenTesters
2
+ module PatternCompilers
3
+ class Job
4
+ # Pattern to be compiled, is Pathname class. Will use full path
5
+ attr_accessor :pattern
6
+
7
+ # Type of pattern as designated by the LinuxPatternCompiler
8
+ attr_accessor :id
9
+
10
+ # Where the job is to be executed, either locally ('local') or on Linux Server Farm ('lsf')
11
+ attr_accessor :location
12
+
13
+ # Controls whether the compiler log files are kept: true/false
14
+ attr_accessor :clean
15
+
16
+ # Controls whether the compiler STDOUT is displayed
17
+ attr_accessor :verbose
18
+
19
+ # Output directory for the .PAT file
20
+ attr_accessor :output_directory
21
+
22
+ # Pinmap file
23
+ attr_accessor :pinmap_workbook
24
+
25
+ # Compiler options where only the opt has to be passed as '-opt'
26
+ attr_accessor :compiler_options
27
+
28
+ # Compiler options where an opt and an arg have to be passed '-opt:arg'
29
+ attr_accessor :compiler_options_with_args
30
+
31
+ # linux compiler full path
32
+ attr_reader :compiler
33
+
34
+ def initialize(pattern, options_with_args, options)
35
+ @pattern = pattern
36
+ @compiler = options_with_args.delete(:compiler)
37
+ @id = options_with_args.delete(:id)
38
+ @location = options_with_args.delete(:location)
39
+ @clean = options_with_args.delete(:clean)
40
+ @verbose = options_with_args.delete(:verbose)
41
+ @output_directory = options_with_args.delete(:output_directory)
42
+ @pinmap_workbook = options_with_args.delete(:pinmap_workbook)
43
+ @compiler_options_with_args = options_with_args.delete_if { |k, v| v.nil? } # Whatever's left has to be valid compiler options
44
+ @compiler_options = options.delete_if { |k, v| v == false }
45
+ end
46
+
47
+ def name
48
+ @pattern.basename
49
+ end
50
+
51
+ def cmd
52
+ cmd = ''
53
+ cmd = "#{@compiler} -pinmap_workbook:#{@pinmap_workbook} -output:#{@output_directory}/#{@pattern.basename.to_s.split('.').first}.PAT #{@pattern} "
54
+ # add in any remaining compiler options
55
+ compiler_options.each_key { |k| cmd += "-#{k} " }
56
+ compiler_options_with_args.each_pair { |k, v| cmd += "-#{k}:#{v} " }
57
+ if @verbose
58
+ cmd += ';'
59
+ else
60
+ cmd += '2>&1 > /dev/null;'
61
+ end
62
+ # If the job is to be run on the LSF add in the clean .log and mv the files if necessary
63
+ if @location == 'lsf'
64
+ cmd += clean_lsf if @clean == true
65
+ end
66
+ cmd
67
+ end
68
+
69
+ def ready?
70
+ ready = true
71
+ ready && @output_directory.directory? &&
72
+ @pattern.file? && @pinmap_workbook.file? &&
73
+ [true, false].include?(@clean) &&
74
+ [:local, :lsf].include?(@location)
75
+ end
76
+
77
+ private
78
+
79
+ def orig_dir
80
+ @pattern.dirname
81
+ end
82
+
83
+ # Generates the LSF commands to delete the pattern compiler log files
84
+ def clean_lsf
85
+ cmd = ''
86
+ logfile = Pathname.new("#{@pattern.dirname}/#{@pattern.basename.to_s.split('.').first}.log")
87
+ logfile.cleanpath
88
+ logfile.cleanpath
89
+ if @clean == true
90
+ cmd += "rm #{logfile}; "
91
+ end
92
+ cmd
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,599 @@
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