origen_testers 0.13.1 → 0.13.2
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/application.rb +151 -151
- data/config/boot.rb +13 -13
- data/config/commands.rb +85 -86
- data/config/users.rb +18 -18
- data/config/version.rb +8 -8
- data/lib/commands/build.rb +69 -69
- data/lib/commands/run.rb +48 -48
- data/lib/origen_testers.rb +47 -47
- data/lib/origen_testers/api.rb +381 -381
- data/lib/origen_testers/basic_test_setups.rb +105 -105
- data/lib/origen_testers/callback_handlers.rb +59 -59
- data/lib/origen_testers/command_based_tester.rb +45 -45
- data/lib/origen_testers/flow.rb +382 -382
- data/lib/origen_testers/generator.rb +283 -283
- data/lib/origen_testers/generator/identity_map.rb +23 -23
- data/lib/origen_testers/generator/placeholder.rb +11 -11
- data/lib/origen_testers/generator/test_numberer.rb +23 -23
- data/lib/origen_testers/igxl_based_tester.rb +12 -12
- data/lib/origen_testers/igxl_based_tester/base.rb +1100 -1099
- data/lib/origen_testers/igxl_based_tester/base/ac_specsets.rb +79 -79
- data/lib/origen_testers/igxl_based_tester/base/custom_test_instance.rb +169 -169
- data/lib/origen_testers/igxl_based_tester/base/dc_specsets.rb +98 -98
- data/lib/origen_testers/igxl_based_tester/base/edge.rb +60 -60
- data/lib/origen_testers/igxl_based_tester/base/edges.rb +24 -24
- data/lib/origen_testers/igxl_based_tester/base/edgeset.rb +39 -39
- data/lib/origen_testers/igxl_based_tester/base/edgesets.rb +130 -130
- data/lib/origen_testers/igxl_based_tester/base/flow.rb +460 -460
- data/lib/origen_testers/igxl_based_tester/base/flow_line.rb +276 -276
- data/lib/origen_testers/igxl_based_tester/base/generator.rb +607 -607
- data/lib/origen_testers/igxl_based_tester/base/global_specs.rb +83 -83
- data/lib/origen_testers/igxl_based_tester/base/job.rb +75 -75
- data/lib/origen_testers/igxl_based_tester/base/jobs.rb +44 -44
- data/lib/origen_testers/igxl_based_tester/base/level_io_se.rb +59 -59
- data/lib/origen_testers/igxl_based_tester/base/level_supply.rb +39 -39
- data/lib/origen_testers/igxl_based_tester/base/levels.rb +31 -31
- data/lib/origen_testers/igxl_based_tester/base/levelset.rb +110 -110
- data/lib/origen_testers/igxl_based_tester/base/patgroup.rb +109 -109
- data/lib/origen_testers/igxl_based_tester/base/patgroups.rb +38 -38
- data/lib/origen_testers/igxl_based_tester/base/patset.rb +68 -68
- data/lib/origen_testers/igxl_based_tester/base/patset_pattern.rb +56 -56
- data/lib/origen_testers/igxl_based_tester/base/patsets.rb +38 -38
- data/lib/origen_testers/igxl_based_tester/base/patsubr.rb +68 -68
- data/lib/origen_testers/igxl_based_tester/base/patsubr_pattern.rb +56 -56
- data/lib/origen_testers/igxl_based_tester/base/patsubrs.rb +38 -38
- data/lib/origen_testers/igxl_based_tester/base/pinmap.rb +93 -93
- data/lib/origen_testers/igxl_based_tester/base/references.rb +25 -25
- data/lib/origen_testers/igxl_based_tester/base/test_instance.rb +322 -322
- data/lib/origen_testers/igxl_based_tester/base/test_instance_group.rb +66 -66
- data/lib/origen_testers/igxl_based_tester/base/test_instances.rb +212 -212
- data/lib/origen_testers/igxl_based_tester/base/test_instances/custom_til.rb +37 -37
- data/lib/origen_testers/igxl_based_tester/base/timeset.rb +37 -37
- data/lib/origen_testers/igxl_based_tester/base/timesets.rb +49 -49
- data/lib/origen_testers/igxl_based_tester/base/timesets_basic.rb +49 -49
- data/lib/origen_testers/igxl_based_tester/files.rb +43 -43
- data/lib/origen_testers/igxl_based_tester/j750.rb +269 -269
- data/lib/origen_testers/igxl_based_tester/j750/custom_test_instance.rb +32 -32
- data/lib/origen_testers/igxl_based_tester/j750/flow.rb +10 -10
- data/lib/origen_testers/igxl_based_tester/j750/flow_line.rb +19 -19
- data/lib/origen_testers/igxl_based_tester/j750/generator.rb +19 -19
- data/lib/origen_testers/igxl_based_tester/j750/patgroup.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/j750/patgroups.rb +10 -10
- data/lib/origen_testers/igxl_based_tester/j750/patset.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/j750/patset_pattern.rb +18 -18
- data/lib/origen_testers/igxl_based_tester/j750/patsets.rb +10 -10
- data/lib/origen_testers/igxl_based_tester/j750/patsubr.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/j750/patsubr_pattern.rb +18 -18
- data/lib/origen_testers/igxl_based_tester/j750/patsubrs.rb +10 -10
- data/lib/origen_testers/igxl_based_tester/j750/test_instance.rb +746 -746
- data/lib/origen_testers/igxl_based_tester/j750/test_instance_group.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/j750/test_instances.rb +10 -10
- data/lib/origen_testers/igxl_based_tester/j750_hpt.rb +34 -34
- data/lib/origen_testers/igxl_based_tester/j750_hpt/custom_test_instance.rb +32 -32
- data/lib/origen_testers/igxl_based_tester/j750_hpt/flow.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/j750_hpt/flow_line.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/j750_hpt/generator.rb +19 -19
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patgroup.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patgroups.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patset.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patset_pattern.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patsets.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patsubr.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patsubr_pattern.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patsubrs.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/j750_hpt/test_instance.rb +599 -599
- data/lib/origen_testers/igxl_based_tester/j750_hpt/test_instance_group.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/j750_hpt/test_instances.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/parser.rb +102 -102
- data/lib/origen_testers/igxl_based_tester/parser/ac_spec.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/parser/dc_spec.rb +33 -33
- data/lib/origen_testers/igxl_based_tester/parser/dc_specs.rb +48 -48
- data/lib/origen_testers/igxl_based_tester/parser/descriptions.rb +339 -339
- data/lib/origen_testers/igxl_based_tester/parser/flow.rb +109 -109
- data/lib/origen_testers/igxl_based_tester/parser/flow_line.rb +203 -203
- data/lib/origen_testers/igxl_based_tester/parser/flows.rb +21 -21
- data/lib/origen_testers/igxl_based_tester/parser/pattern_set.rb +92 -92
- data/lib/origen_testers/igxl_based_tester/parser/pattern_sets.rb +31 -31
- data/lib/origen_testers/igxl_based_tester/parser/test_instance.rb +420 -420
- data/lib/origen_testers/igxl_based_tester/parser/test_instances.rb +24 -24
- data/lib/origen_testers/igxl_based_tester/parser/timeset.rb +13 -13
- data/lib/origen_testers/igxl_based_tester/ultraflex.rb +798 -798
- data/lib/origen_testers/igxl_based_tester/ultraflex/ac_specsets.rb +10 -10
- data/lib/origen_testers/igxl_based_tester/ultraflex/ate_hardware.rb +949 -949
- data/lib/origen_testers/igxl_based_tester/ultraflex/custom_test_instance.rb +36 -36
- data/lib/origen_testers/igxl_based_tester/ultraflex/dc_specsets.rb +10 -10
- data/lib/origen_testers/igxl_based_tester/ultraflex/edge.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/ultraflex/edges.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/ultraflex/edgeset.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/ultraflex/edgesets.rb +10 -10
- data/lib/origen_testers/igxl_based_tester/ultraflex/flow.rb +158 -158
- data/lib/origen_testers/igxl_based_tester/ultraflex/flow_line.rb +19 -19
- data/lib/origen_testers/igxl_based_tester/ultraflex/generator.rb +19 -19
- data/lib/origen_testers/igxl_based_tester/ultraflex/global_specs.rb +10 -10
- data/lib/origen_testers/igxl_based_tester/ultraflex/job.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/ultraflex/jobs.rb +10 -10
- data/lib/origen_testers/igxl_based_tester/ultraflex/level_io_se.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/ultraflex/level_supply.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/ultraflex/levels.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/ultraflex/levelset.rb +10 -10
- data/lib/origen_testers/igxl_based_tester/ultraflex/patgroup.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/ultraflex/patgroups.rb +10 -10
- data/lib/origen_testers/igxl_based_tester/ultraflex/patset.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/ultraflex/patset_pattern.rb +18 -18
- data/lib/origen_testers/igxl_based_tester/ultraflex/patsets.rb +10 -10
- data/lib/origen_testers/igxl_based_tester/ultraflex/patsubr.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/ultraflex/patsubr_pattern.rb +18 -18
- data/lib/origen_testers/igxl_based_tester/ultraflex/patsubrs.rb +10 -10
- data/lib/origen_testers/igxl_based_tester/ultraflex/pinmap.rb +10 -10
- data/lib/origen_testers/igxl_based_tester/ultraflex/references.rb +10 -10
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/ac_specsets.txt.erb +0 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/dc_specsets.txt.erb +0 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/edgesets.txt.erb +0 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/global_specs.txt.erb +0 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/jobs.txt.erb +0 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/levelset.txt.erb +0 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/pinmap.txt.erb +0 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/references.txt.erb +0 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/timesets.txt.erb +0 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/timesets_basic.txt.erb +0 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/test_instance.rb +315 -315
- data/lib/origen_testers/igxl_based_tester/ultraflex/test_instance_group.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/ultraflex/test_instances.rb +10 -10
- data/lib/origen_testers/igxl_based_tester/ultraflex/timeset.rb +9 -9
- data/lib/origen_testers/igxl_based_tester/ultraflex/timesets.rb +10 -10
- data/lib/origen_testers/igxl_based_tester/ultraflex/timesets_basic.rb +10 -10
- data/lib/origen_testers/interface.rb +345 -324
- data/lib/origen_testers/memory_style.rb +77 -77
- data/lib/origen_testers/no_interface.rb +7 -7
- data/lib/origen_testers/origen_ext/application/runner.rb +25 -25
- data/lib/origen_testers/origen_ext/generator.rb +54 -54
- data/lib/origen_testers/origen_ext/generator/flow.rb +91 -77
- data/lib/origen_testers/origen_ext/generator/resources.rb +21 -21
- data/lib/origen_testers/origen_ext/pins/pin.rb +78 -78
- data/lib/origen_testers/origen_ext/pins/pin_collection.rb +84 -84
- data/lib/origen_testers/parser.rb +22 -22
- data/lib/origen_testers/parser/description_lookup.rb +62 -62
- data/lib/origen_testers/parser/searchable_array.rb +30 -30
- data/lib/origen_testers/parser/searchable_hash.rb +30 -30
- data/lib/origen_testers/pattern_compilers.rb +116 -116
- data/lib/origen_testers/pattern_compilers/assembler.rb +88 -88
- data/lib/origen_testers/pattern_compilers/job.rb +96 -96
- data/lib/origen_testers/pattern_compilers/ultraflex_pattern_compiler.rb +599 -599
- data/lib/origen_testers/program_generators.rb +62 -62
- data/lib/origen_testers/smartest_based_tester.rb +8 -8
- data/lib/origen_testers/smartest_based_tester/base.rb +576 -567
- data/lib/origen_testers/smartest_based_tester/base/flow.rb +296 -291
- data/lib/origen_testers/smartest_based_tester/base/generator.rb +207 -194
- data/lib/origen_testers/smartest_based_tester/base/pattern_compiler.rb +32 -32
- data/lib/origen_testers/smartest_based_tester/base/pattern_master.rb +69 -69
- data/lib/origen_testers/smartest_based_tester/base/processors.rb +16 -16
- data/lib/origen_testers/smartest_based_tester/base/processors/adjacent_if_combiner.rb +106 -106
- data/lib/origen_testers/smartest_based_tester/base/processors/continue_implementer.rb +39 -39
- data/lib/origen_testers/smartest_based_tester/base/processors/empty_branch_cleaner.rb +21 -21
- data/lib/origen_testers/smartest_based_tester/base/processors/extract_run_flag_table.rb +33 -33
- data/lib/origen_testers/smartest_based_tester/base/processors/extract_set_variables.rb +22 -22
- data/lib/origen_testers/smartest_based_tester/base/processors/flag_optimizer.rb +188 -188
- data/lib/origen_testers/smartest_based_tester/base/processors/if_ran_cleaner.rb +34 -34
- data/lib/origen_testers/smartest_based_tester/base/test_method.rb +178 -164
- data/lib/origen_testers/smartest_based_tester/base/test_methods.rb +77 -73
- data/lib/origen_testers/smartest_based_tester/base/test_methods/ac_tml.rb +33 -33
- data/lib/origen_testers/smartest_based_tester/base/test_methods/base_tml.rb +38 -38
- data/lib/origen_testers/smartest_based_tester/base/test_methods/custom_tml.rb +19 -19
- data/lib/origen_testers/smartest_based_tester/base/test_methods/dc_tml.rb +147 -147
- data/lib/origen_testers/smartest_based_tester/base/test_methods/limits.rb +65 -65
- data/lib/origen_testers/smartest_based_tester/base/test_suite.rb +208 -193
- data/lib/origen_testers/smartest_based_tester/base/test_suites.rb +58 -54
- data/lib/origen_testers/smartest_based_tester/base/variables_file.rb +38 -38
- data/lib/origen_testers/smartest_based_tester/v93k.rb +8 -8
- data/lib/origen_testers/smartest_based_tester/v93k/builder.rb +89 -89
- data/lib/origen_testers/smartest_based_tester/v93k/builder/flow.rb +181 -181
- data/lib/origen_testers/smartest_based_tester/v93k/builder/pattern_master.rb +54 -54
- data/lib/origen_testers/smartest_based_tester/v93k/flow.rb +10 -10
- data/lib/origen_testers/smartest_based_tester/v93k/generator.rb +19 -19
- data/lib/origen_testers/smartest_based_tester/v93k/pattern_compiler.rb +10 -10
- data/lib/origen_testers/smartest_based_tester/v93k/pattern_master.rb +10 -10
- data/lib/origen_testers/smartest_based_tester/v93k/templates/template.aiv.erb +17 -17
- data/lib/origen_testers/smartest_based_tester/v93k/templates/template.pmfl.erb +13 -13
- data/lib/origen_testers/smartest_based_tester/v93k/templates/template.tf.erb +236 -214
- data/lib/origen_testers/smartest_based_tester/v93k/templates/vars.tf.erb +48 -48
- data/lib/origen_testers/smartest_based_tester/v93k/test_method.rb +9 -9
- data/lib/origen_testers/smartest_based_tester/v93k/test_methods.rb +9 -9
- data/lib/origen_testers/smartest_based_tester/v93k/test_suite.rb +9 -9
- data/lib/origen_testers/smartest_based_tester/v93k/test_suites.rb +9 -9
- data/lib/origen_testers/smartest_based_tester/v93k/variables_file.rb +10 -10
- data/lib/origen_testers/test/basic_interface.rb +17 -17
- data/lib/origen_testers/test/block.rb +21 -21
- data/lib/origen_testers/test/custom_test_interface.rb +111 -111
- data/lib/origen_testers/test/dut.rb +295 -295
- data/lib/origen_testers/test/dut2.rb +76 -76
- data/lib/origen_testers/test/dut3.rb +244 -244
- data/lib/origen_testers/test/interface.rb +503 -503
- data/lib/origen_testers/test/nvm.rb +94 -94
- data/lib/origen_testers/timing.rb +368 -368
- data/lib/origen_testers/vector.rb +207 -207
- data/lib/origen_testers/vector_based_tester.rb +41 -41
- data/lib/origen_testers/vector_generator.rb +655 -655
- data/lib/origen_testers/vector_pipeline.rb +302 -302
- data/pattern/bitmap.rb +7 -7
- data/pattern/dc_instr.rb +7 -7
- data/pattern/delay.rb +7 -7
- data/pattern/freq_counter.rb +6 -6
- data/pattern/mem_test.rb +8 -8
- data/pattern/multi_vector.rb +122 -122
- data/pattern/multi_vector_plus1.rb +125 -125
- data/pattern/nvm/j750/add_late_pins.rb +3 -3
- data/pattern/nvm/j750/iterator_postfix_test_x_bx.rb +8 -8
- data/pattern/nvm/j750/iterator_test_x_bx.rb +8 -8
- data/pattern/nvm/j750/j750_halt.rb +159 -159
- data/pattern/nvm/j750/j750_workout.rb +209 -209
- data/pattern/nvm/j750/timing.rb +73 -73
- data/pattern/read_write_reg.rb +61 -61
- data/pattern/reset.rb +4 -4
- data/pattern/subroutines.rb +69 -69
- data/pattern/tester_overlay.rb +61 -52
- data/pattern/tester_store.rb +28 -28
- data/program/_additional_erase.rb +7 -7
- data/program/_efa_resources.rb +7 -7
- data/program/_erase.rb +25 -25
- data/program/_erase_vfy.rb +5 -5
- data/program/_iv_resources.rb +10 -10
- data/program/basic_interface.rb +5 -5
- data/program/components/_prb1_main.rb +222 -222
- data/program/components/_temp.rb +6 -6
- data/program/custom_tests.rb +10 -10
- data/program/flow_control.rb +422 -422
- data/program/prb1.rb +11 -11
- data/program/prb1_resources.rb +28 -28
- data/program/prb2.rb +27 -27
- data/program/test.rb +29 -29
- data/program/uflex_resources.rb +199 -199
- data/templates/example.txt.erb +53 -53
- data/templates/j750/program_sheet.txt.erb +9 -9
- data/templates/manifest/v93k.yaml.erb +22 -22
- data/templates/web/index.md.erb +51 -51
- data/templates/web/layouts/_basic.html.erb +15 -15
- data/templates/web/partials/_navbar.html.erb +22 -22
- data/templates/web/release_notes.md.erb +5 -5
- metadata +2 -2
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
module OrigenTesters
|
|
2
|
-
class IGXLBasedTester
|
|
3
|
-
class Parser
|
|
4
|
-
class TestInstances < ::OrigenTesters::Parser::SearchableHash
|
|
5
|
-
attr_accessor :parser
|
|
6
|
-
|
|
7
|
-
def initialize(options = {})
|
|
8
|
-
@parser = options[:parser]
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def import(file)
|
|
12
|
-
File.readlines(file).each do |line|
|
|
13
|
-
l = TestInstance.new(line, parser: parser)
|
|
14
|
-
self[l.name] = l if l.valid?
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def inspect
|
|
19
|
-
"<TestInstances: #{size}>"
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
1
|
+
module OrigenTesters
|
|
2
|
+
class IGXLBasedTester
|
|
3
|
+
class Parser
|
|
4
|
+
class TestInstances < ::OrigenTesters::Parser::SearchableHash
|
|
5
|
+
attr_accessor :parser
|
|
6
|
+
|
|
7
|
+
def initialize(options = {})
|
|
8
|
+
@parser = options[:parser]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def import(file)
|
|
12
|
+
File.readlines(file).each do |line|
|
|
13
|
+
l = TestInstance.new(line, parser: parser)
|
|
14
|
+
self[l.name] = l if l.valid?
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def inspect
|
|
19
|
+
"<TestInstances: #{size}>"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
module OrigenTesters
|
|
2
|
-
class IGXLBasedTester
|
|
3
|
-
class Parser
|
|
4
|
-
class Timeset
|
|
5
|
-
attr_accessor :parser
|
|
6
|
-
|
|
7
|
-
def initialize(options = {})
|
|
8
|
-
@parser = options[:parser]
|
|
9
|
-
end
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
end
|
|
1
|
+
module OrigenTesters
|
|
2
|
+
class IGXLBasedTester
|
|
3
|
+
class Parser
|
|
4
|
+
class Timeset
|
|
5
|
+
attr_accessor :parser
|
|
6
|
+
|
|
7
|
+
def initialize(options = {})
|
|
8
|
+
@parser = options[:parser]
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -1,798 +1,798 @@
|
|
|
1
|
-
require 'origen_testers/igxl_based_tester/ultraflex/ate_hardware'
|
|
2
|
-
module OrigenTesters
|
|
3
|
-
module IGXLBasedTester
|
|
4
|
-
class UltraFLEX < Base
|
|
5
|
-
autoload :Generator, 'origen_testers/igxl_based_tester/ultraflex/generator.rb'
|
|
6
|
-
|
|
7
|
-
# Tester model to generate .atp patterns for the Teradyne UltraFLEX
|
|
8
|
-
#
|
|
9
|
-
# == Basic Usage
|
|
10
|
-
# $tester = Testers::UltraFLEX.new
|
|
11
|
-
# $tester.cycle # Generate a vector
|
|
12
|
-
#
|
|
13
|
-
# Many more methods exist to generate UltraFLEX specific micro-code, see below for
|
|
14
|
-
# details.
|
|
15
|
-
#
|
|
16
|
-
# Also note that this class inherits from the base IGXLBasedTester class and so all methods
|
|
17
|
-
# described there are also available.
|
|
18
|
-
|
|
19
|
-
# Returns a new UltraFLEX instance, normally there would only ever be one of these
|
|
20
|
-
# assigned to the global variable such as $tester by your target.
|
|
21
|
-
def initialize
|
|
22
|
-
super
|
|
23
|
-
@pipeline_depth = 255 # for single mode
|
|
24
|
-
@software_version = '8.10.10'
|
|
25
|
-
@name = 'ultraflex'
|
|
26
|
-
@opcode_mode = :single # there is also :dual
|
|
27
|
-
@counter_lsb_bits = 16 # individual counter bit length
|
|
28
|
-
@counter_msb_bits = 12 # temporary register commonly used to extend all counters
|
|
29
|
-
|
|
30
|
-
@flags = %w(cpuA_cond cpuB_cond cpuC_cond cpuD_cond)
|
|
31
|
-
@microcode[:enable] = 'branch_expr ='
|
|
32
|
-
@microcode[:set_flag] = 'set_cpu_cond'
|
|
33
|
-
@microcode[:mask_vector] = 'mask'
|
|
34
|
-
|
|
35
|
-
# Min required for a VM module-- not for SRM modules
|
|
36
|
-
# this handled in pattern_header below
|
|
37
|
-
@min_pattern_vectors = (@opcode_mode == :single) ? 64 : 128
|
|
38
|
-
|
|
39
|
-
@digital_instrument = 'hsdm' # 'hsdm' for HSD1000 and UP800, ok with UP1600 though
|
|
40
|
-
|
|
41
|
-
@capture_state = 'V' # STV requires valid 'V' expect data
|
|
42
|
-
|
|
43
|
-
@set_msb_issued = false # Internal flag to keep track of set_msb usage, allowing for set_lsb to be used as a readcode
|
|
44
|
-
@microcode[:keepalive] = 'keepalive'
|
|
45
|
-
|
|
46
|
-
@onemodsubs_found = false # flag to indicate whether a single-module subroutine has been implemented in this pattern
|
|
47
|
-
@nonmodsubs_found = false # flag to indicate whether a normal non-single-module subroutine has been implemented in this pattern
|
|
48
|
-
|
|
49
|
-
@dssc_send_delay = 144
|
|
50
|
-
@dssc_send_delay = 288 if @opcode_mode == :dual
|
|
51
|
-
@dssc_send_delay = 576 if @opcode_mode == :quad
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# Do a frequency measure.
|
|
55
|
-
#
|
|
56
|
-
# Write the necessary micro code to do a frequency measure on the given pin,
|
|
57
|
-
# optionally supply a read code to pass information to the tester.
|
|
58
|
-
#
|
|
59
|
-
# ==== Examples
|
|
60
|
-
# $tester.freq_count($top.pin(:d_out)) # Freq measure on pin "d_out"
|
|
61
|
-
# $tester.freq_count($top.pin(:d_out):readcode => 10)
|
|
62
|
-
def freq_count(pin, options = {})
|
|
63
|
-
options = { readcode: false
|
|
64
|
-
}.merge(options)
|
|
65
|
-
|
|
66
|
-
set_code(options[:readcode]) if options[:readcode]
|
|
67
|
-
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[0]})") # set cpuA
|
|
68
|
-
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[0]})") # set cpuB
|
|
69
|
-
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[1]})") # set cpuC
|
|
70
|
-
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[2]})") # set cpuD
|
|
71
|
-
cycle(microcode: "freq_loop_1: #{@microcode[:enable]} (#{@flags[0]})")
|
|
72
|
-
cycle(microcode: 'if (branch_expr) jump freq_loop_1')
|
|
73
|
-
pin.drive_lo
|
|
74
|
-
delay(2000)
|
|
75
|
-
pin.dont_care
|
|
76
|
-
cycle(microcode: "freq_loop_2: #{@microcode[:enable]} (#{@flags[1]})")
|
|
77
|
-
cycle(microcode: 'if (branch_expr) jump freq_loop_2')
|
|
78
|
-
cycle(microcode: "#{@microcode[:enable]} (#{@flags[2]})")
|
|
79
|
-
cycle(microcode: 'if (branch_expr) jump freq_loop_1')
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def memory_test(options = {})
|
|
83
|
-
options = {
|
|
84
|
-
gen_vector: true, # Default generate vector not just MTO opcode
|
|
85
|
-
init_counter_x: false, # initialize counter X
|
|
86
|
-
inc_counter_x: false, # increment counter X
|
|
87
|
-
init_counter_y: false, # initialize counter X
|
|
88
|
-
inc_counter_y: false, # increment counter X
|
|
89
|
-
capture_vector: false, # capture vector to memory using all mem types
|
|
90
|
-
capture_vector_mem0: false, # capture vector to memory type 0, here for J750 will be stv_m0
|
|
91
|
-
capture_vector_mem1: false, # capture vector to memory type 1, here for J750 will be stv_m1
|
|
92
|
-
capture_vector_mem2: false, # capture vector to memory type 2, here for J750 will be stv_c
|
|
93
|
-
pin: false, # pin on which to drive or expect data, pass pin object here!
|
|
94
|
-
pin_data: false, # pin data (:none, :drive, :expect)
|
|
95
|
-
use_dgen_group: false,
|
|
96
|
-
set_msb: false
|
|
97
|
-
}.merge(options)
|
|
98
|
-
|
|
99
|
-
mto_opcode = ''
|
|
100
|
-
|
|
101
|
-
if options[:init_counter_x]
|
|
102
|
-
mto_opcode += ' xenable_load jam_reg xa jam_reg'
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
if options[:init_counter_y]
|
|
106
|
-
mto_opcode += ' yenable_load jam_reg ya jam_reg'
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
if options[:inc_counter_x]
|
|
110
|
-
mto_opcode += ' xa inc'
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
if options[:inc_counter_y]
|
|
114
|
-
mto_opcode += ' ya inc'
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
if options[:use_dgen_group]
|
|
118
|
-
mto_opcode += ' dgroup 0'
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
if options[:set_msb]
|
|
122
|
-
microcode 'set_msb 1'
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
unless mto_opcode.eql?('')
|
|
126
|
-
mto_opcode = '(mto =' + mto_opcode + ')'
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
if options[:pin_data] == :expect
|
|
130
|
-
mto_opcode = 'stv'
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
if options[:gen_vector]
|
|
134
|
-
if options[:pin]
|
|
135
|
-
case options[:pin_data]
|
|
136
|
-
when :drive
|
|
137
|
-
# store current pin state
|
|
138
|
-
cur_pin_state = options[:pin].state.to_sym
|
|
139
|
-
options[:pin].drive_mem
|
|
140
|
-
when :expect
|
|
141
|
-
# store current pin state
|
|
142
|
-
cur_pin_state = options[:pin].state.to_sym
|
|
143
|
-
options[:pin].expect_mem
|
|
144
|
-
end
|
|
145
|
-
end
|
|
146
|
-
cycle(microcode: "#{mto_opcode}", dont_compress: false)
|
|
147
|
-
if options[:pin]
|
|
148
|
-
# restore previous pin state
|
|
149
|
-
case options[:pin_data]
|
|
150
|
-
when :drive
|
|
151
|
-
options[:pin].state = cur_pin_state
|
|
152
|
-
when :expect
|
|
153
|
-
options[:pin].state = cur_pin_state
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
else
|
|
157
|
-
microcode "#{mto_opcode}"
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
def call_match
|
|
162
|
-
# fail 'Method call_match not yet supported for UltraFLEX!'
|
|
163
|
-
@match_counter = @match_counter || 0
|
|
164
|
-
call_subroutine("match_done_#{@match_counter}")
|
|
165
|
-
@match_counter += 1 unless @match_counter == (@match_entries || 1) - 1
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
# Ultraflex implementation of J750-style 'set_code'
|
|
169
|
-
#
|
|
170
|
-
# Set a readcode, using one of the Ultraflex general-purpose counters.
|
|
171
|
-
# Counter C15 is used by default, this can be changed by the caller if necessary.
|
|
172
|
-
#
|
|
173
|
-
# Use to set an explicit readcode for communicating with the tester. This method
|
|
174
|
-
# will generate an additional vector (or 2, depending if set_msb is needed).
|
|
175
|
-
#
|
|
176
|
-
# NOTE: Some caveats when using this method:
|
|
177
|
-
# - When setting a counter from the pattern microcode, the actual Patgen counter value is set to n-1.
|
|
178
|
-
# This method adjusts by using a value of n+1, so the value read by the tester is the original intended value.
|
|
179
|
-
#
|
|
180
|
-
# - When setting a counter from pattern microcode, the upper bits must be loaded separately using 'set_msb'.
|
|
181
|
-
# This method calls the set_msb opcode if needed - note the tester must mask the upper 16 bits to get the desired value.
|
|
182
|
-
# The set_msb opcode will also generate a second vector the first time the set_code method is called.
|
|
183
|
-
#
|
|
184
|
-
# ==== Examples
|
|
185
|
-
# $tester.set_code(55)
|
|
186
|
-
#
|
|
187
|
-
def set_code(*code)
|
|
188
|
-
options = code.last.is_a?(Hash) ? code.pop : {}
|
|
189
|
-
options = { counter: 'c15'
|
|
190
|
-
}.merge(options)
|
|
191
|
-
cc " Using counter #{options[:counter]} as set_code replacement - value set to #{code[0]} + 1"
|
|
192
|
-
unless @set_msb_issued
|
|
193
|
-
set_msb(1)
|
|
194
|
-
cycle # set_msb doesn't issue a cycle
|
|
195
|
-
end
|
|
196
|
-
cycle(microcode: "set #{options[:counter]} #{code[0].next}") #+1 here to align with VBT
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
def set_code_no_msb(*code)
|
|
200
|
-
options = code.last.is_a?(Hash) ? code.pop : {}
|
|
201
|
-
options = { counter: 'c15'
|
|
202
|
-
}.merge(options)
|
|
203
|
-
unless @set_msb_issued
|
|
204
|
-
cycle # set_msb doesn't issue a cycle
|
|
205
|
-
end
|
|
206
|
-
cycle(microcode: "set #{options[:counter]} #{code[0].next}") #+1 here to align with VBT
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
def loop_vectors(name, number_of_loops, global = false, label_first = false)
|
|
210
|
-
if number_of_loops > 1
|
|
211
|
-
@loop_counters ||= {}
|
|
212
|
-
if @loop_counters[name]
|
|
213
|
-
@loop_counters[name] += 1
|
|
214
|
-
else
|
|
215
|
-
@loop_counters[name] = 0
|
|
216
|
-
end
|
|
217
|
-
loop_name = @loop_counters[name] == 0 ? name : "#{name}_#{@loop_counters[name]}"
|
|
218
|
-
if label_first
|
|
219
|
-
global_opt = (global) ? 'global ' : ''
|
|
220
|
-
microcode "#{global_opt}#{loop_name}: "
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
if "#{loop_name}" == 'row_loop'
|
|
224
|
-
cycle(microcode: 'loop c0')
|
|
225
|
-
elsif "#{loop_name}" == 'quad_loop'
|
|
226
|
-
cycle(microcode: 'loop c1')
|
|
227
|
-
elsif "#{loop_name}" == 'page_loop_red'
|
|
228
|
-
cycle(microcode: 'loop c2')
|
|
229
|
-
elsif "#{loop_name}" == 'page_loop_ecc'
|
|
230
|
-
cycle(microcode: 'loop c3')
|
|
231
|
-
elsif "#{loop_name}" == 'page_loop_data'
|
|
232
|
-
cycle(microcode: 'loop c4')
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
unless label_first
|
|
236
|
-
global_opt = (global) ? 'global ' : ''
|
|
237
|
-
cycle(microcode: "#{global_opt}#{loop_name}: ")
|
|
238
|
-
end
|
|
239
|
-
yield
|
|
240
|
-
cycle(microcode: "end_loop #{loop_name}")
|
|
241
|
-
else
|
|
242
|
-
yield
|
|
243
|
-
end
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
alias_method :loop_vector, :loop_vectors
|
|
247
|
-
|
|
248
|
-
def pattern_header(options = {})
|
|
249
|
-
options = {
|
|
250
|
-
instruments: {}
|
|
251
|
-
}.merge(options)
|
|
252
|
-
|
|
253
|
-
case $tester.vector_group_size
|
|
254
|
-
when 1
|
|
255
|
-
@opcode_mode = :single
|
|
256
|
-
when 2
|
|
257
|
-
@opcode_mode = :dual
|
|
258
|
-
when 4
|
|
259
|
-
@opcode_mode = :quad
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
options[:memory_test] = memory_test_en
|
|
263
|
-
options[:dc_pins] = get_dc_instr_pins
|
|
264
|
-
options[:digsrc_pins] = get_digsrc_pins
|
|
265
|
-
options[:digcap_pins] = get_digcap_pins
|
|
266
|
-
if options[:dc_pins]
|
|
267
|
-
options[:dc_pins].each do |pin|
|
|
268
|
-
options[:instruments].merge!(pin => 'DCVS')
|
|
269
|
-
end
|
|
270
|
-
end
|
|
271
|
-
|
|
272
|
-
# Syntax for Digital Source
|
|
273
|
-
# instruments = {
|
|
274
|
-
# pin-item:digsrc instrument-width: bit-order: instrument-mode:
|
|
275
|
-
# site-uniqueness: format: auto_cond;
|
|
276
|
-
# }
|
|
277
|
-
|
|
278
|
-
if options[:digsrc_pins]
|
|
279
|
-
@digsrc_settings.each do |setting_name, setting|
|
|
280
|
-
options.merge!(setting_name => setting) if options[setting_name].nil?
|
|
281
|
-
end
|
|
282
|
-
options[:digsrc_pins].each do |pin|
|
|
283
|
-
options[:instruments].merge!(pin => 'digsrc')
|
|
284
|
-
end
|
|
285
|
-
end
|
|
286
|
-
|
|
287
|
-
# Syntax for Digital Capture
|
|
288
|
-
# instruments = {
|
|
289
|
-
# pin-item:digcap instrument-width: bit-order: instrument-mode:
|
|
290
|
-
# format: data-type: auto_cond: auto_trig_enable: store_stv: receive_data;
|
|
291
|
-
# }
|
|
292
|
-
|
|
293
|
-
if options[:digcap_pins]
|
|
294
|
-
@digcap_settings.each do |setting_name, setting|
|
|
295
|
-
options.merge!(setting_name => setting) if options[setting_name].nil?
|
|
296
|
-
end
|
|
297
|
-
options[:digcap_pins].each do |pin|
|
|
298
|
-
options[:instruments].merge!(pin => 'digcap')
|
|
299
|
-
end
|
|
300
|
-
end
|
|
301
|
-
|
|
302
|
-
# If memory test, then add to instruments hash
|
|
303
|
-
if options[:memory_test]
|
|
304
|
-
options[:instruments].merge!('nil' => 'mto')
|
|
305
|
-
end
|
|
306
|
-
|
|
307
|
-
# If tester.overlay was used to implement digsrc, update the header instruments
|
|
308
|
-
auto_instr = {}
|
|
309
|
-
@overlay_history.each_pair do |pin_name, value|
|
|
310
|
-
if value[:is_digsrc]
|
|
311
|
-
microcode "// DigSrc SEND count for #{pin_name}: #{value[:count]}"
|
|
312
|
-
new_instr = 'DigSrc '
|
|
313
|
-
|
|
314
|
-
# override default settings
|
|
315
|
-
digsrc_overrides = source_memory(:digsrc).accumulate_attributes(pin_name)
|
|
316
|
-
|
|
317
|
-
# append instrument width
|
|
318
|
-
digsrc_instr_width = (dut.pin(pin_name)).size
|
|
319
|
-
# override default width if requested
|
|
320
|
-
digsrc_instr_width = digsrc_overrides[:size] unless digsrc_overrides[:size].nil?
|
|
321
|
-
new_instr += digsrc_instr_width.to_s
|
|
322
|
-
|
|
323
|
-
# append any other instrument override settings
|
|
324
|
-
if digsrc_instr_width > 1 && (dut.pin(pin_name)).size == 1
|
|
325
|
-
new_instr += ':serial'
|
|
326
|
-
if (digsrc_overrides[:bit_order] != :msb0) && (digsrc_overrides[:bit_order] != :msb)
|
|
327
|
-
new_instr += ':lsb'
|
|
328
|
-
else
|
|
329
|
-
new_instr += ':msb'
|
|
330
|
-
end
|
|
331
|
-
end
|
|
332
|
-
new_instr += ":format=#{digsrc_overrides[:format]}" unless digsrc_overrides[:format].nil?
|
|
333
|
-
new_instr += ":data_type=#{digsrc_overrides[:data_type]}" unless digsrc_overrides[:data_type].nil?
|
|
334
|
-
auto_instr["(#{pin_name})"] = new_instr
|
|
335
|
-
end
|
|
336
|
-
end
|
|
337
|
-
# If tester.store was used to implement digcap, update the header instruments
|
|
338
|
-
# TODO: a lot of duplication of digsrc logic here. This can be smart-ified.
|
|
339
|
-
@capture_history.each_pair do |pin_name, value|
|
|
340
|
-
if value[:is_digcap]
|
|
341
|
-
microcode "// DigCap Store count for #{pin_name}: #{value[:count]}"
|
|
342
|
-
new_instr = 'DigCap '
|
|
343
|
-
|
|
344
|
-
# override default settings
|
|
345
|
-
digcap_overrides = capture_memory(:digcap).accumulate_attributes(pin_name)
|
|
346
|
-
|
|
347
|
-
# append instrument width
|
|
348
|
-
digcap_instr_width = (dut.pin(pin_name)).size
|
|
349
|
-
digcap_instr_width = digcap_overrides[:size] unless digcap_overrides[:size].nil?
|
|
350
|
-
new_instr += digcap_instr_width.to_s
|
|
351
|
-
if digcap_instr_width > 1 && (dut.pin(pin_name)).size == 1
|
|
352
|
-
new_instr += ':serial'
|
|
353
|
-
if (digcap_overrides[:bit_order] != :msb0) && (digcap_overrides[:bit_order] != :msb)
|
|
354
|
-
new_instr += ':lsb'
|
|
355
|
-
else
|
|
356
|
-
new_instr += ':msb'
|
|
357
|
-
end
|
|
358
|
-
end
|
|
359
|
-
new_instr += ":format=#{digcap_overrides[:format]}" unless digcap_overrides[:format].nil?
|
|
360
|
-
new_instr += ":data_type=#{digcap_overrides[:data_type]}" unless digcap_overrides[:data_type].nil?
|
|
361
|
-
new_instr += ':auto_trig_enable' # always enable auto-trigger for digcap, trigger microcode isn't applied
|
|
362
|
-
auto_instr["(#{pin_name})"] = new_instr
|
|
363
|
-
end
|
|
364
|
-
end
|
|
365
|
-
options[:instruments] = options[:instruments].merge(auto_instr)
|
|
366
|
-
|
|
367
|
-
super(options.merge(digital_inst: @digital_instrument,
|
|
368
|
-
memory_test: false,
|
|
369
|
-
high_voltage: false,
|
|
370
|
-
svm_only: false
|
|
371
|
-
)) do |pin_list|
|
|
372
|
-
# if subroutine pattern has only single-module subroutines then skip module start
|
|
373
|
-
# (will be taken care of elsewhere)
|
|
374
|
-
unless options[:subroutine_pat] && @onemodsubs_found && !@nonmodsubs_found
|
|
375
|
-
microcode "#{options[:subroutine_pat] ? 'srm_vector' : 'vm_vector'}"
|
|
376
|
-
microcode "#{options[:pattern]} ($tset, #{pin_list})"
|
|
377
|
-
microcode '{'
|
|
378
|
-
end
|
|
379
|
-
# override min vector limit if subroutine pattern
|
|
380
|
-
@min_pattern_vectors = 0 if options[:subroutine_pat]
|
|
381
|
-
unless options[:subroutine_pat]
|
|
382
|
-
microcode "start_label #{options[:pattern]}_st:"
|
|
383
|
-
end
|
|
384
|
-
end
|
|
385
|
-
end
|
|
386
|
-
|
|
387
|
-
def pattern_footer(options = {})
|
|
388
|
-
# if subroutine pattern has any single-module subroutines then skip module end
|
|
389
|
-
# (will be taken care of elsewhere)
|
|
390
|
-
unless options[:subroutine_pat] && @onemodsubs_found
|
|
391
|
-
super(options.merge(end_module: false))
|
|
392
|
-
end
|
|
393
|
-
end
|
|
394
|
-
|
|
395
|
-
# allow for option of separate modules for each subroutine
|
|
396
|
-
# requirement is that any subroutines in their own module (options[:onemodsub] = true)
|
|
397
|
-
# MUST be implemented AFTER any subroutines in the common pattern module!
|
|
398
|
-
def start_subroutine(name, options = {})
|
|
399
|
-
if options[:onemodsub]
|
|
400
|
-
if @nonmodsubs_found && !@onemodsubs_found
|
|
401
|
-
# this means we need to do end module for non-single-module subroutines
|
|
402
|
-
# do only once!
|
|
403
|
-
pattern_footer(options.merge(subroutine_pat: true, end_module: false))
|
|
404
|
-
end
|
|
405
|
-
@onemodsubs_found = true # importnat put this after the call to pattern_footer above
|
|
406
|
-
pin_list = ordered_pins.map(&:name).join(', ')
|
|
407
|
-
microcode 'srm_vector'
|
|
408
|
-
microcode "#{name}_module ($tset, #{pin_list})"
|
|
409
|
-
microcode '{'
|
|
410
|
-
else
|
|
411
|
-
# normal subroutine to use common
|
|
412
|
-
if @onemodsubs_found
|
|
413
|
-
# give error -- requirement is that any normal subroutines using common pattern module
|
|
414
|
-
# must be done BEFORE any subroutines that need their own module definition!
|
|
415
|
-
fail "ERROR: Cannot implement any common module subroutines (#{name}) after implementing any single-module subroutines in the same pattern!"
|
|
416
|
-
end
|
|
417
|
-
@nonmodsubs_found = true
|
|
418
|
-
end
|
|
419
|
-
super(name, options)
|
|
420
|
-
end
|
|
421
|
-
|
|
422
|
-
def end_subroutine(cond = false, options = {})
|
|
423
|
-
(cond, options) = false, cond if cond.is_a?(Hash)
|
|
424
|
-
super(cond, options)
|
|
425
|
-
if options[:onemodsub]
|
|
426
|
-
microcode '}'
|
|
427
|
-
end
|
|
428
|
-
end
|
|
429
|
-
|
|
430
|
-
# Generates a match loop based on vector condition passed in via block
|
|
431
|
-
#
|
|
432
|
-
# This method is not really intended to be called directly, rather you should call
|
|
433
|
-
# via Tester#wait:
|
|
434
|
-
# e.g. $tester.wait(:match => true) do
|
|
435
|
-
# reg(:status_reg).bit(:done).read(1)! # vector condition that you want to match
|
|
436
|
-
# end
|
|
437
|
-
#
|
|
438
|
-
# The timeout should be provided in cycles, however when called via the wait method the
|
|
439
|
-
# time-based helpers (time_in_us, etc) will be converted to cycles for you.
|
|
440
|
-
#
|
|
441
|
-
# The following options are available to tailor the match loop behavior, defaults in
|
|
442
|
-
# parenthesis:
|
|
443
|
-
# * :force_fail_on_timeout (true) - Force a vector mis-compare if the match loop times out
|
|
444
|
-
# * :on_timeout_goto ("") - Optionally supply a label to branch to on timeout, by default will continue from the end of the match loop
|
|
445
|
-
# * :on_block_match_goto ("") - Optionally supply a label to branch to when block condition is met, by default will continue from the end of the match loop
|
|
446
|
-
# * :multiple_entries (false) - Supply an integer to generate multiple entries into the match (each with a unique readcode), this can be useful when debugging patterns with multiple matches
|
|
447
|
-
# * :force_fail_on_timeout (true) - force pattern to fail if timeout occurs
|
|
448
|
-
# * :global_loops (false) - whether match loop loops should use global labels
|
|
449
|
-
# * :manual_stop (false) - whether to use extra cpuB flag to resolve IG-XL v.3.50.xx bug where VBT clears cpuA immediately
|
|
450
|
-
# at start of PatFlagFunc instead of at end. Use will have to manually clear cpuB to resume this pattern.
|
|
451
|
-
# ==== Examples
|
|
452
|
-
# $tester.wait(:match => true, :time_in_us => 5000, :pin => $top.pin(:done), :state => :high) do
|
|
453
|
-
# <vectors>
|
|
454
|
-
# end
|
|
455
|
-
def match_block(timeout, options = {}, &block)
|
|
456
|
-
options = {
|
|
457
|
-
check_for_fails: false,
|
|
458
|
-
on_timeout_goto: false,
|
|
459
|
-
on_block_match_goto: false,
|
|
460
|
-
multiple_entries: false,
|
|
461
|
-
force_fail_on_timeout: true,
|
|
462
|
-
global_loops: false,
|
|
463
|
-
manual_stop: false,
|
|
464
|
-
clr_fail_post_match: false
|
|
465
|
-
}.merge(options)
|
|
466
|
-
|
|
467
|
-
unless block_given?
|
|
468
|
-
fail 'ERROR: block not passed to match_block!'
|
|
469
|
-
end
|
|
470
|
-
|
|
471
|
-
# if options[:check_for_fails]
|
|
472
|
-
# cc 'NOTE: check for fails prior to match loop not necessary on UltraFlex'
|
|
473
|
-
# end
|
|
474
|
-
|
|
475
|
-
# ss 'WARNING: MATCH LOOP FOR ULTRAFLEX STILL UNDER DEVELOPMENT'
|
|
476
|
-
|
|
477
|
-
# Create BlockArgs objects in order to receive multiple blocks
|
|
478
|
-
match_conditions = Origen::Utility::BlockArgs.new
|
|
479
|
-
fail_conditions = Origen::Utility::BlockArgs.new
|
|
480
|
-
|
|
481
|
-
# yield object to calling routine to get populated with blocks
|
|
482
|
-
if block.arity > 0
|
|
483
|
-
yield match_conditions, fail_conditions
|
|
484
|
-
else
|
|
485
|
-
# for backwards compatibility with Origen core call to match_block
|
|
486
|
-
match_conditions.add(&block)
|
|
487
|
-
fail_conditions.add(&block)
|
|
488
|
-
end
|
|
489
|
-
|
|
490
|
-
if options[:check_for_fails]
|
|
491
|
-
if options[:multiple_entries]
|
|
492
|
-
@match_entries.times do |i|
|
|
493
|
-
microcode "global subr match_done_#{i}:"
|
|
494
|
-
set_code(i + 100)
|
|
495
|
-
cycle(microcode: 'jump call_tester') unless i == @match_entries - 1
|
|
496
|
-
end
|
|
497
|
-
microcode 'call_tester:'
|
|
498
|
-
else
|
|
499
|
-
set_code(100)
|
|
500
|
-
end
|
|
501
|
-
cc 'Wait for any prior failures to propagate through the pipeline'
|
|
502
|
-
cycle(microcode: 'pipe_minus 1')
|
|
503
|
-
cc 'Now handshake with the tester to bin out and parts that have failed before they got here'
|
|
504
|
-
handshake(manual_stop: options[:manual_stop])
|
|
505
|
-
end
|
|
506
|
-
|
|
507
|
-
# Now do the main match loop
|
|
508
|
-
cc 'Start the match loop'
|
|
509
|
-
|
|
510
|
-
cycle # (:microcode => "set_msb #{counter_msb}") # set_msb microcode will be set below after counting match loop cycles
|
|
511
|
-
set_msb_vector = last_vector # remember the vector with set_msb opcode
|
|
512
|
-
|
|
513
|
-
cycle(microcode: 'branch_expr = (fail)')
|
|
514
|
-
|
|
515
|
-
global_opt = (options[:global_loops]) ? 'global ' : ''
|
|
516
|
-
microcode "#{global_opt}match_loop_#{@unique_counter}:"
|
|
517
|
-
|
|
518
|
-
cycle # (:microcode => "set c0 #{counter_lsb}")
|
|
519
|
-
set_c0_vector = last_vector # remember the vector with set_c0 opcode
|
|
520
|
-
|
|
521
|
-
microcode "match_result_loop_#{@unique_counter}:"
|
|
522
|
-
cycle(microcode: 'loop c0')
|
|
523
|
-
|
|
524
|
-
# count cycles in match loop block passed to help with meeting
|
|
525
|
-
# desired timeout value (have to back assign microcodes above)
|
|
526
|
-
prematch_cycle_count = cycle_count
|
|
527
|
-
match_conditions.each_with_index do |condition, i|
|
|
528
|
-
mask_fails(true)
|
|
529
|
-
condition.call # match condition
|
|
530
|
-
mask_fails(false)
|
|
531
|
-
|
|
532
|
-
cc ' Wait for the result to propagate through the pipeline'
|
|
533
|
-
cycle(microcode: 'pipe_minus 1')
|
|
534
|
-
inc_cycle_count(@pipeline_depth - 1) # Account for pipeline depth
|
|
535
|
-
cc "Branch if block condition #{i} not yet met"
|
|
536
|
-
cycle(microcode: "if (branch_expr) jump block_#{i}_notyet_matched_#{@unique_counter}")
|
|
537
|
-
cc 'Match found'
|
|
538
|
-
cycle(microcode: 'pop_loop')
|
|
539
|
-
if options[:on_block_match_goto]
|
|
540
|
-
if options[:on_block_match_goto].is_a?(Hash)
|
|
541
|
-
if options[:on_block_match_goto][i]
|
|
542
|
-
custom_jump = options[:on_block_match_goto][i]
|
|
543
|
-
else
|
|
544
|
-
custom_jump = nil
|
|
545
|
-
end
|
|
546
|
-
else
|
|
547
|
-
custom_jump = options[:on_block_match_goto]
|
|
548
|
-
end
|
|
549
|
-
end
|
|
550
|
-
if custom_jump
|
|
551
|
-
cycle(microcode: "jump #{custom_jump}")
|
|
552
|
-
else
|
|
553
|
-
cycle(microcode: "jump match_loop_end_#{@unique_counter}")
|
|
554
|
-
end
|
|
555
|
-
cc 'Match not yet found'
|
|
556
|
-
cycle(microcode: "block_#{i}_notyet_matched_#{@unique_counter}:")
|
|
557
|
-
end
|
|
558
|
-
|
|
559
|
-
match_conditions_cycle_count = cycle_count - prematch_cycle_count
|
|
560
|
-
cc "Match loop cycle count = #{match_conditions_cycle_count}"
|
|
561
|
-
|
|
562
|
-
# reduce timeout requested by match loop cycle count
|
|
563
|
-
timeout = (timeout.to_f / match_conditions_cycle_count).ceil
|
|
564
|
-
|
|
565
|
-
# Calculate the counter values appropriately hit the timeout requested
|
|
566
|
-
match_delay_cycles = false
|
|
567
|
-
|
|
568
|
-
# Determine full value of counter0
|
|
569
|
-
counter_value = timeout.to_f.floor
|
|
570
|
-
|
|
571
|
-
if counter_value < (2**@counter_lsb_bits)
|
|
572
|
-
# small value, don't need msb temp register
|
|
573
|
-
counter_msb = 1
|
|
574
|
-
counter_lsb = counter_value
|
|
575
|
-
elsif counter_value < (2**(@counter_lsb_bits + @counter_msb_bits))
|
|
576
|
-
# larger value, but smaller than counter maximum
|
|
577
|
-
counter_msb = counter_value # set MSB (lowest LSB bits get ignored)
|
|
578
|
-
counter_lsb = counter_value & (2**@counter_lsb_bits - 1) # set LSB
|
|
579
|
-
elsif counter_value < (2**(@counter_lsb_bits + @counter_msb_bits)) * @max_repeat_loop
|
|
580
|
-
# larger value, greater than counter, so add time delay per instance of loop to avoid using second counter
|
|
581
|
-
match_delay_cycles = (counter_value.to_f / (2**(@counter_lsb_bits + @counter_msb_bits))).ceil
|
|
582
|
-
counter_msb = (counter_value / match_delay_cycles).floor # set MSB (lowest LSB bits get ignored)
|
|
583
|
-
counter_lsb = counter_msb & (2**@counter_lsb_bits - 1) # set LSB
|
|
584
|
-
else
|
|
585
|
-
abort 'ERROR: timeout value too large in tester match method!'
|
|
586
|
-
end
|
|
587
|
-
|
|
588
|
-
# retroactively modify the counters based on cycles in match loop conditions
|
|
589
|
-
set_msb_vector.microcode = "set_msb #{counter_msb}"
|
|
590
|
-
set_c0_vector.microcode = "set c0 #{counter_lsb}"
|
|
591
|
-
|
|
592
|
-
if match_delay_cycles
|
|
593
|
-
cc 'Delay to meet timeout value'
|
|
594
|
-
cycle(repeat: match_delay_cycles) if match_delay_cycles
|
|
595
|
-
end
|
|
596
|
-
|
|
597
|
-
cycle(microcode: "end_loop match_result_loop_#{@unique_counter}")
|
|
598
|
-
|
|
599
|
-
if options[:force_fail_on_timeout]
|
|
600
|
-
cc 'To get here something has gone wrong, check blocks again to force a pattern failure'
|
|
601
|
-
fail_conditions.each do |condition|
|
|
602
|
-
cycle(microcode: 'pipe_minus 1')
|
|
603
|
-
condition.call
|
|
604
|
-
end
|
|
605
|
-
end
|
|
606
|
-
if options[:on_timeout_goto]
|
|
607
|
-
cycle(microcode: "jump #{options[:on_timeout_goto]}")
|
|
608
|
-
else
|
|
609
|
-
cycle(microcode: "jump match_loop_end_#{@unique_counter}")
|
|
610
|
-
end
|
|
611
|
-
cycle(microcode: "match_loop_end_#{@unique_counter}:")
|
|
612
|
-
|
|
613
|
-
@unique_counter += 1 # Increment so a different label will be applied if another
|
|
614
|
-
# handshake is called in the same pattern
|
|
615
|
-
end
|
|
616
|
-
|
|
617
|
-
# Handshake with the tester.
|
|
618
|
-
#
|
|
619
|
-
# Will set a cpu flag (A) and wait for it to be cleared by the tester, optionally
|
|
620
|
-
# pass in a read code to pass information to the tester.
|
|
621
|
-
#
|
|
622
|
-
# ==== Examples
|
|
623
|
-
# $tester.handshake # Pass control to the tester for a measurement
|
|
624
|
-
# $tester.handshake(:readcode => 10) # Trigger a specific action by the tester
|
|
625
|
-
def handshake(options = {})
|
|
626
|
-
options = {
|
|
627
|
-
readcode: false,
|
|
628
|
-
manual_stop: false, # set a 2nd CPU flag in case 1st flag is automatically cleared
|
|
629
|
-
}.merge(options)
|
|
630
|
-
if options[:readcode]
|
|
631
|
-
set_code(options[:readcode])
|
|
632
|
-
end
|
|
633
|
-
if options[:manual_stop]
|
|
634
|
-
cycle(microcode: "#{@microcode[:enable]} (#{@flags[1]})")
|
|
635
|
-
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[0]} #{@flags[1]})")
|
|
636
|
-
else
|
|
637
|
-
cycle(microcode: "#{@microcode[:enable]} (#{@flags[0]})")
|
|
638
|
-
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[0]})")
|
|
639
|
-
end
|
|
640
|
-
cycle(microcode: "loop_here_#{@unique_counter}: if (branch_expr) jump loop_here_#{@unique_counter}")
|
|
641
|
-
|
|
642
|
-
@unique_counter += 1 # Increment so a different label will be applied if another
|
|
643
|
-
# handshake is called in the same pattern
|
|
644
|
-
end
|
|
645
|
-
|
|
646
|
-
def keep_alive(options = {})
|
|
647
|
-
if options[:subroutine_pat]
|
|
648
|
-
cycle(microcode: 'clr_subr')
|
|
649
|
-
cycle(microcode: "#{@microcode[:enable]} (#{@flags[3]})")
|
|
650
|
-
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[3]})")
|
|
651
|
-
cycle(microcode: "loop_here_#{@unique_counter}: if (branch_expr) jump loop_here_#{@unique_counter}")
|
|
652
|
-
cycle
|
|
653
|
-
@unique_counter += 1 # Increment so a different label will be applied if another
|
|
654
|
-
else
|
|
655
|
-
$tester.cycle
|
|
656
|
-
call_subroutine('keep_alive')
|
|
657
|
-
end
|
|
658
|
-
end
|
|
659
|
-
|
|
660
|
-
# Capture a vector to the tester HRAM.
|
|
661
|
-
#
|
|
662
|
-
# This method applys a store vector (stv) opcode to the previous vector, note that is does
|
|
663
|
-
# not actually generate a new vector.
|
|
664
|
-
#
|
|
665
|
-
# Sometimes when generating vectors within a loop you may want to apply a stv opcode
|
|
666
|
-
# retrospectively to a previous vector, passing in an offset option will allow you
|
|
667
|
-
# to do this.
|
|
668
|
-
#
|
|
669
|
-
# On J750 the pins argument is ignored since the tester only supports whole vector capture.
|
|
670
|
-
#
|
|
671
|
-
# @example
|
|
672
|
-
# $tester.cycle # This is the vector you want to capture
|
|
673
|
-
# $tester.store # This applys the STV opcode
|
|
674
|
-
#
|
|
675
|
-
# $tester.cycle # This one gets stored
|
|
676
|
-
# $tester.cycle
|
|
677
|
-
# $tester.cycle
|
|
678
|
-
# $tester.store(:offset => -2) # Just realized I need to capture that earlier vector
|
|
679
|
-
def store(*pins)
|
|
680
|
-
options = pins.last.is_a?(Hash) ? pins.pop : {}
|
|
681
|
-
options = { offset: 0,
|
|
682
|
-
opcode: 'stv'
|
|
683
|
-
}.merge(options)
|
|
684
|
-
pins = pins.flatten.compact
|
|
685
|
-
if pins.empty?
|
|
686
|
-
fail 'For the UltraFLEX you must supply the pins to store/capture'
|
|
687
|
-
end
|
|
688
|
-
|
|
689
|
-
capt_style = options[:capture_style].nil? ? @capture_style : options[:capture_style]
|
|
690
|
-
if capt_style == :digcap
|
|
691
|
-
capt_microcode = dssc_store(pins, options)
|
|
692
|
-
else
|
|
693
|
-
capt_microcode = options[:opcode]
|
|
694
|
-
end
|
|
695
|
-
|
|
696
|
-
pins.each do |pin|
|
|
697
|
-
pin.restore_state do
|
|
698
|
-
pin.capture
|
|
699
|
-
update_vector_pin_val pin, offset: options[:offset]
|
|
700
|
-
last_vector(options[:offset]).dont_compress = true
|
|
701
|
-
end
|
|
702
|
-
end
|
|
703
|
-
update_vector microcode: capt_microcode, offset: options[:offset]
|
|
704
|
-
end
|
|
705
|
-
alias_method :to_hram, :store
|
|
706
|
-
alias_method :capture, :store
|
|
707
|
-
|
|
708
|
-
# use digcap to store, called by tester.store()
|
|
709
|
-
def dssc_store(pins, options)
|
|
710
|
-
repeat_count = last_vector(options[:offset]).repeat
|
|
711
|
-
capt_microcode = []
|
|
712
|
-
pins.each do |pin|
|
|
713
|
-
if @capture_history[pin.name].nil?
|
|
714
|
-
@capture_history[pin.name] = { is_digcap: true, count: repeat_count }
|
|
715
|
-
else
|
|
716
|
-
@capture_history[pin.name][:count] += repeat_count
|
|
717
|
-
end
|
|
718
|
-
capt_microcode << "((#{pin.name}):DigCap = Store)"
|
|
719
|
-
end
|
|
720
|
-
capt_microcode << 'stv'
|
|
721
|
-
capt_microcode.join(',')
|
|
722
|
-
end
|
|
723
|
-
|
|
724
|
-
def reload_counters(name)
|
|
725
|
-
microcode "reload #{name}"
|
|
726
|
-
end
|
|
727
|
-
|
|
728
|
-
def set_msb(integer)
|
|
729
|
-
microcode "set_msb #{integer}"
|
|
730
|
-
end
|
|
731
|
-
|
|
732
|
-
# Capture the next vector generated to HRAM
|
|
733
|
-
#
|
|
734
|
-
# This method applies a store vector (stv) opcode to the next vector to be generated,
|
|
735
|
-
# note that is does not actually generate a new vector.
|
|
736
|
-
#
|
|
737
|
-
# pin argument must be provided so that 'V' (valid) state can be applied to the pin
|
|
738
|
-
# if not already.
|
|
739
|
-
#
|
|
740
|
-
# @example
|
|
741
|
-
# $tester.store_next_cycle
|
|
742
|
-
# $tester.cycle # This is the vector that will be captured
|
|
743
|
-
def store_next_cycle(*pins)
|
|
744
|
-
options = pins.last.is_a?(Hash) ? pins.pop : {}
|
|
745
|
-
options = {
|
|
746
|
-
opcode: 'stv'
|
|
747
|
-
}.merge(options)
|
|
748
|
-
pins = pins.flatten.compact
|
|
749
|
-
if pins.empty?
|
|
750
|
-
fail 'For the UltraFLEX you must supply the pins to store/capture'
|
|
751
|
-
end
|
|
752
|
-
|
|
753
|
-
capt_style = options[:capture_style].nil? ? @capture_style : options[:capture_style]
|
|
754
|
-
if capt_style == :digcap
|
|
755
|
-
capt_microcode = []
|
|
756
|
-
repeat_count = options[:repeat].nil? ? 1 : options[:repeat]
|
|
757
|
-
pins.each do |pin|
|
|
758
|
-
if @capture_history[pin.name].nil?
|
|
759
|
-
@capture_history[pin.name] = { is_digcap: true, count: repeat_count }
|
|
760
|
-
else
|
|
761
|
-
@capture_history[pin.name][:count] += repeat_count
|
|
762
|
-
end
|
|
763
|
-
capt_microcode << "((#{pin.name}):DigCap = Store)"
|
|
764
|
-
end
|
|
765
|
-
capt_microcode << 'stv'
|
|
766
|
-
capt_microcode = capt_microcode.join(',')
|
|
767
|
-
else
|
|
768
|
-
capt_microcode = options[:opcode]
|
|
769
|
-
end
|
|
770
|
-
|
|
771
|
-
pins.each { |pin| pin.save; pin.capture }
|
|
772
|
-
# Register this clean up function to be run after the next vector
|
|
773
|
-
# is generated (SMcG: cool or what! DH: Yes, very cool!)
|
|
774
|
-
preset_next_vector(microcode: capt_microcode) do
|
|
775
|
-
pins.each(&:restore)
|
|
776
|
-
end
|
|
777
|
-
end
|
|
778
|
-
alias_method :store!, :store_next_cycle
|
|
779
|
-
|
|
780
|
-
# ate_hardware stores "key" UltraFLEX hardware information needed for test program generation
|
|
781
|
-
# Instrument types available for ppmu: "HSD-M", "HSD-U", "HSD-4G", and "HSS-6G".
|
|
782
|
-
# Sample usage: $tester.ate_hardware("HSD-U").ppmu
|
|
783
|
-
# Instrument types available for supply: "VSM", "VSMx2", "VSMx4", "HexVS", "HexVSx2", "HexVSx4",
|
|
784
|
-
# "HexVSx6", "HexVS+x2", "HexVS+x4", "HexVS+x6", "HDVS1", "HDVS1x2", "HDVS1x4", "VHDVS",
|
|
785
|
-
# "VHDVS_HC", "VHDVSx2", "VHDVS_HCx2", "VHDVS_HCx4", "VHDVS_HCx8", "VHDVS+", "VHDVS_HC+",
|
|
786
|
-
# "VHDVS+x2", "VHDVS_HC+x2", "VHDVS_HC+x4", and "VHDVS_HC+x8".
|
|
787
|
-
# HDVS1 is also known as HDVS. VHDVS is also known as UVS256.
|
|
788
|
-
# x2 is Merged2, x4 is Merged4, x6 is Merged6. _HC is High-Current.
|
|
789
|
-
# + is High-Accuracy.
|
|
790
|
-
# Sample usage: $tester.ate_hardware("VSM").supply
|
|
791
|
-
# Sample usage: $tester.ate_hardware("HSD-M").ppmu
|
|
792
|
-
def ate_hardware(instrumentname = '')
|
|
793
|
-
@ate_hardware = ATEHardware.new(instrumentname)
|
|
794
|
-
end
|
|
795
|
-
end
|
|
796
|
-
end
|
|
797
|
-
UltraFLEX = IGXLBasedTester::UltraFLEX
|
|
798
|
-
end
|
|
1
|
+
require 'origen_testers/igxl_based_tester/ultraflex/ate_hardware'
|
|
2
|
+
module OrigenTesters
|
|
3
|
+
module IGXLBasedTester
|
|
4
|
+
class UltraFLEX < Base
|
|
5
|
+
autoload :Generator, 'origen_testers/igxl_based_tester/ultraflex/generator.rb'
|
|
6
|
+
|
|
7
|
+
# Tester model to generate .atp patterns for the Teradyne UltraFLEX
|
|
8
|
+
#
|
|
9
|
+
# == Basic Usage
|
|
10
|
+
# $tester = Testers::UltraFLEX.new
|
|
11
|
+
# $tester.cycle # Generate a vector
|
|
12
|
+
#
|
|
13
|
+
# Many more methods exist to generate UltraFLEX specific micro-code, see below for
|
|
14
|
+
# details.
|
|
15
|
+
#
|
|
16
|
+
# Also note that this class inherits from the base IGXLBasedTester class and so all methods
|
|
17
|
+
# described there are also available.
|
|
18
|
+
|
|
19
|
+
# Returns a new UltraFLEX instance, normally there would only ever be one of these
|
|
20
|
+
# assigned to the global variable such as $tester by your target.
|
|
21
|
+
def initialize
|
|
22
|
+
super
|
|
23
|
+
@pipeline_depth = 255 # for single mode
|
|
24
|
+
@software_version = '8.10.10'
|
|
25
|
+
@name = 'ultraflex'
|
|
26
|
+
@opcode_mode = :single # there is also :dual
|
|
27
|
+
@counter_lsb_bits = 16 # individual counter bit length
|
|
28
|
+
@counter_msb_bits = 12 # temporary register commonly used to extend all counters
|
|
29
|
+
|
|
30
|
+
@flags = %w(cpuA_cond cpuB_cond cpuC_cond cpuD_cond)
|
|
31
|
+
@microcode[:enable] = 'branch_expr ='
|
|
32
|
+
@microcode[:set_flag] = 'set_cpu_cond'
|
|
33
|
+
@microcode[:mask_vector] = 'mask'
|
|
34
|
+
|
|
35
|
+
# Min required for a VM module-- not for SRM modules
|
|
36
|
+
# this handled in pattern_header below
|
|
37
|
+
@min_pattern_vectors = (@opcode_mode == :single) ? 64 : 128
|
|
38
|
+
|
|
39
|
+
@digital_instrument = 'hsdm' # 'hsdm' for HSD1000 and UP800, ok with UP1600 though
|
|
40
|
+
|
|
41
|
+
@capture_state = 'V' # STV requires valid 'V' expect data
|
|
42
|
+
|
|
43
|
+
@set_msb_issued = false # Internal flag to keep track of set_msb usage, allowing for set_lsb to be used as a readcode
|
|
44
|
+
@microcode[:keepalive] = 'keepalive'
|
|
45
|
+
|
|
46
|
+
@onemodsubs_found = false # flag to indicate whether a single-module subroutine has been implemented in this pattern
|
|
47
|
+
@nonmodsubs_found = false # flag to indicate whether a normal non-single-module subroutine has been implemented in this pattern
|
|
48
|
+
|
|
49
|
+
@dssc_send_delay = 144
|
|
50
|
+
@dssc_send_delay = 288 if @opcode_mode == :dual
|
|
51
|
+
@dssc_send_delay = 576 if @opcode_mode == :quad
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Do a frequency measure.
|
|
55
|
+
#
|
|
56
|
+
# Write the necessary micro code to do a frequency measure on the given pin,
|
|
57
|
+
# optionally supply a read code to pass information to the tester.
|
|
58
|
+
#
|
|
59
|
+
# ==== Examples
|
|
60
|
+
# $tester.freq_count($top.pin(:d_out)) # Freq measure on pin "d_out"
|
|
61
|
+
# $tester.freq_count($top.pin(:d_out):readcode => 10)
|
|
62
|
+
def freq_count(pin, options = {})
|
|
63
|
+
options = { readcode: false
|
|
64
|
+
}.merge(options)
|
|
65
|
+
|
|
66
|
+
set_code(options[:readcode]) if options[:readcode]
|
|
67
|
+
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[0]})") # set cpuA
|
|
68
|
+
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[0]})") # set cpuB
|
|
69
|
+
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[1]})") # set cpuC
|
|
70
|
+
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[2]})") # set cpuD
|
|
71
|
+
cycle(microcode: "freq_loop_1: #{@microcode[:enable]} (#{@flags[0]})")
|
|
72
|
+
cycle(microcode: 'if (branch_expr) jump freq_loop_1')
|
|
73
|
+
pin.drive_lo
|
|
74
|
+
delay(2000)
|
|
75
|
+
pin.dont_care
|
|
76
|
+
cycle(microcode: "freq_loop_2: #{@microcode[:enable]} (#{@flags[1]})")
|
|
77
|
+
cycle(microcode: 'if (branch_expr) jump freq_loop_2')
|
|
78
|
+
cycle(microcode: "#{@microcode[:enable]} (#{@flags[2]})")
|
|
79
|
+
cycle(microcode: 'if (branch_expr) jump freq_loop_1')
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def memory_test(options = {})
|
|
83
|
+
options = {
|
|
84
|
+
gen_vector: true, # Default generate vector not just MTO opcode
|
|
85
|
+
init_counter_x: false, # initialize counter X
|
|
86
|
+
inc_counter_x: false, # increment counter X
|
|
87
|
+
init_counter_y: false, # initialize counter X
|
|
88
|
+
inc_counter_y: false, # increment counter X
|
|
89
|
+
capture_vector: false, # capture vector to memory using all mem types
|
|
90
|
+
capture_vector_mem0: false, # capture vector to memory type 0, here for J750 will be stv_m0
|
|
91
|
+
capture_vector_mem1: false, # capture vector to memory type 1, here for J750 will be stv_m1
|
|
92
|
+
capture_vector_mem2: false, # capture vector to memory type 2, here for J750 will be stv_c
|
|
93
|
+
pin: false, # pin on which to drive or expect data, pass pin object here!
|
|
94
|
+
pin_data: false, # pin data (:none, :drive, :expect)
|
|
95
|
+
use_dgen_group: false,
|
|
96
|
+
set_msb: false
|
|
97
|
+
}.merge(options)
|
|
98
|
+
|
|
99
|
+
mto_opcode = ''
|
|
100
|
+
|
|
101
|
+
if options[:init_counter_x]
|
|
102
|
+
mto_opcode += ' xenable_load jam_reg xa jam_reg'
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
if options[:init_counter_y]
|
|
106
|
+
mto_opcode += ' yenable_load jam_reg ya jam_reg'
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
if options[:inc_counter_x]
|
|
110
|
+
mto_opcode += ' xa inc'
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
if options[:inc_counter_y]
|
|
114
|
+
mto_opcode += ' ya inc'
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
if options[:use_dgen_group]
|
|
118
|
+
mto_opcode += ' dgroup 0'
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
if options[:set_msb]
|
|
122
|
+
microcode 'set_msb 1'
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
unless mto_opcode.eql?('')
|
|
126
|
+
mto_opcode = '(mto =' + mto_opcode + ')'
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
if options[:pin_data] == :expect
|
|
130
|
+
mto_opcode = 'stv'
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
if options[:gen_vector]
|
|
134
|
+
if options[:pin]
|
|
135
|
+
case options[:pin_data]
|
|
136
|
+
when :drive
|
|
137
|
+
# store current pin state
|
|
138
|
+
cur_pin_state = options[:pin].state.to_sym
|
|
139
|
+
options[:pin].drive_mem
|
|
140
|
+
when :expect
|
|
141
|
+
# store current pin state
|
|
142
|
+
cur_pin_state = options[:pin].state.to_sym
|
|
143
|
+
options[:pin].expect_mem
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
cycle(microcode: "#{mto_opcode}", dont_compress: false)
|
|
147
|
+
if options[:pin]
|
|
148
|
+
# restore previous pin state
|
|
149
|
+
case options[:pin_data]
|
|
150
|
+
when :drive
|
|
151
|
+
options[:pin].state = cur_pin_state
|
|
152
|
+
when :expect
|
|
153
|
+
options[:pin].state = cur_pin_state
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
else
|
|
157
|
+
microcode "#{mto_opcode}"
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def call_match
|
|
162
|
+
# fail 'Method call_match not yet supported for UltraFLEX!'
|
|
163
|
+
@match_counter = @match_counter || 0
|
|
164
|
+
call_subroutine("match_done_#{@match_counter}")
|
|
165
|
+
@match_counter += 1 unless @match_counter == (@match_entries || 1) - 1
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Ultraflex implementation of J750-style 'set_code'
|
|
169
|
+
#
|
|
170
|
+
# Set a readcode, using one of the Ultraflex general-purpose counters.
|
|
171
|
+
# Counter C15 is used by default, this can be changed by the caller if necessary.
|
|
172
|
+
#
|
|
173
|
+
# Use to set an explicit readcode for communicating with the tester. This method
|
|
174
|
+
# will generate an additional vector (or 2, depending if set_msb is needed).
|
|
175
|
+
#
|
|
176
|
+
# NOTE: Some caveats when using this method:
|
|
177
|
+
# - When setting a counter from the pattern microcode, the actual Patgen counter value is set to n-1.
|
|
178
|
+
# This method adjusts by using a value of n+1, so the value read by the tester is the original intended value.
|
|
179
|
+
#
|
|
180
|
+
# - When setting a counter from pattern microcode, the upper bits must be loaded separately using 'set_msb'.
|
|
181
|
+
# This method calls the set_msb opcode if needed - note the tester must mask the upper 16 bits to get the desired value.
|
|
182
|
+
# The set_msb opcode will also generate a second vector the first time the set_code method is called.
|
|
183
|
+
#
|
|
184
|
+
# ==== Examples
|
|
185
|
+
# $tester.set_code(55)
|
|
186
|
+
#
|
|
187
|
+
def set_code(*code)
|
|
188
|
+
options = code.last.is_a?(Hash) ? code.pop : {}
|
|
189
|
+
options = { counter: 'c15'
|
|
190
|
+
}.merge(options)
|
|
191
|
+
cc " Using counter #{options[:counter]} as set_code replacement - value set to #{code[0]} + 1"
|
|
192
|
+
unless @set_msb_issued
|
|
193
|
+
set_msb(1)
|
|
194
|
+
cycle # set_msb doesn't issue a cycle
|
|
195
|
+
end
|
|
196
|
+
cycle(microcode: "set #{options[:counter]} #{code[0].next}") #+1 here to align with VBT
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def set_code_no_msb(*code)
|
|
200
|
+
options = code.last.is_a?(Hash) ? code.pop : {}
|
|
201
|
+
options = { counter: 'c15'
|
|
202
|
+
}.merge(options)
|
|
203
|
+
unless @set_msb_issued
|
|
204
|
+
cycle # set_msb doesn't issue a cycle
|
|
205
|
+
end
|
|
206
|
+
cycle(microcode: "set #{options[:counter]} #{code[0].next}") #+1 here to align with VBT
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def loop_vectors(name, number_of_loops, global = false, label_first = false)
|
|
210
|
+
if number_of_loops > 1
|
|
211
|
+
@loop_counters ||= {}
|
|
212
|
+
if @loop_counters[name]
|
|
213
|
+
@loop_counters[name] += 1
|
|
214
|
+
else
|
|
215
|
+
@loop_counters[name] = 0
|
|
216
|
+
end
|
|
217
|
+
loop_name = @loop_counters[name] == 0 ? name : "#{name}_#{@loop_counters[name]}"
|
|
218
|
+
if label_first
|
|
219
|
+
global_opt = (global) ? 'global ' : ''
|
|
220
|
+
microcode "#{global_opt}#{loop_name}: "
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
if "#{loop_name}" == 'row_loop'
|
|
224
|
+
cycle(microcode: 'loop c0')
|
|
225
|
+
elsif "#{loop_name}" == 'quad_loop'
|
|
226
|
+
cycle(microcode: 'loop c1')
|
|
227
|
+
elsif "#{loop_name}" == 'page_loop_red'
|
|
228
|
+
cycle(microcode: 'loop c2')
|
|
229
|
+
elsif "#{loop_name}" == 'page_loop_ecc'
|
|
230
|
+
cycle(microcode: 'loop c3')
|
|
231
|
+
elsif "#{loop_name}" == 'page_loop_data'
|
|
232
|
+
cycle(microcode: 'loop c4')
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
unless label_first
|
|
236
|
+
global_opt = (global) ? 'global ' : ''
|
|
237
|
+
cycle(microcode: "#{global_opt}#{loop_name}: ")
|
|
238
|
+
end
|
|
239
|
+
yield
|
|
240
|
+
cycle(microcode: "end_loop #{loop_name}")
|
|
241
|
+
else
|
|
242
|
+
yield
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
alias_method :loop_vector, :loop_vectors
|
|
247
|
+
|
|
248
|
+
def pattern_header(options = {})
|
|
249
|
+
options = {
|
|
250
|
+
instruments: {}
|
|
251
|
+
}.merge(options)
|
|
252
|
+
|
|
253
|
+
case $tester.vector_group_size
|
|
254
|
+
when 1
|
|
255
|
+
@opcode_mode = :single
|
|
256
|
+
when 2
|
|
257
|
+
@opcode_mode = :dual
|
|
258
|
+
when 4
|
|
259
|
+
@opcode_mode = :quad
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
options[:memory_test] = memory_test_en
|
|
263
|
+
options[:dc_pins] = get_dc_instr_pins
|
|
264
|
+
options[:digsrc_pins] = get_digsrc_pins
|
|
265
|
+
options[:digcap_pins] = get_digcap_pins
|
|
266
|
+
if options[:dc_pins]
|
|
267
|
+
options[:dc_pins].each do |pin|
|
|
268
|
+
options[:instruments].merge!(pin => 'DCVS')
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Syntax for Digital Source
|
|
273
|
+
# instruments = {
|
|
274
|
+
# pin-item:digsrc instrument-width: bit-order: instrument-mode:
|
|
275
|
+
# site-uniqueness: format: auto_cond;
|
|
276
|
+
# }
|
|
277
|
+
|
|
278
|
+
if options[:digsrc_pins]
|
|
279
|
+
@digsrc_settings.each do |setting_name, setting|
|
|
280
|
+
options.merge!(setting_name => setting) if options[setting_name].nil?
|
|
281
|
+
end
|
|
282
|
+
options[:digsrc_pins].each do |pin|
|
|
283
|
+
options[:instruments].merge!(pin => 'digsrc')
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# Syntax for Digital Capture
|
|
288
|
+
# instruments = {
|
|
289
|
+
# pin-item:digcap instrument-width: bit-order: instrument-mode:
|
|
290
|
+
# format: data-type: auto_cond: auto_trig_enable: store_stv: receive_data;
|
|
291
|
+
# }
|
|
292
|
+
|
|
293
|
+
if options[:digcap_pins]
|
|
294
|
+
@digcap_settings.each do |setting_name, setting|
|
|
295
|
+
options.merge!(setting_name => setting) if options[setting_name].nil?
|
|
296
|
+
end
|
|
297
|
+
options[:digcap_pins].each do |pin|
|
|
298
|
+
options[:instruments].merge!(pin => 'digcap')
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# If memory test, then add to instruments hash
|
|
303
|
+
if options[:memory_test]
|
|
304
|
+
options[:instruments].merge!('nil' => 'mto')
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# If tester.overlay was used to implement digsrc, update the header instruments
|
|
308
|
+
auto_instr = {}
|
|
309
|
+
@overlay_history.each_pair do |pin_name, value|
|
|
310
|
+
if value[:is_digsrc]
|
|
311
|
+
microcode "// DigSrc SEND count for #{pin_name}: #{value[:count]}"
|
|
312
|
+
new_instr = 'DigSrc '
|
|
313
|
+
|
|
314
|
+
# override default settings
|
|
315
|
+
digsrc_overrides = source_memory(:digsrc).accumulate_attributes(pin_name)
|
|
316
|
+
|
|
317
|
+
# append instrument width
|
|
318
|
+
digsrc_instr_width = (dut.pin(pin_name)).size
|
|
319
|
+
# override default width if requested
|
|
320
|
+
digsrc_instr_width = digsrc_overrides[:size] unless digsrc_overrides[:size].nil?
|
|
321
|
+
new_instr += digsrc_instr_width.to_s
|
|
322
|
+
|
|
323
|
+
# append any other instrument override settings
|
|
324
|
+
if digsrc_instr_width > 1 && (dut.pin(pin_name)).size == 1
|
|
325
|
+
new_instr += ':serial'
|
|
326
|
+
if (digsrc_overrides[:bit_order] != :msb0) && (digsrc_overrides[:bit_order] != :msb)
|
|
327
|
+
new_instr += ':lsb'
|
|
328
|
+
else
|
|
329
|
+
new_instr += ':msb'
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
new_instr += ":format=#{digsrc_overrides[:format]}" unless digsrc_overrides[:format].nil?
|
|
333
|
+
new_instr += ":data_type=#{digsrc_overrides[:data_type]}" unless digsrc_overrides[:data_type].nil?
|
|
334
|
+
auto_instr["(#{pin_name})"] = new_instr
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
# If tester.store was used to implement digcap, update the header instruments
|
|
338
|
+
# TODO: a lot of duplication of digsrc logic here. This can be smart-ified.
|
|
339
|
+
@capture_history.each_pair do |pin_name, value|
|
|
340
|
+
if value[:is_digcap]
|
|
341
|
+
microcode "// DigCap Store count for #{pin_name}: #{value[:count]}"
|
|
342
|
+
new_instr = 'DigCap '
|
|
343
|
+
|
|
344
|
+
# override default settings
|
|
345
|
+
digcap_overrides = capture_memory(:digcap).accumulate_attributes(pin_name)
|
|
346
|
+
|
|
347
|
+
# append instrument width
|
|
348
|
+
digcap_instr_width = (dut.pin(pin_name)).size
|
|
349
|
+
digcap_instr_width = digcap_overrides[:size] unless digcap_overrides[:size].nil?
|
|
350
|
+
new_instr += digcap_instr_width.to_s
|
|
351
|
+
if digcap_instr_width > 1 && (dut.pin(pin_name)).size == 1
|
|
352
|
+
new_instr += ':serial'
|
|
353
|
+
if (digcap_overrides[:bit_order] != :msb0) && (digcap_overrides[:bit_order] != :msb)
|
|
354
|
+
new_instr += ':lsb'
|
|
355
|
+
else
|
|
356
|
+
new_instr += ':msb'
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
new_instr += ":format=#{digcap_overrides[:format]}" unless digcap_overrides[:format].nil?
|
|
360
|
+
new_instr += ":data_type=#{digcap_overrides[:data_type]}" unless digcap_overrides[:data_type].nil?
|
|
361
|
+
new_instr += ':auto_trig_enable' # always enable auto-trigger for digcap, trigger microcode isn't applied
|
|
362
|
+
auto_instr["(#{pin_name})"] = new_instr
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
options[:instruments] = options[:instruments].merge(auto_instr)
|
|
366
|
+
|
|
367
|
+
super(options.merge(digital_inst: @digital_instrument,
|
|
368
|
+
memory_test: false,
|
|
369
|
+
high_voltage: false,
|
|
370
|
+
svm_only: false
|
|
371
|
+
)) do |pin_list|
|
|
372
|
+
# if subroutine pattern has only single-module subroutines then skip module start
|
|
373
|
+
# (will be taken care of elsewhere)
|
|
374
|
+
unless options[:subroutine_pat] && @onemodsubs_found && !@nonmodsubs_found
|
|
375
|
+
microcode "#{options[:subroutine_pat] ? 'srm_vector' : 'vm_vector'}"
|
|
376
|
+
microcode "#{options[:pattern]} ($tset, #{pin_list})"
|
|
377
|
+
microcode '{'
|
|
378
|
+
end
|
|
379
|
+
# override min vector limit if subroutine pattern
|
|
380
|
+
@min_pattern_vectors = 0 if options[:subroutine_pat]
|
|
381
|
+
unless options[:subroutine_pat]
|
|
382
|
+
microcode "start_label #{options[:pattern]}_st:"
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
def pattern_footer(options = {})
|
|
388
|
+
# if subroutine pattern has any single-module subroutines then skip module end
|
|
389
|
+
# (will be taken care of elsewhere)
|
|
390
|
+
unless options[:subroutine_pat] && @onemodsubs_found
|
|
391
|
+
super(options.merge(end_module: false))
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# allow for option of separate modules for each subroutine
|
|
396
|
+
# requirement is that any subroutines in their own module (options[:onemodsub] = true)
|
|
397
|
+
# MUST be implemented AFTER any subroutines in the common pattern module!
|
|
398
|
+
def start_subroutine(name, options = {})
|
|
399
|
+
if options[:onemodsub]
|
|
400
|
+
if @nonmodsubs_found && !@onemodsubs_found
|
|
401
|
+
# this means we need to do end module for non-single-module subroutines
|
|
402
|
+
# do only once!
|
|
403
|
+
pattern_footer(options.merge(subroutine_pat: true, end_module: false))
|
|
404
|
+
end
|
|
405
|
+
@onemodsubs_found = true # importnat put this after the call to pattern_footer above
|
|
406
|
+
pin_list = ordered_pins.map(&:name).join(', ')
|
|
407
|
+
microcode 'srm_vector'
|
|
408
|
+
microcode "#{name}_module ($tset, #{pin_list})"
|
|
409
|
+
microcode '{'
|
|
410
|
+
else
|
|
411
|
+
# normal subroutine to use common
|
|
412
|
+
if @onemodsubs_found
|
|
413
|
+
# give error -- requirement is that any normal subroutines using common pattern module
|
|
414
|
+
# must be done BEFORE any subroutines that need their own module definition!
|
|
415
|
+
fail "ERROR: Cannot implement any common module subroutines (#{name}) after implementing any single-module subroutines in the same pattern!"
|
|
416
|
+
end
|
|
417
|
+
@nonmodsubs_found = true
|
|
418
|
+
end
|
|
419
|
+
super(name, options)
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
def end_subroutine(cond = false, options = {})
|
|
423
|
+
(cond, options) = false, cond if cond.is_a?(Hash)
|
|
424
|
+
super(cond, options)
|
|
425
|
+
if options[:onemodsub]
|
|
426
|
+
microcode '}'
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
# Generates a match loop based on vector condition passed in via block
|
|
431
|
+
#
|
|
432
|
+
# This method is not really intended to be called directly, rather you should call
|
|
433
|
+
# via Tester#wait:
|
|
434
|
+
# e.g. $tester.wait(:match => true) do
|
|
435
|
+
# reg(:status_reg).bit(:done).read(1)! # vector condition that you want to match
|
|
436
|
+
# end
|
|
437
|
+
#
|
|
438
|
+
# The timeout should be provided in cycles, however when called via the wait method the
|
|
439
|
+
# time-based helpers (time_in_us, etc) will be converted to cycles for you.
|
|
440
|
+
#
|
|
441
|
+
# The following options are available to tailor the match loop behavior, defaults in
|
|
442
|
+
# parenthesis:
|
|
443
|
+
# * :force_fail_on_timeout (true) - Force a vector mis-compare if the match loop times out
|
|
444
|
+
# * :on_timeout_goto ("") - Optionally supply a label to branch to on timeout, by default will continue from the end of the match loop
|
|
445
|
+
# * :on_block_match_goto ("") - Optionally supply a label to branch to when block condition is met, by default will continue from the end of the match loop
|
|
446
|
+
# * :multiple_entries (false) - Supply an integer to generate multiple entries into the match (each with a unique readcode), this can be useful when debugging patterns with multiple matches
|
|
447
|
+
# * :force_fail_on_timeout (true) - force pattern to fail if timeout occurs
|
|
448
|
+
# * :global_loops (false) - whether match loop loops should use global labels
|
|
449
|
+
# * :manual_stop (false) - whether to use extra cpuB flag to resolve IG-XL v.3.50.xx bug where VBT clears cpuA immediately
|
|
450
|
+
# at start of PatFlagFunc instead of at end. Use will have to manually clear cpuB to resume this pattern.
|
|
451
|
+
# ==== Examples
|
|
452
|
+
# $tester.wait(:match => true, :time_in_us => 5000, :pin => $top.pin(:done), :state => :high) do
|
|
453
|
+
# <vectors>
|
|
454
|
+
# end
|
|
455
|
+
def match_block(timeout, options = {}, &block)
|
|
456
|
+
options = {
|
|
457
|
+
check_for_fails: false,
|
|
458
|
+
on_timeout_goto: false,
|
|
459
|
+
on_block_match_goto: false,
|
|
460
|
+
multiple_entries: false,
|
|
461
|
+
force_fail_on_timeout: true,
|
|
462
|
+
global_loops: false,
|
|
463
|
+
manual_stop: false,
|
|
464
|
+
clr_fail_post_match: false
|
|
465
|
+
}.merge(options)
|
|
466
|
+
|
|
467
|
+
unless block_given?
|
|
468
|
+
fail 'ERROR: block not passed to match_block!'
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
# if options[:check_for_fails]
|
|
472
|
+
# cc 'NOTE: check for fails prior to match loop not necessary on UltraFlex'
|
|
473
|
+
# end
|
|
474
|
+
|
|
475
|
+
# ss 'WARNING: MATCH LOOP FOR ULTRAFLEX STILL UNDER DEVELOPMENT'
|
|
476
|
+
|
|
477
|
+
# Create BlockArgs objects in order to receive multiple blocks
|
|
478
|
+
match_conditions = Origen::Utility::BlockArgs.new
|
|
479
|
+
fail_conditions = Origen::Utility::BlockArgs.new
|
|
480
|
+
|
|
481
|
+
# yield object to calling routine to get populated with blocks
|
|
482
|
+
if block.arity > 0
|
|
483
|
+
yield match_conditions, fail_conditions
|
|
484
|
+
else
|
|
485
|
+
# for backwards compatibility with Origen core call to match_block
|
|
486
|
+
match_conditions.add(&block)
|
|
487
|
+
fail_conditions.add(&block)
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
if options[:check_for_fails]
|
|
491
|
+
if options[:multiple_entries]
|
|
492
|
+
@match_entries.times do |i|
|
|
493
|
+
microcode "global subr match_done_#{i}:"
|
|
494
|
+
set_code(i + 100)
|
|
495
|
+
cycle(microcode: 'jump call_tester') unless i == @match_entries - 1
|
|
496
|
+
end
|
|
497
|
+
microcode 'call_tester:'
|
|
498
|
+
else
|
|
499
|
+
set_code(100)
|
|
500
|
+
end
|
|
501
|
+
cc 'Wait for any prior failures to propagate through the pipeline'
|
|
502
|
+
cycle(microcode: 'pipe_minus 1')
|
|
503
|
+
cc 'Now handshake with the tester to bin out and parts that have failed before they got here'
|
|
504
|
+
handshake(manual_stop: options[:manual_stop])
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
# Now do the main match loop
|
|
508
|
+
cc 'Start the match loop'
|
|
509
|
+
|
|
510
|
+
cycle # (:microcode => "set_msb #{counter_msb}") # set_msb microcode will be set below after counting match loop cycles
|
|
511
|
+
set_msb_vector = last_vector # remember the vector with set_msb opcode
|
|
512
|
+
|
|
513
|
+
cycle(microcode: 'branch_expr = (fail)')
|
|
514
|
+
|
|
515
|
+
global_opt = (options[:global_loops]) ? 'global ' : ''
|
|
516
|
+
microcode "#{global_opt}match_loop_#{@unique_counter}:"
|
|
517
|
+
|
|
518
|
+
cycle # (:microcode => "set c0 #{counter_lsb}")
|
|
519
|
+
set_c0_vector = last_vector # remember the vector with set_c0 opcode
|
|
520
|
+
|
|
521
|
+
microcode "match_result_loop_#{@unique_counter}:"
|
|
522
|
+
cycle(microcode: 'loop c0')
|
|
523
|
+
|
|
524
|
+
# count cycles in match loop block passed to help with meeting
|
|
525
|
+
# desired timeout value (have to back assign microcodes above)
|
|
526
|
+
prematch_cycle_count = cycle_count
|
|
527
|
+
match_conditions.each_with_index do |condition, i|
|
|
528
|
+
mask_fails(true)
|
|
529
|
+
condition.call # match condition
|
|
530
|
+
mask_fails(false)
|
|
531
|
+
|
|
532
|
+
cc ' Wait for the result to propagate through the pipeline'
|
|
533
|
+
cycle(microcode: 'pipe_minus 1')
|
|
534
|
+
inc_cycle_count(@pipeline_depth - 1) # Account for pipeline depth
|
|
535
|
+
cc "Branch if block condition #{i} not yet met"
|
|
536
|
+
cycle(microcode: "if (branch_expr) jump block_#{i}_notyet_matched_#{@unique_counter}")
|
|
537
|
+
cc 'Match found'
|
|
538
|
+
cycle(microcode: 'pop_loop')
|
|
539
|
+
if options[:on_block_match_goto]
|
|
540
|
+
if options[:on_block_match_goto].is_a?(Hash)
|
|
541
|
+
if options[:on_block_match_goto][i]
|
|
542
|
+
custom_jump = options[:on_block_match_goto][i]
|
|
543
|
+
else
|
|
544
|
+
custom_jump = nil
|
|
545
|
+
end
|
|
546
|
+
else
|
|
547
|
+
custom_jump = options[:on_block_match_goto]
|
|
548
|
+
end
|
|
549
|
+
end
|
|
550
|
+
if custom_jump
|
|
551
|
+
cycle(microcode: "jump #{custom_jump}")
|
|
552
|
+
else
|
|
553
|
+
cycle(microcode: "jump match_loop_end_#{@unique_counter}")
|
|
554
|
+
end
|
|
555
|
+
cc 'Match not yet found'
|
|
556
|
+
cycle(microcode: "block_#{i}_notyet_matched_#{@unique_counter}:")
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
match_conditions_cycle_count = cycle_count - prematch_cycle_count
|
|
560
|
+
cc "Match loop cycle count = #{match_conditions_cycle_count}"
|
|
561
|
+
|
|
562
|
+
# reduce timeout requested by match loop cycle count
|
|
563
|
+
timeout = (timeout.to_f / match_conditions_cycle_count).ceil
|
|
564
|
+
|
|
565
|
+
# Calculate the counter values appropriately hit the timeout requested
|
|
566
|
+
match_delay_cycles = false
|
|
567
|
+
|
|
568
|
+
# Determine full value of counter0
|
|
569
|
+
counter_value = timeout.to_f.floor
|
|
570
|
+
|
|
571
|
+
if counter_value < (2**@counter_lsb_bits)
|
|
572
|
+
# small value, don't need msb temp register
|
|
573
|
+
counter_msb = 1
|
|
574
|
+
counter_lsb = counter_value
|
|
575
|
+
elsif counter_value < (2**(@counter_lsb_bits + @counter_msb_bits))
|
|
576
|
+
# larger value, but smaller than counter maximum
|
|
577
|
+
counter_msb = counter_value # set MSB (lowest LSB bits get ignored)
|
|
578
|
+
counter_lsb = counter_value & (2**@counter_lsb_bits - 1) # set LSB
|
|
579
|
+
elsif counter_value < (2**(@counter_lsb_bits + @counter_msb_bits)) * @max_repeat_loop
|
|
580
|
+
# larger value, greater than counter, so add time delay per instance of loop to avoid using second counter
|
|
581
|
+
match_delay_cycles = (counter_value.to_f / (2**(@counter_lsb_bits + @counter_msb_bits))).ceil
|
|
582
|
+
counter_msb = (counter_value / match_delay_cycles).floor # set MSB (lowest LSB bits get ignored)
|
|
583
|
+
counter_lsb = counter_msb & (2**@counter_lsb_bits - 1) # set LSB
|
|
584
|
+
else
|
|
585
|
+
abort 'ERROR: timeout value too large in tester match method!'
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
# retroactively modify the counters based on cycles in match loop conditions
|
|
589
|
+
set_msb_vector.microcode = "set_msb #{counter_msb}"
|
|
590
|
+
set_c0_vector.microcode = "set c0 #{counter_lsb}"
|
|
591
|
+
|
|
592
|
+
if match_delay_cycles
|
|
593
|
+
cc 'Delay to meet timeout value'
|
|
594
|
+
cycle(repeat: match_delay_cycles) if match_delay_cycles
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
cycle(microcode: "end_loop match_result_loop_#{@unique_counter}")
|
|
598
|
+
|
|
599
|
+
if options[:force_fail_on_timeout]
|
|
600
|
+
cc 'To get here something has gone wrong, check blocks again to force a pattern failure'
|
|
601
|
+
fail_conditions.each do |condition|
|
|
602
|
+
cycle(microcode: 'pipe_minus 1')
|
|
603
|
+
condition.call
|
|
604
|
+
end
|
|
605
|
+
end
|
|
606
|
+
if options[:on_timeout_goto]
|
|
607
|
+
cycle(microcode: "jump #{options[:on_timeout_goto]}")
|
|
608
|
+
else
|
|
609
|
+
cycle(microcode: "jump match_loop_end_#{@unique_counter}")
|
|
610
|
+
end
|
|
611
|
+
cycle(microcode: "match_loop_end_#{@unique_counter}:")
|
|
612
|
+
|
|
613
|
+
@unique_counter += 1 # Increment so a different label will be applied if another
|
|
614
|
+
# handshake is called in the same pattern
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
# Handshake with the tester.
|
|
618
|
+
#
|
|
619
|
+
# Will set a cpu flag (A) and wait for it to be cleared by the tester, optionally
|
|
620
|
+
# pass in a read code to pass information to the tester.
|
|
621
|
+
#
|
|
622
|
+
# ==== Examples
|
|
623
|
+
# $tester.handshake # Pass control to the tester for a measurement
|
|
624
|
+
# $tester.handshake(:readcode => 10) # Trigger a specific action by the tester
|
|
625
|
+
def handshake(options = {})
|
|
626
|
+
options = {
|
|
627
|
+
readcode: false,
|
|
628
|
+
manual_stop: false, # set a 2nd CPU flag in case 1st flag is automatically cleared
|
|
629
|
+
}.merge(options)
|
|
630
|
+
if options[:readcode]
|
|
631
|
+
set_code(options[:readcode])
|
|
632
|
+
end
|
|
633
|
+
if options[:manual_stop]
|
|
634
|
+
cycle(microcode: "#{@microcode[:enable]} (#{@flags[1]})")
|
|
635
|
+
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[0]} #{@flags[1]})")
|
|
636
|
+
else
|
|
637
|
+
cycle(microcode: "#{@microcode[:enable]} (#{@flags[0]})")
|
|
638
|
+
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[0]})")
|
|
639
|
+
end
|
|
640
|
+
cycle(microcode: "loop_here_#{@unique_counter}: if (branch_expr) jump loop_here_#{@unique_counter}")
|
|
641
|
+
|
|
642
|
+
@unique_counter += 1 # Increment so a different label will be applied if another
|
|
643
|
+
# handshake is called in the same pattern
|
|
644
|
+
end
|
|
645
|
+
|
|
646
|
+
def keep_alive(options = {})
|
|
647
|
+
if options[:subroutine_pat]
|
|
648
|
+
cycle(microcode: 'clr_subr')
|
|
649
|
+
cycle(microcode: "#{@microcode[:enable]} (#{@flags[3]})")
|
|
650
|
+
cycle(microcode: "#{@microcode[:set_flag]} (#{@flags[3]})")
|
|
651
|
+
cycle(microcode: "loop_here_#{@unique_counter}: if (branch_expr) jump loop_here_#{@unique_counter}")
|
|
652
|
+
cycle
|
|
653
|
+
@unique_counter += 1 # Increment so a different label will be applied if another
|
|
654
|
+
else
|
|
655
|
+
$tester.cycle
|
|
656
|
+
call_subroutine('keep_alive')
|
|
657
|
+
end
|
|
658
|
+
end
|
|
659
|
+
|
|
660
|
+
# Capture a vector to the tester HRAM.
|
|
661
|
+
#
|
|
662
|
+
# This method applys a store vector (stv) opcode to the previous vector, note that is does
|
|
663
|
+
# not actually generate a new vector.
|
|
664
|
+
#
|
|
665
|
+
# Sometimes when generating vectors within a loop you may want to apply a stv opcode
|
|
666
|
+
# retrospectively to a previous vector, passing in an offset option will allow you
|
|
667
|
+
# to do this.
|
|
668
|
+
#
|
|
669
|
+
# On J750 the pins argument is ignored since the tester only supports whole vector capture.
|
|
670
|
+
#
|
|
671
|
+
# @example
|
|
672
|
+
# $tester.cycle # This is the vector you want to capture
|
|
673
|
+
# $tester.store # This applys the STV opcode
|
|
674
|
+
#
|
|
675
|
+
# $tester.cycle # This one gets stored
|
|
676
|
+
# $tester.cycle
|
|
677
|
+
# $tester.cycle
|
|
678
|
+
# $tester.store(:offset => -2) # Just realized I need to capture that earlier vector
|
|
679
|
+
def store(*pins)
|
|
680
|
+
options = pins.last.is_a?(Hash) ? pins.pop : {}
|
|
681
|
+
options = { offset: 0,
|
|
682
|
+
opcode: 'stv'
|
|
683
|
+
}.merge(options)
|
|
684
|
+
pins = pins.flatten.compact
|
|
685
|
+
if pins.empty?
|
|
686
|
+
fail 'For the UltraFLEX you must supply the pins to store/capture'
|
|
687
|
+
end
|
|
688
|
+
|
|
689
|
+
capt_style = options[:capture_style].nil? ? @capture_style : options[:capture_style]
|
|
690
|
+
if capt_style == :digcap
|
|
691
|
+
capt_microcode = dssc_store(pins, options)
|
|
692
|
+
else
|
|
693
|
+
capt_microcode = options[:opcode]
|
|
694
|
+
end
|
|
695
|
+
|
|
696
|
+
pins.each do |pin|
|
|
697
|
+
pin.restore_state do
|
|
698
|
+
pin.capture
|
|
699
|
+
update_vector_pin_val pin, offset: options[:offset]
|
|
700
|
+
last_vector(options[:offset]).dont_compress = true
|
|
701
|
+
end
|
|
702
|
+
end
|
|
703
|
+
update_vector microcode: capt_microcode, offset: options[:offset]
|
|
704
|
+
end
|
|
705
|
+
alias_method :to_hram, :store
|
|
706
|
+
alias_method :capture, :store
|
|
707
|
+
|
|
708
|
+
# use digcap to store, called by tester.store()
|
|
709
|
+
def dssc_store(pins, options)
|
|
710
|
+
repeat_count = last_vector(options[:offset]).repeat
|
|
711
|
+
capt_microcode = []
|
|
712
|
+
pins.each do |pin|
|
|
713
|
+
if @capture_history[pin.name].nil?
|
|
714
|
+
@capture_history[pin.name] = { is_digcap: true, count: repeat_count }
|
|
715
|
+
else
|
|
716
|
+
@capture_history[pin.name][:count] += repeat_count
|
|
717
|
+
end
|
|
718
|
+
capt_microcode << "((#{pin.name}):DigCap = Store)"
|
|
719
|
+
end
|
|
720
|
+
capt_microcode << 'stv'
|
|
721
|
+
capt_microcode.join(',')
|
|
722
|
+
end
|
|
723
|
+
|
|
724
|
+
def reload_counters(name)
|
|
725
|
+
microcode "reload #{name}"
|
|
726
|
+
end
|
|
727
|
+
|
|
728
|
+
def set_msb(integer)
|
|
729
|
+
microcode "set_msb #{integer}"
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
# Capture the next vector generated to HRAM
|
|
733
|
+
#
|
|
734
|
+
# This method applies a store vector (stv) opcode to the next vector to be generated,
|
|
735
|
+
# note that is does not actually generate a new vector.
|
|
736
|
+
#
|
|
737
|
+
# pin argument must be provided so that 'V' (valid) state can be applied to the pin
|
|
738
|
+
# if not already.
|
|
739
|
+
#
|
|
740
|
+
# @example
|
|
741
|
+
# $tester.store_next_cycle
|
|
742
|
+
# $tester.cycle # This is the vector that will be captured
|
|
743
|
+
def store_next_cycle(*pins)
|
|
744
|
+
options = pins.last.is_a?(Hash) ? pins.pop : {}
|
|
745
|
+
options = {
|
|
746
|
+
opcode: 'stv'
|
|
747
|
+
}.merge(options)
|
|
748
|
+
pins = pins.flatten.compact
|
|
749
|
+
if pins.empty?
|
|
750
|
+
fail 'For the UltraFLEX you must supply the pins to store/capture'
|
|
751
|
+
end
|
|
752
|
+
|
|
753
|
+
capt_style = options[:capture_style].nil? ? @capture_style : options[:capture_style]
|
|
754
|
+
if capt_style == :digcap
|
|
755
|
+
capt_microcode = []
|
|
756
|
+
repeat_count = options[:repeat].nil? ? 1 : options[:repeat]
|
|
757
|
+
pins.each do |pin|
|
|
758
|
+
if @capture_history[pin.name].nil?
|
|
759
|
+
@capture_history[pin.name] = { is_digcap: true, count: repeat_count }
|
|
760
|
+
else
|
|
761
|
+
@capture_history[pin.name][:count] += repeat_count
|
|
762
|
+
end
|
|
763
|
+
capt_microcode << "((#{pin.name}):DigCap = Store)"
|
|
764
|
+
end
|
|
765
|
+
capt_microcode << 'stv'
|
|
766
|
+
capt_microcode = capt_microcode.join(',')
|
|
767
|
+
else
|
|
768
|
+
capt_microcode = options[:opcode]
|
|
769
|
+
end
|
|
770
|
+
|
|
771
|
+
pins.each { |pin| pin.save; pin.capture }
|
|
772
|
+
# Register this clean up function to be run after the next vector
|
|
773
|
+
# is generated (SMcG: cool or what! DH: Yes, very cool!)
|
|
774
|
+
preset_next_vector(microcode: capt_microcode) do
|
|
775
|
+
pins.each(&:restore)
|
|
776
|
+
end
|
|
777
|
+
end
|
|
778
|
+
alias_method :store!, :store_next_cycle
|
|
779
|
+
|
|
780
|
+
# ate_hardware stores "key" UltraFLEX hardware information needed for test program generation
|
|
781
|
+
# Instrument types available for ppmu: "HSD-M", "HSD-U", "HSD-4G", and "HSS-6G".
|
|
782
|
+
# Sample usage: $tester.ate_hardware("HSD-U").ppmu
|
|
783
|
+
# Instrument types available for supply: "VSM", "VSMx2", "VSMx4", "HexVS", "HexVSx2", "HexVSx4",
|
|
784
|
+
# "HexVSx6", "HexVS+x2", "HexVS+x4", "HexVS+x6", "HDVS1", "HDVS1x2", "HDVS1x4", "VHDVS",
|
|
785
|
+
# "VHDVS_HC", "VHDVSx2", "VHDVS_HCx2", "VHDVS_HCx4", "VHDVS_HCx8", "VHDVS+", "VHDVS_HC+",
|
|
786
|
+
# "VHDVS+x2", "VHDVS_HC+x2", "VHDVS_HC+x4", and "VHDVS_HC+x8".
|
|
787
|
+
# HDVS1 is also known as HDVS. VHDVS is also known as UVS256.
|
|
788
|
+
# x2 is Merged2, x4 is Merged4, x6 is Merged6. _HC is High-Current.
|
|
789
|
+
# + is High-Accuracy.
|
|
790
|
+
# Sample usage: $tester.ate_hardware("VSM").supply
|
|
791
|
+
# Sample usage: $tester.ate_hardware("HSD-M").ppmu
|
|
792
|
+
def ate_hardware(instrumentname = '')
|
|
793
|
+
@ate_hardware = ATEHardware.new(instrumentname)
|
|
794
|
+
end
|
|
795
|
+
end
|
|
796
|
+
end
|
|
797
|
+
UltraFLEX = IGXLBasedTester::UltraFLEX
|
|
798
|
+
end
|