origen_testers 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/config/application.rb +140 -0
- data/config/commands.rb +73 -0
- data/config/development.rb +12 -0
- data/config/environment.rb +1 -0
- data/config/shared_commands.rb +47 -0
- data/config/users.rb +18 -0
- data/config/version.rb +8 -0
- data/lib/commands/build.rb +69 -0
- data/lib/origen_testers.rb +23 -0
- data/lib/origen_testers/api.rb +258 -0
- data/lib/origen_testers/basic_test_setups.rb +105 -0
- data/lib/origen_testers/callback_handlers.rb +58 -0
- data/lib/origen_testers/generator.rb +279 -0
- data/lib/origen_testers/generator/flow_control_api.rb +611 -0
- data/lib/origen_testers/generator/identity_map.rb +23 -0
- data/lib/origen_testers/generator/placeholder.rb +11 -0
- data/lib/origen_testers/generator/test_numberer.rb +23 -0
- data/lib/origen_testers/igxl_based_tester.rb +12 -0
- data/lib/origen_testers/igxl_based_tester/base.rb +641 -0
- data/lib/origen_testers/igxl_based_tester/base/flow.rb +171 -0
- data/lib/origen_testers/igxl_based_tester/base/flow_line.rb +322 -0
- data/lib/origen_testers/igxl_based_tester/base/generator.rb +217 -0
- data/lib/origen_testers/igxl_based_tester/base/patgroup.rb +109 -0
- data/lib/origen_testers/igxl_based_tester/base/patgroups.rb +38 -0
- data/lib/origen_testers/igxl_based_tester/base/patset.rb +68 -0
- data/lib/origen_testers/igxl_based_tester/base/patset_pattern.rb +56 -0
- data/lib/origen_testers/igxl_based_tester/base/patsets.rb +38 -0
- data/lib/origen_testers/igxl_based_tester/base/patsubr.rb +68 -0
- data/lib/origen_testers/igxl_based_tester/base/patsubr_pattern.rb +56 -0
- data/lib/origen_testers/igxl_based_tester/base/patsubrs.rb +38 -0
- data/lib/origen_testers/igxl_based_tester/base/test_instance.rb +326 -0
- data/lib/origen_testers/igxl_based_tester/base/test_instance_group.rb +58 -0
- data/lib/origen_testers/igxl_based_tester/base/test_instances.rb +179 -0
- data/lib/origen_testers/igxl_based_tester/files.rb +43 -0
- data/lib/origen_testers/igxl_based_tester/j750.rb +248 -0
- data/lib/origen_testers/igxl_based_tester/j750/flow.rb +10 -0
- data/lib/origen_testers/igxl_based_tester/j750/flow_line.rb +19 -0
- data/lib/origen_testers/igxl_based_tester/j750/generator.rb +19 -0
- data/lib/origen_testers/igxl_based_tester/j750/patgroup.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750/patgroups.rb +10 -0
- data/lib/origen_testers/igxl_based_tester/j750/patset.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750/patset_pattern.rb +18 -0
- data/lib/origen_testers/igxl_based_tester/j750/patsets.rb +10 -0
- data/lib/origen_testers/igxl_based_tester/j750/patsubr.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750/patsubr_pattern.rb +18 -0
- data/lib/origen_testers/igxl_based_tester/j750/patsubrs.rb +10 -0
- data/lib/origen_testers/igxl_based_tester/j750/templates/flow.txt.erb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750/templates/instances.txt.erb +16 -0
- data/lib/origen_testers/igxl_based_tester/j750/templates/patgroups.txt.erb +8 -0
- data/lib/origen_testers/igxl_based_tester/j750/templates/patsets.txt.erb +10 -0
- data/lib/origen_testers/igxl_based_tester/j750/templates/patsubrs.txt.erb +10 -0
- data/lib/origen_testers/igxl_based_tester/j750/test_instance.rb +547 -0
- data/lib/origen_testers/igxl_based_tester/j750/test_instance_group.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750/test_instances.rb +10 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt.rb +34 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/flow.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/flow_line.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/generator.rb +19 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patgroup.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patgroups.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patset.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patset_pattern.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patsets.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patsubr.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patsubr_pattern.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patsubrs.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/test_instance.rb +515 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/test_instance_group.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/test_instances.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/parser.rb +102 -0
- data/lib/origen_testers/igxl_based_tester/parser/ac_spec.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/parser/ac_specs.rb +0 -0
- data/lib/origen_testers/igxl_based_tester/parser/dc_spec.rb +33 -0
- data/lib/origen_testers/igxl_based_tester/parser/dc_specs.rb +48 -0
- data/lib/origen_testers/igxl_based_tester/parser/descriptions.rb +339 -0
- data/lib/origen_testers/igxl_based_tester/parser/flow.rb +109 -0
- data/lib/origen_testers/igxl_based_tester/parser/flow_line.rb +203 -0
- data/lib/origen_testers/igxl_based_tester/parser/flows.rb +21 -0
- data/lib/origen_testers/igxl_based_tester/parser/pattern_set.rb +92 -0
- data/lib/origen_testers/igxl_based_tester/parser/pattern_sets.rb +31 -0
- data/lib/origen_testers/igxl_based_tester/parser/test_instance.rb +341 -0
- data/lib/origen_testers/igxl_based_tester/parser/test_instances.rb +24 -0
- data/lib/origen_testers/igxl_based_tester/parser/timeset.rb +13 -0
- data/lib/origen_testers/igxl_based_tester/parser/timesets.rb +0 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex.rb +477 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/flow.rb +10 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/flow_line.rb +19 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/generator.rb +19 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/patgroup.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/patgroups.rb +10 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/patset.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/patset_pattern.rb +18 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/patsets.rb +10 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/patsubr.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/patsubr_pattern.rb +18 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/patsubrs.rb +10 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/flow.txt.erb +9 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/instances.txt.erb +16 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/patgroups.txt.erb +9 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/patsets.txt.erb +10 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/patsubrs.txt.erb +10 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/test_instance.rb +270 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/test_instance_group.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/test_instances.rb +10 -0
- data/lib/origen_testers/interface.rb +183 -0
- data/lib/origen_testers/parser.rb +22 -0
- data/lib/origen_testers/parser/description_lookup.rb +62 -0
- data/lib/origen_testers/parser/searchable_array.rb +30 -0
- data/lib/origen_testers/parser/searchable_hash.rb +30 -0
- data/lib/origen_testers/pattern_compilers.rb +116 -0
- data/lib/origen_testers/pattern_compilers/assembler.rb +88 -0
- data/lib/origen_testers/pattern_compilers/job.rb +96 -0
- data/lib/origen_testers/pattern_compilers/ultraflex_pattern_compiler.rb +599 -0
- data/lib/origen_testers/program_generators.rb +55 -0
- data/lib/origen_testers/smartest_based_tester.rb +8 -0
- data/lib/origen_testers/smartest_based_tester/base.rb +411 -0
- data/lib/origen_testers/smartest_based_tester/base/flow.rb +188 -0
- data/lib/origen_testers/smartest_based_tester/base/flow_node.rb +476 -0
- data/lib/origen_testers/smartest_based_tester/base/generator.rb +123 -0
- data/lib/origen_testers/smartest_based_tester/base/pattern_compiler.rb +23 -0
- data/lib/origen_testers/smartest_based_tester/base/pattern_master.rb +47 -0
- data/lib/origen_testers/smartest_based_tester/base/test_method.rb +143 -0
- data/lib/origen_testers/smartest_based_tester/base/test_methods.rb +73 -0
- data/lib/origen_testers/smartest_based_tester/base/test_methods/ac_tml.rb +33 -0
- data/lib/origen_testers/smartest_based_tester/base/test_methods/base_tml.rb +38 -0
- data/lib/origen_testers/smartest_based_tester/base/test_methods/custom_tml.rb +19 -0
- data/lib/origen_testers/smartest_based_tester/base/test_methods/dc_tml.rb +147 -0
- data/lib/origen_testers/smartest_based_tester/base/test_methods/limits.rb +43 -0
- data/lib/origen_testers/smartest_based_tester/base/test_suite.rb +166 -0
- data/lib/origen_testers/smartest_based_tester/base/test_suites.rb +58 -0
- data/lib/origen_testers/smartest_based_tester/v93k.rb +8 -0
- data/lib/origen_testers/smartest_based_tester/v93k/builder.rb +89 -0
- data/lib/origen_testers/smartest_based_tester/v93k/builder/flow.rb +169 -0
- data/lib/origen_testers/smartest_based_tester/v93k/builder/pattern_master.rb +54 -0
- data/lib/origen_testers/smartest_based_tester/v93k/flow.rb +10 -0
- data/lib/origen_testers/smartest_based_tester/v93k/flow_node.rb +9 -0
- data/lib/origen_testers/smartest_based_tester/v93k/generator.rb +19 -0
- data/lib/origen_testers/smartest_based_tester/v93k/pattern_compiler.rb +10 -0
- data/lib/origen_testers/smartest_based_tester/v93k/pattern_master.rb +10 -0
- data/lib/origen_testers/smartest_based_tester/v93k/templates/template.aiv.erb +17 -0
- data/lib/origen_testers/smartest_based_tester/v93k/templates/template.flow.erb +201 -0
- data/lib/origen_testers/smartest_based_tester/v93k/templates/template.pmfl.erb +13 -0
- data/lib/origen_testers/smartest_based_tester/v93k/test_method.rb +9 -0
- data/lib/origen_testers/smartest_based_tester/v93k/test_methods.rb +9 -0
- data/lib/origen_testers/smartest_based_tester/v93k/test_suite.rb +9 -0
- data/lib/origen_testers/smartest_based_tester/v93k/test_suites.rb +9 -0
- data/lib/origen_testers/test/basic_interface.rb +17 -0
- data/lib/origen_testers/test/block.rb +21 -0
- data/lib/origen_testers/test/dut.rb +184 -0
- data/lib/origen_testers/test/dut2.rb +76 -0
- data/lib/origen_testers/test/j750_base_interface.rb +119 -0
- data/lib/origen_testers/test/j750_hpt_interface.rb +8 -0
- data/lib/origen_testers/test/j750_interface.rb +8 -0
- data/lib/origen_testers/test/nvm.rb +94 -0
- data/lib/origen_testers/test/ultraflex_interface.rb +110 -0
- data/lib/origen_testers/test/v93k_interface.rb +115 -0
- data/lib/origen_testers/timing.rb +362 -0
- data/lib/origen_testers/vector.rb +203 -0
- data/lib/origen_testers/vector_based_tester.rb +42 -0
- data/lib/origen_testers/vector_generator.rb +623 -0
- data/lib/origen_testers/vector_pipeline.rb +288 -0
- data/pattern/dc_instr.rb +7 -0
- data/pattern/delay.rb +7 -0
- data/pattern/mem_test.rb +8 -0
- data/pattern/multi_vector.rb +117 -0
- data/pattern/multi_vector_plus1.rb +125 -0
- data/pattern/nvm/j750/add_late_pins.rb +3 -0
- data/pattern/nvm/j750/iterator_postfix_test_x_bx.rb +8 -0
- data/pattern/nvm/j750/iterator_test_x_bx.rb +8 -0
- data/pattern/nvm/j750/j750_halt.rb +159 -0
- data/pattern/nvm/j750/j750_workout.rb +202 -0
- data/pattern/nvm/j750/timing.rb +73 -0
- data/pattern/nvm/v93k/v93k_workout.rb +136 -0
- data/pattern/read_write_reg.rb +58 -0
- data/pattern/reset.rb +4 -0
- data/pattern/subroutines.rb +38 -0
- data/program/_additional_erase.rb +7 -0
- data/program/_efa_resources.rb +7 -0
- data/program/_erase.rb +25 -0
- data/program/_erase_vfy.rb +5 -0
- data/program/_iv_resources.rb +10 -0
- data/program/basic_interface.rb +5 -0
- data/program/components/_prb2_main.rb +6 -0
- data/program/flow_control.rb +164 -0
- data/program/prb1.rb +226 -0
- data/program/prb1_resources.rb +28 -0
- data/program/prb2.rb +40 -0
- data/program/test.rb +20 -0
- data/templates/example.txt.erb +53 -0
- data/templates/j750/_vt_flow.txt.erb +8 -0
- data/templates/j750/_vt_instances.txt.erb +4 -0
- data/templates/j750/program_sheet.txt.erb +9 -0
- data/templates/manifest/v93k.yaml.erb +22 -0
- data/templates/web/index.md.erb +51 -0
- data/templates/web/layouts/_basic.html.erb +15 -0
- data/templates/web/partials/_navbar.html.erb +22 -0
- data/templates/web/release_notes.md.erb +5 -0
- metadata +332 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
module OrigenTesters
|
|
2
|
+
# A simple class to model a vector
|
|
3
|
+
class Vector
|
|
4
|
+
attr_accessor :repeat, :microcode, :timeset, :pin_vals,
|
|
5
|
+
:number, :cycle_number, :dont_compress,
|
|
6
|
+
:comments, :inline_comment, :cycle, :number
|
|
7
|
+
|
|
8
|
+
def initialize(attrs = {})
|
|
9
|
+
@inline_comment = ''
|
|
10
|
+
attrs.each do |attribute, value|
|
|
11
|
+
send("#{attribute}=", value)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def comments
|
|
16
|
+
@comments ||= []
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def update(attrs = {})
|
|
20
|
+
attrs.each do |attribute, value|
|
|
21
|
+
send("#{attribute}=", value)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Returns the value (a string) that is assigned to the given pin by the
|
|
26
|
+
# given vector
|
|
27
|
+
#
|
|
28
|
+
# vector.pin_vals # => "1 1 XX10 H X1"
|
|
29
|
+
# vector.pin_value($dut.pins(:jtag)) # => "XX10"
|
|
30
|
+
def pin_value(pin)
|
|
31
|
+
$tester.regex_for_pin(pin).match(pin_vals)
|
|
32
|
+
Regexp.last_match(1)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Replace the current pin value assigned to the given pin with either the state
|
|
36
|
+
# that it currently has, or with a supplied string value.
|
|
37
|
+
#
|
|
38
|
+
# In the case of a string being supplied as the 2nd argument, the caller is
|
|
39
|
+
# responsible for ensuring that the pin state format/codes matches that used
|
|
40
|
+
# by the current tester.
|
|
41
|
+
#
|
|
42
|
+
# vector.pin_vals # => "1 1 XX10 H X1"
|
|
43
|
+
# $dut.pins(:jtag).drive(0)
|
|
44
|
+
# vector.set_pin_value($dut.pins(:jtag))
|
|
45
|
+
# vector.pin_vals # => "1 1 0000 H X1"
|
|
46
|
+
# vector.set_pin_value($dut.pins(:jtag), "XXXX")
|
|
47
|
+
# vector.pin_vals # => "1 1 XXXX H X1"
|
|
48
|
+
def set_pin_value(pin, value = nil)
|
|
49
|
+
regex = $tester.regex_for_pin_sub(pin)
|
|
50
|
+
value ||= pin.to_vector
|
|
51
|
+
if $tester.ordered_pins_cache.first == pin
|
|
52
|
+
self.pin_vals = pin_vals.sub(regex, value + '\2')
|
|
53
|
+
elsif $tester.ordered_pins_cache.last == pin
|
|
54
|
+
self.pin_vals = pin_vals.sub(regex, '\1' + value)
|
|
55
|
+
else
|
|
56
|
+
self.pin_vals = pin_vals.sub(regex, '\1' + value + '\3')
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Converts the vector to the period specified by the given timeset (instead of the period
|
|
61
|
+
# for the timeset it was originally created with).
|
|
62
|
+
#
|
|
63
|
+
# This may convert the single vector to multiple vectors, in which case the method will
|
|
64
|
+
# yield as many vectors as required back to the caller.
|
|
65
|
+
def convert_to_timeset(tset)
|
|
66
|
+
# If no conversion required
|
|
67
|
+
if tset.period_in_ns == timeset.period_in_ns
|
|
68
|
+
yield self
|
|
69
|
+
else
|
|
70
|
+
if tset.period_in_ns > timeset.period_in_ns
|
|
71
|
+
fail "Cannot convert a vector with timeset #{timeset.name} to timeset #{tset.name}!"
|
|
72
|
+
end
|
|
73
|
+
if timeset.period_in_ns % tset.period_in_ns != 0
|
|
74
|
+
fail "The period of timeset #{timeset.name} is not a multiple of the period of timeset #{tset.name}!"
|
|
75
|
+
end
|
|
76
|
+
if $tester.timing_toggled_pins.empty?
|
|
77
|
+
vector_modification_required = false
|
|
78
|
+
else
|
|
79
|
+
# If the timing toggled pins are not driving on this vector, then no
|
|
80
|
+
# modification will be required
|
|
81
|
+
vector_modification_required = $tester.timing_toggled_pins.any? do |pin|
|
|
82
|
+
value = pin_value(pin)
|
|
83
|
+
value == '1' || value == '0'
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
number_of_base_vectors = repeat || 1
|
|
87
|
+
vectors_per_period = timeset.period_in_ns / tset.period_in_ns
|
|
88
|
+
self.inline_comment += "Period levelled (#{timeset.name})"
|
|
89
|
+
self.timeset = tset
|
|
90
|
+
if vector_modification_required && vectors_per_period > 1
|
|
91
|
+
pin_values = $tester.timing_toggled_pins.map do |pin|
|
|
92
|
+
on = pin_value(pin)
|
|
93
|
+
if on == '1'
|
|
94
|
+
{ pin: pin, on: '1', off: '0' }
|
|
95
|
+
elsif on == '0'
|
|
96
|
+
{ pin: pin, on: '0', off: '1' }
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
pin_vals_with_compare = nil
|
|
100
|
+
number_of_base_vectors.times do |i|
|
|
101
|
+
# Drive the 'on' value on the first cycle, this is already setup
|
|
102
|
+
v = dup
|
|
103
|
+
v.repeat = 1
|
|
104
|
+
v.pin_vals = inhibit_compares
|
|
105
|
+
yield v
|
|
106
|
+
# Then drive the pin 'off' value for the remainder
|
|
107
|
+
v = dup
|
|
108
|
+
r = vectors_per_period - 1
|
|
109
|
+
if r > 1
|
|
110
|
+
v = dup
|
|
111
|
+
v.repeat = r - 1
|
|
112
|
+
pin_values.each { |vals| v.set_pin_value(vals[:pin], vals[:off]) if vals }
|
|
113
|
+
yield v
|
|
114
|
+
end
|
|
115
|
+
v = dup
|
|
116
|
+
v.repeat = 1
|
|
117
|
+
v.pin_vals = restore_compares
|
|
118
|
+
pin_values.each { |vals| v.set_pin_value(vals[:pin], vals[:off]) if vals }
|
|
119
|
+
yield v
|
|
120
|
+
end
|
|
121
|
+
else
|
|
122
|
+
self.repeat = number_of_base_vectors * vectors_per_period
|
|
123
|
+
yield self
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Set all active compare data to X.
|
|
129
|
+
# The original values will be preserved so that they can be restored
|
|
130
|
+
# vector.pin_vals # => "1 1 LHLL 10001 L 1 XX 0"
|
|
131
|
+
# vector.inhibit_compares # => "1 1 XXXX 10001 X 1 XX 0"
|
|
132
|
+
# vector.restore_compares # => "1 1 LHLL 10001 L 1 XX 0"
|
|
133
|
+
def inhibit_compares
|
|
134
|
+
@orig_pin_vals = pin_vals
|
|
135
|
+
@pin_vals = pin_vals.gsub(/H|L/, 'X')
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# @see Vector#inhibit_compares
|
|
139
|
+
def restore_compares
|
|
140
|
+
@pin_vals = @orig_pin_vals
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Updates the pin values to reflect the value currently held by the given pin
|
|
144
|
+
def update_pin_val(pin)
|
|
145
|
+
vals = pin_vals.split(' ')
|
|
146
|
+
if pin.belongs_to_a_pin_group? && !pin.is_a?(Origen::Pins::PinCollection)
|
|
147
|
+
port = nil
|
|
148
|
+
pin.groups.each { |i| port = i[1] if port.nil? && Origen.tester.ordered_pins.include?(i[1]) } # see if group is included in ordered pins
|
|
149
|
+
if port
|
|
150
|
+
ix = Origen.tester.ordered_pins.index(port) # find index of port
|
|
151
|
+
i = port.index(pin)
|
|
152
|
+
else
|
|
153
|
+
ix = Origen.tester.ordered_pins.index(pin)
|
|
154
|
+
i = 0
|
|
155
|
+
end
|
|
156
|
+
else
|
|
157
|
+
ix = Origen.tester.ordered_pins.index(pin)
|
|
158
|
+
i = 0
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
if Origen.pin_bank.pin_groups.keys.include? pin.id
|
|
162
|
+
val = pin.map { |p| Origen.tester.format_pin_state(p) }.join('')
|
|
163
|
+
vals[ix] = val
|
|
164
|
+
else
|
|
165
|
+
val = Origen.tester.format_pin_state(pin)
|
|
166
|
+
vals[ix][i] = val
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
self.pin_vals = vals.join(' ')
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def ordered_pins
|
|
173
|
+
Origen.app.pin_map.sort_by { |id, pin| pin.order }.map { |id, pin| pin }
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def microcode=(val)
|
|
177
|
+
if val && has_microcode? && @microcode != val
|
|
178
|
+
fail "Trying to assign microcode: #{val}, but vector already has microcode: #{@microcode}"
|
|
179
|
+
else
|
|
180
|
+
@microcode = val
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Since repeat 0 is non-intuitive every vector implicitly has a repeat of 1
|
|
185
|
+
def repeat
|
|
186
|
+
@repeat || 1
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def has_microcode?
|
|
190
|
+
!!(@microcode && !@microcode.empty?)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def ==(obj)
|
|
194
|
+
if obj.is_a?(Vector)
|
|
195
|
+
self.has_microcode? == obj.has_microcode? &&
|
|
196
|
+
timeset == obj.timeset &&
|
|
197
|
+
pin_vals == obj.pin_vals
|
|
198
|
+
else
|
|
199
|
+
super obj
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require 'active_support/concern'
|
|
2
|
+
module OrigenTesters
|
|
3
|
+
# Including this module in a class gives it all the basics required
|
|
4
|
+
# to generator vector-based test patterns
|
|
5
|
+
module VectorBasedTester
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
require 'origen_testers/vector_generator'
|
|
9
|
+
require 'origen_testers/timing'
|
|
10
|
+
require 'origen_testers/api'
|
|
11
|
+
|
|
12
|
+
include VectorGenerator
|
|
13
|
+
include Timing
|
|
14
|
+
include API
|
|
15
|
+
|
|
16
|
+
included do
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
module ClassMethods # :nodoc:
|
|
20
|
+
# This overrides the new method of any class which includes this
|
|
21
|
+
# module to force the newly created instance to be registered as
|
|
22
|
+
# a tester with Origen
|
|
23
|
+
def new(*args, &block) # :nodoc:
|
|
24
|
+
if Origen.app.with_doc_tester?
|
|
25
|
+
x = Origen::Tester::Doc.allocate
|
|
26
|
+
if Origen.app.with_html_doc_tester?
|
|
27
|
+
x.html_mode = true
|
|
28
|
+
end
|
|
29
|
+
else
|
|
30
|
+
x = allocate
|
|
31
|
+
end
|
|
32
|
+
x.send(:initialize, *args, &block)
|
|
33
|
+
x.register_tester
|
|
34
|
+
x
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def register_tester # :nodoc:
|
|
39
|
+
Origen.app.tester = self
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
require 'active_support/concern'
|
|
2
|
+
module OrigenTesters
|
|
3
|
+
module VectorGenerator
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
require 'erb'
|
|
7
|
+
|
|
8
|
+
included do
|
|
9
|
+
# When set to true vector and cycle number comments will be appended to pattern vectors.
|
|
10
|
+
# This can also be enabled by running the generate command with the '-v' switch.
|
|
11
|
+
attr_accessor :vector_comments
|
|
12
|
+
attr_accessor :compress
|
|
13
|
+
attr_accessor :expand_repeats
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def vector_group_size
|
|
17
|
+
@vector_group_size || 1
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def vector_group_size=(number)
|
|
21
|
+
if number > 1 && number.odd?
|
|
22
|
+
fail 'Only even numbers can be supplied for the vector_group_size!'
|
|
23
|
+
end
|
|
24
|
+
# Each pattern should run with its own tester instance, but just in case
|
|
25
|
+
@pipeline = nil
|
|
26
|
+
@vector_group_size = number
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def with_vector_group_size(number)
|
|
30
|
+
orig = vector_group_size
|
|
31
|
+
self.vector_group_size = number
|
|
32
|
+
yield
|
|
33
|
+
self.vector_group_size = orig
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Duplicate the last vector as required until aligned with the start of the
|
|
37
|
+
# next vector group
|
|
38
|
+
def align
|
|
39
|
+
stage.store :align
|
|
40
|
+
end
|
|
41
|
+
alias_method :align_to_first, :align
|
|
42
|
+
|
|
43
|
+
# Duplicate the last vector as required until aligned to the last vector of the
|
|
44
|
+
# current vector group
|
|
45
|
+
def align_to_last
|
|
46
|
+
stage.store :align_last
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Returns an array of pin IDs that are currently inhibited (will not
|
|
50
|
+
# be included when vectors are generated)
|
|
51
|
+
def inhibited_pins
|
|
52
|
+
@inhibited_pins ||= []
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# init vector count when first accessed, otherwise return value
|
|
56
|
+
def vec_count
|
|
57
|
+
@vec_count ||= 0
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# increment vector count
|
|
61
|
+
def inc_vec_count(num = 1)
|
|
62
|
+
vec_count if @vec_count.nil? # define if not already
|
|
63
|
+
@vec_count = @vec_count + num
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# decrement vector count
|
|
67
|
+
def dec_vec_count(num = 1)
|
|
68
|
+
vec_count if @vec_count.nil? # define if not already
|
|
69
|
+
@vec_count = @vec_count - num
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# init cycle count when first accessed, otherwise return value
|
|
73
|
+
def cycle_count
|
|
74
|
+
@cycle_count ||= 0
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# increment cycle count
|
|
78
|
+
def inc_cycle_count(num = 1)
|
|
79
|
+
cycle_count if @cycle_count.nil? # define if not already
|
|
80
|
+
@cycle_count = @cycle_count + num
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# reset_cycle_count
|
|
84
|
+
def reset_cycle_count(num = 0)
|
|
85
|
+
cycle_count if @cycle_count.nil? # define if not already
|
|
86
|
+
@cycle_count = num
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Call to prevent the given pins from appearing in the generated vectors.
|
|
90
|
+
#
|
|
91
|
+
# This is a convenient way to inhibit something like a J750 mux pin from
|
|
92
|
+
# appearing in the patterns when generating the pattern for a different
|
|
93
|
+
# platform.
|
|
94
|
+
#
|
|
95
|
+
# When used this
|
|
96
|
+
# method must be called before the first vector is generated - it will not be retrospectively
|
|
97
|
+
# applied to existing vectors.
|
|
98
|
+
def inhibit_pin(*pins)
|
|
99
|
+
pins.each do |pin|
|
|
100
|
+
pin = $dut.pin(pin) if pin.is_a?(Symbol)
|
|
101
|
+
inhibited_pins << pin
|
|
102
|
+
end
|
|
103
|
+
inhibited_pins.uniq!
|
|
104
|
+
inhibited_pins.compact!
|
|
105
|
+
inhibited_pins
|
|
106
|
+
end
|
|
107
|
+
alias_method :inhibit_pins, :inhibit_pin
|
|
108
|
+
|
|
109
|
+
# Render content directly into a pattern, any options will be passed to the template
|
|
110
|
+
def render(template, options = {})
|
|
111
|
+
# Record the current file, this can be used to resolve any relative path
|
|
112
|
+
# references in the file about to be compiled
|
|
113
|
+
Origen.file_handler.current_file = template
|
|
114
|
+
# Ran into crosstalk problems when rendering ERB templates recursively, setting eoutvar based
|
|
115
|
+
# on the name of the file will causes each template to be rendered into its own 'bank'.
|
|
116
|
+
# Not sure why the final gsub is needed but seems to fail to parse correctly otherwise.
|
|
117
|
+
eoutvar = Pathname.new(template).basename('.*').basename('.*').to_s.gsub('-', '_')
|
|
118
|
+
# Make the file name available to the template
|
|
119
|
+
Origen.generator.compiler.options[:file] = template
|
|
120
|
+
options.each { |k, v| Origen.generator.compiler.options[k] = v }
|
|
121
|
+
code = Origen.generator.compiler.insert(ERB.new(File.read(template.to_s), 0, Origen.config.erb_trim_mode, eoutvar).result)
|
|
122
|
+
code.strip!
|
|
123
|
+
push_microcode code
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# If the tester defines a method named template this method will compile
|
|
127
|
+
# whatever template file is returned by that method.
|
|
128
|
+
#
|
|
129
|
+
# This method is called automatically after the body section of a Pattern.create
|
|
130
|
+
# operation has completed.
|
|
131
|
+
def render_template
|
|
132
|
+
_render(:template)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Same as the render method, except the template method should be called body_template.
|
|
136
|
+
def render_body
|
|
137
|
+
_render(:body_template)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# If the tester defines a method named footer_template this method will compile
|
|
141
|
+
# whatever template file is returned by that method.
|
|
142
|
+
#
|
|
143
|
+
# This method is called automatically during the footer section of a Pattern.create
|
|
144
|
+
# operation.
|
|
145
|
+
def render_footer
|
|
146
|
+
_render(:footer_template)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# If the tester defines a method named header_template this method will compile
|
|
150
|
+
# whatever template file is returned by that method.
|
|
151
|
+
#
|
|
152
|
+
# This method is called automatically during the header section of a Pattern.create
|
|
153
|
+
# operation.
|
|
154
|
+
def render_header
|
|
155
|
+
_render(:header_template)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def _render(method) # :nodoc:
|
|
159
|
+
if self.respond_to?(method)
|
|
160
|
+
template = send(method)
|
|
161
|
+
# Record the current file, this can be used to resolve any relative path
|
|
162
|
+
# references in the file about to be compiled
|
|
163
|
+
Origen.file_handler.current_file = template
|
|
164
|
+
# Ran into crosstalk problems when rendering ERB templates recursively, setting eoutvar based
|
|
165
|
+
# on the name of the file will causes each template to be rendered into its own 'bank'.
|
|
166
|
+
# Not sure why the final gsub is needed but seems to fail to parse correctly otherwise.
|
|
167
|
+
eoutvar = Pathname.new(template).basename('.*').basename('.*').to_s.gsub('-', '_')
|
|
168
|
+
# Make the file name available to the template
|
|
169
|
+
Origen.generator.compiler.options[:file] = template
|
|
170
|
+
push_microcode Origen.generator.compiler.insert(ERB.new(File.read(template.to_s), 0, Origen.config.erb_trim_mode, eoutvar).result)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def stage
|
|
175
|
+
Origen.generator.stage
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def push_comment(msg)
|
|
179
|
+
# Comments are stored verbatim for now, can't see much use for a dedicated comment object
|
|
180
|
+
stage.store msg unless @inhibit_comments
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def microcode(code, options = {})
|
|
184
|
+
unless @inhibit_vectors
|
|
185
|
+
if options[:offset] && options[:offset] != 0
|
|
186
|
+
stage.insert_from_end code, options[:offset]
|
|
187
|
+
else
|
|
188
|
+
stage.store code
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
alias_method :push_microcode, :microcode
|
|
193
|
+
|
|
194
|
+
def last_vector(offset = 0)
|
|
195
|
+
stage.last_vector(offset)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def last_object(offset = 0)
|
|
199
|
+
stage.last_object(offset)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Allows the attributes for the next vector to be setup prior
|
|
203
|
+
# to generating it.
|
|
204
|
+
#
|
|
205
|
+
# A block can be optionally supplied to act as a clean up method,
|
|
206
|
+
# that is the block will be saved and executed after the next
|
|
207
|
+
# cycle has been generated.
|
|
208
|
+
#
|
|
209
|
+
# See the V93K store_next_cycle method for an example of using
|
|
210
|
+
# this.
|
|
211
|
+
def preset_next_vector(attrs = {}, &block)
|
|
212
|
+
@preset_next_vector = attrs
|
|
213
|
+
@preset_next_vector_cleanup = block
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# Called by every $tester.cycle command to push a vector to the stage object
|
|
217
|
+
def push_vector(attrs = {})
|
|
218
|
+
attrs = {
|
|
219
|
+
dont_compress: @dont_compress
|
|
220
|
+
}.merge(attrs)
|
|
221
|
+
unless @inhibit_vectors
|
|
222
|
+
if @preset_next_vector
|
|
223
|
+
attrs = @preset_next_vector.merge(attrs) do |key, preset, current|
|
|
224
|
+
if preset && current && current != ''
|
|
225
|
+
fail "Value for #{key} set by preset_next_vector clashed with the next vector!"
|
|
226
|
+
else
|
|
227
|
+
preset || current
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
@preset_next_vector = nil
|
|
231
|
+
end
|
|
232
|
+
stage.store Vector.new(attrs)
|
|
233
|
+
inc_vec_count
|
|
234
|
+
inc_cycle_count(attrs[:repeat] || 1)
|
|
235
|
+
if @preset_next_vector_cleanup
|
|
236
|
+
@preset_next_vector_cleanup.call
|
|
237
|
+
@preset_next_vector_cleanup = nil
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
alias_method :vector, :push_vector
|
|
242
|
+
|
|
243
|
+
def update_vector(attrs = {})
|
|
244
|
+
unless @inhibit_vectors
|
|
245
|
+
offset = (attrs.delete(:offset) || 0).abs
|
|
246
|
+
stage.last_vector(offset).update(attrs)
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def update_vector_pin_val(pin, options = {})
|
|
251
|
+
unless @inhibit_vectors
|
|
252
|
+
offset = (options.delete(:offset) || 0).abs
|
|
253
|
+
stage.last_vector(offset).update_pin_val(pin)
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Adds the given microcode to the last vector if possible. If not possible (meaning the
|
|
258
|
+
# vector already contains microcode) then a new cycle will be added with the given
|
|
259
|
+
# microcode.
|
|
260
|
+
def add_microcode_to_last_or_cycle(code)
|
|
261
|
+
cycle if !stage.last_vector || stage.last_vector.has_microcode?
|
|
262
|
+
stage.last_vector.update(microcode: code)
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Final pass of a generator vector array which returns lines suitable for writing to the
|
|
266
|
+
# output file. This gives the tester model a chance to concatenate repeats and any other
|
|
267
|
+
# last optimization/formatting changes it wishes to make.
|
|
268
|
+
#
|
|
269
|
+
# At this point vector array contains a combination of non-vector lines and uncompressed
|
|
270
|
+
# Vector objects (vector lines)
|
|
271
|
+
#
|
|
272
|
+
def format(vector_array, section)
|
|
273
|
+
# Go through vector_array and print out both
|
|
274
|
+
# vectors and non-vectors to pattern (via 'yield line')
|
|
275
|
+
vector_array.each do |vec|
|
|
276
|
+
# skip here important for the ways delays are currently handled
|
|
277
|
+
# TODO: This seems like an upstream bug that should be investigated, why is such
|
|
278
|
+
# a vector even generated?
|
|
279
|
+
if vec.is_a?(String)
|
|
280
|
+
if vec.strip[0] == comment_char
|
|
281
|
+
pipeline.push_comment(vec)
|
|
282
|
+
else
|
|
283
|
+
pipeline.push_microcode(vec)
|
|
284
|
+
end
|
|
285
|
+
else
|
|
286
|
+
next if vec.respond_to?(:repeat) && vec.repeat == 0 # skip vectors with repeat of 0!
|
|
287
|
+
pipeline << vec
|
|
288
|
+
end
|
|
289
|
+
pipeline.flush do |vector|
|
|
290
|
+
expand_vector(vector) do |line|
|
|
291
|
+
yield line
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
# now flush buffer if there is still a vector
|
|
296
|
+
pipeline.empty(min_vectors: section == :footer ? @min_pattern_vectors : nil) do |vector|
|
|
297
|
+
expand_vector(vector) do |line|
|
|
298
|
+
yield line
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# Tester models can overwrite this if they wish to inject any additional pattern lines
|
|
304
|
+
# at final pattern dump time
|
|
305
|
+
def before_write_pattern_line(line)
|
|
306
|
+
[line]
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def pipeline
|
|
310
|
+
@pipeline ||= VectorPipeline.new(vector_group_size)
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def dont_compress
|
|
314
|
+
if block_given?
|
|
315
|
+
orig = @dont_compress
|
|
316
|
+
@dont_compress = true
|
|
317
|
+
yield
|
|
318
|
+
@dont_compress = orig
|
|
319
|
+
else
|
|
320
|
+
@dont_compress
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def dont_compress=(val)
|
|
325
|
+
@dont_compress = val
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# expands (uncompresses to pattern) vector if desired or leaves it as is
|
|
329
|
+
# allows for tracking and formatting of vector
|
|
330
|
+
# if comment then return without modification
|
|
331
|
+
def expand_vector(vec)
|
|
332
|
+
if vec.is_a?(Vector)
|
|
333
|
+
if expand_repeats
|
|
334
|
+
vec.repeat.times do
|
|
335
|
+
vec.repeat = 1
|
|
336
|
+
yield track_and_format_vector(vec)
|
|
337
|
+
end
|
|
338
|
+
else
|
|
339
|
+
yield track_and_format_vector(vec)
|
|
340
|
+
end
|
|
341
|
+
else
|
|
342
|
+
yield vec # Return comments without modification
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
# Update tracking info (stats object) and allow for
|
|
347
|
+
# any additional formatting via format_vector
|
|
348
|
+
# method if overridden
|
|
349
|
+
def track_and_format_vector(vec)
|
|
350
|
+
unless vec.timeset
|
|
351
|
+
puts 'No timeset defined!'
|
|
352
|
+
puts 'Add one to your top level startup method or target like this:'
|
|
353
|
+
puts '$tester.set_timeset("nvmbist", 40) # Where 40 is the period in ns'
|
|
354
|
+
exit 1
|
|
355
|
+
end
|
|
356
|
+
stats = Origen.app.stats
|
|
357
|
+
stats.add_vector
|
|
358
|
+
if vector_group_size > 1 && vec.repeat > 1
|
|
359
|
+
stats.add_cycle(1)
|
|
360
|
+
stats.add_cycle((vec.repeat - 1) * vector_group_size)
|
|
361
|
+
stats.add_time_in_ns(vec.timeset.period_in_ns)
|
|
362
|
+
stats.add_time_in_ns((vec.repeat - 1) * vector_group_size * vec.timeset.period_in_ns)
|
|
363
|
+
else
|
|
364
|
+
stats.add_cycle(vec.repeat)
|
|
365
|
+
stats.add_time_in_ns(vec.repeat * vec.timeset.period_in_ns)
|
|
366
|
+
end
|
|
367
|
+
format_vector(vec)
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def format_vector(vec)
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
def pingroup_map
|
|
374
|
+
Origen.app.pingroup_map
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
# Cache any pin ordering for later use since all vectors should be formatted the same
|
|
378
|
+
def ordered_pins_cache(options = {})
|
|
379
|
+
@ordered_pins_cache ||= ordered_pins(options)
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def ordered_pins(options = {})
|
|
383
|
+
options = {
|
|
384
|
+
include_inhibited_pins: false,
|
|
385
|
+
include_pingroups: true
|
|
386
|
+
}.merge(options)
|
|
387
|
+
|
|
388
|
+
pinorder = Origen.app.pin_pattern_order.dup
|
|
389
|
+
pinexclude = Origen.app.pin_pattern_exclude.dup
|
|
390
|
+
pinids = []
|
|
391
|
+
|
|
392
|
+
if Origen.app.pin_pattern_order.last.is_a?(Hash)
|
|
393
|
+
options.merge!(pinorder.pop)
|
|
394
|
+
end
|
|
395
|
+
if Origen.app.pin_pattern_exclude.last.is_a?(Hash)
|
|
396
|
+
options.merge!(pinexclude.pop)
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
ordered_pins = []
|
|
400
|
+
|
|
401
|
+
# add bit here that puts pingroup id into ordered pins array and deletes included pins
|
|
402
|
+
pins = Origen.pin_bank.pins.dup
|
|
403
|
+
pingroups = Origen.pin_bank.pin_groups.dup
|
|
404
|
+
|
|
405
|
+
if pinorder && pinorder.size > 0
|
|
406
|
+
pinorder.each do |id|
|
|
407
|
+
if Origen.pin_bank.pin_groups.keys.include? id
|
|
408
|
+
# see if group is already in ordered_pins
|
|
409
|
+
fail "Pin group #{id} is duplicately defined in pin_pattern_order" unless pingroups.include? id
|
|
410
|
+
# see if any pins in group are already in pin_order
|
|
411
|
+
used = []
|
|
412
|
+
pingroups[id].each do |pin|
|
|
413
|
+
pinorder.each { |pin| pinids << Origen.pin_bank.find(pin).id if Origen.pin_bank.find(pin) }
|
|
414
|
+
used << pin if pinids.include?(pin.id) # see if pin included in pinids
|
|
415
|
+
end
|
|
416
|
+
if !used.empty?
|
|
417
|
+
pingroups[id].each { |pin| ordered_pins << pin unless used.include?(pin) }
|
|
418
|
+
else
|
|
419
|
+
# this is a pin group, add pin_group and delete all pins in group
|
|
420
|
+
ordered_pins << pingroups[id]
|
|
421
|
+
pingroups[id].each do |pin|
|
|
422
|
+
fail "Pin (#{pin.name}) in group (#{id}) is duplicately defined in pin_pattern_order" unless pins.include? pin.id
|
|
423
|
+
pins.delete(pin.id)
|
|
424
|
+
end
|
|
425
|
+
end
|
|
426
|
+
pingroups.delete(id)
|
|
427
|
+
else # this is a pin
|
|
428
|
+
pin = Origen.pin_bank.find(id)
|
|
429
|
+
fail "Undefined pin (#{id}) added to pin_pattern_order" unless pin
|
|
430
|
+
ordered_pins << pin
|
|
431
|
+
pin.name = id
|
|
432
|
+
fail "Individual pin (#{pin.name}) is duplicately defined in pin_pattern_order" unless pins.include? pin.id
|
|
433
|
+
pins.delete(pin.id)
|
|
434
|
+
end
|
|
435
|
+
end
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
if pinexclude && pinexclude.size > 0
|
|
439
|
+
pinexclude.each do |id|
|
|
440
|
+
if Origen.pin_bank.pin_groups.keys.include? id
|
|
441
|
+
# see if group is already in ordered_pins
|
|
442
|
+
fail "Pin group #{id} is defined both in pin_pattern_order and pin_pattern_exclude" unless pingroups.include? id
|
|
443
|
+
# this is a pin group, delete all pins in group
|
|
444
|
+
pingroups[id].each do |pin|
|
|
445
|
+
fail "Pin (#{pin.name}) in group (#{id}) is defined both in pin_pattern_order and pin_pattern_exclude" unless pins.include? pin.id
|
|
446
|
+
pins.delete(pin.id)
|
|
447
|
+
end
|
|
448
|
+
else # this is a pin, delete the pin
|
|
449
|
+
pin = Origen.pin_bank.find(id)
|
|
450
|
+
fail "Undefined pin (#{id}) added to pin_pattern_exclude" unless pin
|
|
451
|
+
fail "Pin #{pin.name} is defined both in pin_pattern_order and pin_pattern_exclude" unless pins.include? pin.id
|
|
452
|
+
pin.name = id
|
|
453
|
+
pins.delete(pin.id)
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
unless options[:only]
|
|
459
|
+
# all the rest of the pins to the end of the pattern order
|
|
460
|
+
pins.each do |id, pin|
|
|
461
|
+
# check for port
|
|
462
|
+
if pin.belongs_to_a_pin_group?
|
|
463
|
+
if id =~ /(\D+)\d+$/
|
|
464
|
+
name = Regexp.last_match[1]
|
|
465
|
+
port = nil
|
|
466
|
+
pin.groups.each do |group|
|
|
467
|
+
if group[0] == name.to_sym # belongs to a port
|
|
468
|
+
port = group[1]
|
|
469
|
+
end
|
|
470
|
+
end
|
|
471
|
+
if pingroups.include?(port.id)
|
|
472
|
+
ordered_pins << port
|
|
473
|
+
port.each { |pin| pins.delete(pin.id) }
|
|
474
|
+
end
|
|
475
|
+
else
|
|
476
|
+
ordered_pins << pin
|
|
477
|
+
end
|
|
478
|
+
else
|
|
479
|
+
ordered_pins << pin
|
|
480
|
+
end
|
|
481
|
+
end
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
ordered_pins.map do |pin|
|
|
485
|
+
if options[:include_inhibited_pins]
|
|
486
|
+
pin
|
|
487
|
+
else
|
|
488
|
+
inhibited_pins.include?(pin) ? nil : pin
|
|
489
|
+
end
|
|
490
|
+
end.compact
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
def current_pin_vals
|
|
494
|
+
ordered_pins_cache.map(&:to_vector).join(' ')
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
# Returns a regular expression that can be used to get the value
|
|
498
|
+
# of the given pin within the string returned by current_pin_vals.
|
|
499
|
+
# str = $tester.current_pin_vals # => "1 1 XX10 H X1"
|
|
500
|
+
# regex = $tester.regex_for_pin($dut.pins(:jtag)) # => /\w{1} \w{1} (\w{4}) \w{1} \w{2}/
|
|
501
|
+
# regex.match(str)
|
|
502
|
+
# Regexp.last_match(1) # => "XX10"
|
|
503
|
+
#
|
|
504
|
+
# @see Vector#pin_value
|
|
505
|
+
def regex_for_pin(pin)
|
|
506
|
+
@regex_for_pins ||= {}
|
|
507
|
+
# Cache this as potentially called many times during pattern generation
|
|
508
|
+
@regex_for_pins[pin] ||= begin
|
|
509
|
+
regex = '/'
|
|
510
|
+
ordered_pins_cache.each do |p|
|
|
511
|
+
if pin == p
|
|
512
|
+
regex += "(\\w{#{p.size}}) "
|
|
513
|
+
else
|
|
514
|
+
regex += "\\w{#{p.size}} "
|
|
515
|
+
end
|
|
516
|
+
end
|
|
517
|
+
eval(regex.strip + '/')
|
|
518
|
+
end
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
# Returns a regular expression that can be used to change the value
|
|
522
|
+
# of the given pin within the string returned by current_pin_vals.
|
|
523
|
+
# str = $tester.current_pin_vals # => "1 1 XX10 H X1"
|
|
524
|
+
# regex = $tester.regex_for_pin_sub($dut.pins(:jtag)) # => /(\w{1} \w{1} )(\w{4})( \w{1} \w{2})/
|
|
525
|
+
# str.sub(regex, '\1LLLL\3') # => "1 1 LLLL H X1"
|
|
526
|
+
#
|
|
527
|
+
# @see Vector#set_pin_value
|
|
528
|
+
def regex_for_pin_sub(pin)
|
|
529
|
+
@regex_for_pin_subs ||= {}
|
|
530
|
+
# Cache this as potentially called many times during pattern generation
|
|
531
|
+
@regex_for_pin_subs[pin] ||= begin
|
|
532
|
+
regex = '/'
|
|
533
|
+
first_pin_done = false
|
|
534
|
+
match_pin_done = false
|
|
535
|
+
ordered_pins_cache.each do |p|
|
|
536
|
+
if pin == p
|
|
537
|
+
regex += ')' if first_pin_done
|
|
538
|
+
regex += "(\\w{#{p.size}})( "
|
|
539
|
+
else
|
|
540
|
+
regex += '(' unless first_pin_done
|
|
541
|
+
regex += "\\w{#{p.size}} "
|
|
542
|
+
end
|
|
543
|
+
first_pin_done = true
|
|
544
|
+
end
|
|
545
|
+
regex.strip!
|
|
546
|
+
if regex[-1] == '('
|
|
547
|
+
regex.chop!
|
|
548
|
+
else
|
|
549
|
+
regex += ')'
|
|
550
|
+
end
|
|
551
|
+
eval(regex + '/')
|
|
552
|
+
end
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
def get_pingroup(pin)
|
|
556
|
+
pingroup_map.each do |id, pins|
|
|
557
|
+
return id if pins.include? pin
|
|
558
|
+
end
|
|
559
|
+
nil
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
def update_pin_from_formatted_state(pin, state)
|
|
563
|
+
if state == @repeat_previous || state == '-'
|
|
564
|
+
pin.repeat_previous = true
|
|
565
|
+
elsif state == @drive_very_hi_state || state == '2'
|
|
566
|
+
pin.drive_very_hi
|
|
567
|
+
elsif state == @drive_hi_state || state == '1'
|
|
568
|
+
pin.drive_hi
|
|
569
|
+
elsif state == @drive_lo_state || state == '0'
|
|
570
|
+
pin.drive_lo
|
|
571
|
+
elsif state == @expect_hi_state || state == 'H'
|
|
572
|
+
pin.expect_hi
|
|
573
|
+
elsif state == @expect_lo_state || state == 'L'
|
|
574
|
+
pin.expect_lo
|
|
575
|
+
elsif state == @expect_mid_state || state == 'M'
|
|
576
|
+
pin.expect_mid
|
|
577
|
+
elsif state == @drive_mem_state || state == 'D'
|
|
578
|
+
pin.drive_mem
|
|
579
|
+
elsif state == @expect_mem_state || state == 'E'
|
|
580
|
+
pin.expect_mem
|
|
581
|
+
elsif state == @capture_state || state == 'C'
|
|
582
|
+
pin.capture
|
|
583
|
+
elsif state == @dont_care_state || state == 'X'
|
|
584
|
+
pin.dont_care
|
|
585
|
+
else
|
|
586
|
+
fail "Unknown pin state: #{state}"
|
|
587
|
+
end
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
# @see Origen::Pins::Pin#to_vector
|
|
591
|
+
def format_pin_state(pin)
|
|
592
|
+
if pin.repeat_previous? && @support_repeat_previous
|
|
593
|
+
@repeat_previous || '-'
|
|
594
|
+
elsif pin.driving?
|
|
595
|
+
if pin.value == 1
|
|
596
|
+
if pin.high_voltage?
|
|
597
|
+
@drive_very_hi_state || '2'
|
|
598
|
+
else
|
|
599
|
+
@drive_hi_state || '1'
|
|
600
|
+
end
|
|
601
|
+
else
|
|
602
|
+
@drive_lo_state || '0'
|
|
603
|
+
end
|
|
604
|
+
elsif pin.comparing_midband?
|
|
605
|
+
@expect_mid_state || 'M'
|
|
606
|
+
elsif pin.comparing?
|
|
607
|
+
if pin.value == 1
|
|
608
|
+
@expect_hi_state || 'H'
|
|
609
|
+
else
|
|
610
|
+
@expect_lo_state || 'L'
|
|
611
|
+
end
|
|
612
|
+
elsif pin.driving_mem?
|
|
613
|
+
@drive_mem_state || 'D'
|
|
614
|
+
elsif pin.comparing_mem?
|
|
615
|
+
@expect_mem_state || 'E'
|
|
616
|
+
elsif pin.to_be_captured?
|
|
617
|
+
@capture_state || 'C'
|
|
618
|
+
else
|
|
619
|
+
@dont_care_state || 'X'
|
|
620
|
+
end
|
|
621
|
+
end
|
|
622
|
+
end
|
|
623
|
+
end
|