origen 0.28.2 → 0.29.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/bin/origen +14 -2
  3. data/config/version.rb +2 -2
  4. data/lib/origen.rb +72 -45
  5. data/lib/origen/application.rb +29 -19
  6. data/lib/origen/application/deployer.rb +3 -1
  7. data/lib/origen/application/runner.rb +10 -8
  8. data/lib/origen/chip_mode.rb +1 -1
  9. data/lib/origen/commands.rb +24 -12
  10. data/lib/origen/commands/version.rb +1 -1
  11. data/lib/origen/commands_global.rb +32 -8
  12. data/lib/origen/core_ext.rb +1 -2
  13. data/lib/origen/core_ext/enumerable.rb +2 -2
  14. data/lib/origen/core_ext/integer.rb +85 -0
  15. data/lib/origen/core_ext/numeric.rb +28 -4
  16. data/lib/origen/global_app.rb +9 -0
  17. data/lib/origen/log.rb +1 -1
  18. data/lib/origen/model_initializer.rb +6 -1
  19. data/lib/origen/netlist/list.rb +2 -2
  20. data/lib/origen/org_file.rb +125 -0
  21. data/lib/origen/org_file/interceptable.rb +44 -0
  22. data/lib/origen/org_file/interceptor.rb +100 -0
  23. data/lib/origen/parameters/set.rb +1 -1
  24. data/lib/origen/pins.rb +4 -0
  25. data/lib/origen/pins/function_proxy.rb +8 -0
  26. data/lib/origen/pins/pin.rb +90 -38
  27. data/lib/origen/pins/pin_collection.rb +61 -21
  28. data/lib/origen/ports/port.rb +1 -1
  29. data/lib/origen/registers.rb +1 -1
  30. data/lib/origen/registers/reg.rb +1 -1
  31. data/lib/origen/remote_manager.rb +25 -15
  32. data/lib/origen/site_config.rb +140 -13
  33. data/lib/origen/specs/checkers.rb +2 -2
  34. data/lib/origen/sub_blocks.rb +6 -1
  35. data/lib/origen/value.rb +119 -0
  36. data/lib/origen/value/bin_str_val.rb +72 -0
  37. data/lib/origen/value/hex_str_val.rb +100 -0
  38. data/origen_site_config.yml +15 -8
  39. metadata +12 -6
  40. data/lib/origen/core_ext/bignum.rb +0 -38
  41. data/lib/origen/core_ext/fixnum.rb +0 -56
@@ -179,7 +179,7 @@ module Origen
179
179
  else
180
180
  results_hash["#{name}#{delimiter}#{k}"] = v
181
181
  if k == param_hash.keys.last
182
- name = nil
182
+ name = name.include?(delimiter) ? name.split(delimiter)[0..-2].join(delimiter) : nil
183
183
  end
184
184
  end
185
185
  end
@@ -227,8 +227,12 @@ module Origen
227
227
  name: ''
228
228
  }.merge(options)
229
229
 
230
+ rtl_name = options[:rtl_name]
231
+ force = options[:force]
230
232
  options.delete(:size).times do |i|
231
233
  options[:name] = "#{id}#{i}".to_sym
234
+ options[:rtl_name] = "#{rtl_name}#{i}".to_sym if rtl_name
235
+ options[:force] = force[i] if force
232
236
 
233
237
  if power_pin
234
238
  group[i] = PowerPin.new(i, self, options)
@@ -16,6 +16,14 @@ module Origen
16
16
  @pin
17
17
  end
18
18
 
19
+ # @api private
20
+ #
21
+ # To play nicely with == when a function proxy is wrapping a pin that is already
22
+ # wrapped by an OrgFile interceptor
23
+ def __object__
24
+ @pin.__object__
25
+ end
26
+
19
27
  # Intercept all calls to function-scoped attributes of the pin so
20
28
  # that we can inject the function that we want the attribute value for
21
29
  Pin::FUNCTION_SCOPED_ATTRIBUTES.each do |attribute|
@@ -2,6 +2,17 @@ module Origen
2
2
  module Pins
3
3
  class Pin
4
4
  include PinCommon
5
+ include OrgFile::Interceptable
6
+
7
+ # Don't include the ! method in here, the cycle will be captured at the tester level and
8
+ # it would cause a double cycle in the org file if also captured at the pin
9
+ ORG_FILE_INTERCEPTED_METHODS = [
10
+ :suspend, :resume, :repeat_previous=,
11
+ :drive_hi, :drive_hi, :drive_very_hi, :drive_lo, :drive_lo, :drive_mem, :expect_mem,
12
+ :assert_hi, :expect_hi, :compare_hi, :assert_lo, :expect_lo, :compare_lo, :dont_care,
13
+ :drive, :assert, :compare, :expect, :assert_midband, :compare_midband, :expect_midband,
14
+ :toggle, :capture, :store
15
+ ]
5
16
 
6
17
  # Any attributes listed here will be looked up for the current function defined
7
18
  # by the current mode and configuration context before falling back to a default
@@ -37,8 +48,10 @@ module Origen
37
48
  attr_accessor :ext_pulldown
38
49
  # Pin type, either :analog or :digital
39
50
  attr_accessor :type
40
- # Pin RTL name, short term solution for products that do not get full HDL path for pins
51
+ # Pin RTL name
41
52
  attr_accessor :rtl_name
53
+ # Value to be forced on the pin, e.g. during simulation
54
+ attr_accessor :force
42
55
 
43
56
  attr_accessor :description
44
57
  attr_accessor :notes
@@ -59,6 +72,7 @@ module Origen
59
72
  @direction = sanitize_direction(options[:direction])
60
73
  @invert = options[:invert]
61
74
  @reset = options[:reset]
75
+ @force = options[:force] & 1
62
76
  @id = id
63
77
  @name = options[:name]
64
78
  @rtl_name = options[:rtl_name]
@@ -75,11 +89,24 @@ module Origen
75
89
  @clock = nil
76
90
  @meta = options[:meta] || {}
77
91
  @dib_meta = options[:dib_meta] || {}
92
+ @_saved_state = []
93
+ @_saved_value = []
94
+ @_saved_suspend = []
95
+ @_saved_invert = []
96
+ @_saved_repeat_previous = []
78
97
  on_init(owner, options)
79
98
  # Assign the initial state from the method so that any inversion is picked up...
80
99
  send(@reset)
81
100
  end
82
101
 
102
+ def global_path_to
103
+ "dut.pins(:#{id})"
104
+ end
105
+
106
+ def org_file_intercepted_methods
107
+ ORG_FILE_INTERCEPTED_METHODS
108
+ end
109
+
83
110
  # Returns the drive cycle wave assigned to the pin based on the currently enabled timeset,
84
111
  # or nil if none is set.
85
112
  # Note that if a timeset is set then all pins will always return a wave as they will pick
@@ -90,7 +117,7 @@ module Origen
90
117
  # every cycle in some applications
91
118
  @drive_waves ||= {}
92
119
  @drive_waves[t.id] ||= {}
93
- @drive_waves[t.id][code] ||= dut.current_timeset.send(:wave_for, self, type: :drive, code: code)
120
+ @drive_waves[t.id][code] ||= dut.current_timeset.send(:wave_for, myself, type: :drive, code: code)
94
121
  end
95
122
  end
96
123
 
@@ -104,7 +131,15 @@ module Origen
104
131
  # every cycle in some applications
105
132
  @compare_waves ||= {}
106
133
  @compare_waves[t.id] ||= {}
107
- @compare_waves[t.id][code] ||= dut.current_timeset.send(:wave_for, self, type: :compare, code: code)
134
+ @compare_waves[t.id][code] ||= dut.current_timeset.send(:wave_for, myself, type: :compare, code: code)
135
+ end
136
+ end
137
+
138
+ def rtl_name
139
+ if primary_group
140
+ (@rtl_name || "#{primary_group.id}#{primary_group_index}").to_s
141
+ else
142
+ (@rtl_name || id).to_s
108
143
  end
109
144
  end
110
145
 
@@ -123,7 +158,7 @@ module Origen
123
158
  def hello
124
159
  drive_hi
125
160
  @@hello_pins ||= []
126
- @@hello_pins << self unless @@hello_pins.include?(self)
161
+ @@hello_pins << myself unless @@hello_pins.include?(myself)
127
162
  @@hello_loop ||= Thread.new do
128
163
  loop do
129
164
  @@hello_pins.each(&:toggle)
@@ -141,7 +176,7 @@ module Origen
141
176
 
142
177
  # See Pin#hello
143
178
  def goodbye
144
- @@hello_pins.delete(self)
179
+ @@hello_pins.delete(myself)
145
180
  puts "Pin #{name} has stopped toggling"
146
181
  end
147
182
 
@@ -244,7 +279,7 @@ module Origen
244
279
  # pin.expect_lo
245
280
  # pin.to_vector # => "L"
246
281
  def to_vector
247
- @vector_formatted_value ||= Origen.tester.format_pin_state(self)
282
+ @vector_formatted_value ||= Origen.tester.format_pin_state(myself)
248
283
  end
249
284
 
250
285
  # @api private
@@ -266,13 +301,13 @@ module Origen
266
301
  # pin.value # => 1
267
302
  def vector_formatted_value=(val)
268
303
  unless @vector_formatted_value == val
269
- Origen.tester.update_pin_from_formatted_state(self, val)
304
+ Origen.tester.update_pin_from_formatted_state(myself, val)
270
305
  @vector_formatted_value = val
271
306
  end
272
307
  end
273
308
 
274
309
  def inspect
275
- "<#{self.class}:#{object_id}>"
310
+ "<#{myself.class}:#{object_id}>"
276
311
  end
277
312
 
278
313
  def describe(options = {})
@@ -368,7 +403,7 @@ module Origen
368
403
  def groups
369
404
  # Origen.pin_bank.all_pin_groups.select do |name, group|
370
405
  @groups ||= Origen.pin_bank.pin_groups.select do |_name, group|
371
- group.include?(self)
406
+ group.include?(myself)
372
407
  end
373
408
  end
374
409
  alias_method :pin_groups, :groups
@@ -391,8 +426,8 @@ module Origen
391
426
  else
392
427
  packages.each do |package_id|
393
428
  package_id = package_id.respond_to?(:id) ? package_id.id : package_id
394
- self.packages[package_id] ||= {}
395
- self.packages[package_id][:location] = str
429
+ myself.packages[package_id] ||= {}
430
+ myself.packages[package_id][:location] = str
396
431
  add_alias str.to_s.symbolize, package: package_id, mode: :all, configuration: :all
397
432
  end
398
433
  end
@@ -412,9 +447,9 @@ module Origen
412
447
  else
413
448
  packages.each do |package_id|
414
449
  package_id = package_id.respond_to?(:id) ? package_id.id : package_id
415
- self.packages[package_id] ||= {}
416
- self.packages[package_id][:dib_assignment] ||= []
417
- self.packages[package_id][:dib_assignment][options[:site]] = str
450
+ myself.packages[package_id] ||= {}
451
+ myself.packages[package_id][:dib_assignment] ||= []
452
+ myself.packages[package_id][:dib_assignment][options[:site]] = str
418
453
  add_alias str.to_s.symbolize, package: package_id, mode: :all, configuration: :all
419
454
  end
420
455
  end
@@ -468,7 +503,7 @@ module Origen
468
503
  def add_function(id, options = {})
469
504
  id = id.to_sym
470
505
  add_function_attributes(options.merge(name: id, id: id.to_sym))
471
- f = FunctionProxy.new(id, self)
506
+ f = FunctionProxy.new(id, myself)
472
507
  add_alias id, packages: :all, obj: f
473
508
  end
474
509
 
@@ -510,7 +545,7 @@ module Origen
510
545
  # If the options contain a package, mode or configuration reference then the alias
511
546
  # will only work under that context.
512
547
  def add_alias(id, options = {})
513
- obj = options.delete(:obj) || self
548
+ obj = options.delete(:obj) || myself
514
549
  if aliases[id]
515
550
  aliases[id][:packages] += resolve_packages(options)
516
551
  aliases[id][:modes] += resolve_modes(options)
@@ -556,7 +591,7 @@ module Origen
556
591
  # Returns true if the pin is an alias of the given pin name
557
592
  def is_alias_of?(name)
558
593
  if Origen.pin_bank.find(name)
559
- Origen.pin_bank.find(name).id == Origen.pin_bank.find(self).id
594
+ Origen.pin_bank.find(name).id == Origen.pin_bank.find(myself).id
560
595
  else
561
596
  false
562
597
  end
@@ -610,18 +645,32 @@ module Origen
610
645
  end
611
646
 
612
647
  def set_value(val)
648
+ orig = val
613
649
  invalidate_vector_cache
614
650
  if val.is_a?(String) || val.is_a?(Symbol)
615
- @vector_formatted_value = val.to_s
651
+ val = val.to_s
652
+ if val =~ /^(b|h).+/
653
+ val = Origen::Value.new(val)
654
+ else
655
+ @vector_formatted_value = val
656
+ return
657
+ end
658
+ end
659
+ if val.is_a?(Origen::Value)
660
+ val = val[0]
616
661
  else
617
662
  # If val is a data bit extract the value of it
618
663
  val = val.respond_to?(:data) ? val.data : val
619
664
  # Assume driving/asserting a nil value means 0
620
665
  val = 0 unless val
621
- if val > 1
666
+ if !val.x_or_z? && val > 1
622
667
  fail "Attempt to set a value of #{val} on pin #{name}"
623
668
  end
624
- @repeat_previous = false
669
+ end
670
+ @repeat_previous = false
671
+ if val.x_or_z?
672
+ dont_care
673
+ else
625
674
  if inverted?
626
675
  @value = val == 0 ? 1 : 0
627
676
  else
@@ -719,9 +768,9 @@ module Origen
719
768
  # options = { :active => false #if active true means to take tester active load capability into account
720
769
  # }.merge(options)
721
770
  # unless state_to_be_inverted?
722
- # self.state = ($tester.active_loads || !options[:active]) ? $tester.pin_state(:expect_lo) : $tester.pin_state(:dont_care)
771
+ # myself.state = ($tester.active_loads || !options[:active]) ? $tester.pin_state(:expect_lo) : $tester.pin_state(:dont_care)
723
772
  # else
724
- # self.state = ($tester.active_loads || !options[:active]) ? $tester.pin_state(:expect_hi) : $tester.pin_state(:dont_care)
773
+ # myself.state = ($tester.active_loads || !options[:active]) ? $tester.pin_state(:expect_hi) : $tester.pin_state(:dont_care)
725
774
  # end
726
775
  end
727
776
  alias_method :expect_lo, :assert_lo
@@ -881,21 +930,24 @@ module Origen
881
930
  restore
882
931
  end
883
932
 
884
- def save # :nodoc:
885
- @_saved_state = @state
886
- @_saved_value = @value
887
- @_saved_suspend = @suspend
888
- @_saved_invert = @invert
889
- @_saved_repeat_previous = @repeat_previous
933
+ # Saves the current state of the pin, allowing it to be restored to the
934
+ # current state by calling the restore method
935
+ def save
936
+ @_saved_state << @state
937
+ @_saved_value << @value
938
+ @_saved_suspend << @suspend
939
+ @_saved_invert << @invert
940
+ @_saved_repeat_previous << @repeat_previous
890
941
  end
891
942
 
892
- def restore # :nodoc:
943
+ # Restores the state of the pin to the last time save was called
944
+ def restore
893
945
  invalidate_vector_cache
894
- @state = @_saved_state
895
- @value = @_saved_value
896
- @suspend = @_saved_suspend
897
- @invert = @_saved_invert
898
- @repeat_previous = @_saved_repeat_previous
946
+ @state = @_saved_state.pop
947
+ @value = @_saved_value.pop
948
+ @suspend = @_saved_suspend.pop
949
+ @invert = @_saved_invert.pop
950
+ @repeat_previous = @_saved_repeat_previous.pop
899
951
  end
900
952
 
901
953
  def is_not_a_clock?
@@ -911,7 +963,7 @@ module Origen
911
963
  end
912
964
 
913
965
  def enable_clock(options = {})
914
- @clock = PinClock.new(self, options)
966
+ @clock = PinClock.new(myself, options)
915
967
  end
916
968
 
917
969
  def disable_clock(options = {})
@@ -924,7 +976,7 @@ module Origen
924
976
  end
925
977
 
926
978
  def start_clock(options = {})
927
- enable_clock(options) if self.is_not_a_clock?
979
+ enable_clock(options) if myself.is_not_a_clock?
928
980
  @clock.start_clock(options)
929
981
  end
930
982
  alias_method :resume_clock, :start_clock
@@ -951,12 +1003,12 @@ module Origen
951
1003
  @clock.toggle
952
1004
  end
953
1005
 
954
- # Delete this pin (self). Used bang in method name to keep same for pins and
1006
+ # Delete this pin (myself). Used bang in method name to keep same for pins and
955
1007
  # pin collections. Pin collections already had a delete method which deletes
956
1008
  # a pin from the collection. Needed delete! to indicate it is deleting the
957
1009
  # actual pin or pin group calling the method.
958
1010
  def delete!
959
- owner.delete_pin(self)
1011
+ owner.delete_pin(myself)
960
1012
  end
961
1013
 
962
1014
  def type=(value)
@@ -5,6 +5,14 @@ module Origen
5
5
  class PinCollection
6
6
  include PinCommon
7
7
  include Enumerable
8
+ include OrgFile::Interceptable
9
+
10
+ ORG_FILE_INTERCEPTED_METHODS = [
11
+ :drive, :drive_hi, :drive_lo, :drive_very_hi, :drive_mem, :expect_mem, :toggle,
12
+ :repeat_previous=, :capture, :assert, :compare, :expect,
13
+ :assert_hi, :expect_hi, :compare_hi, :assert_lo, :expect_lo, :compare_lo,
14
+ :dont_care
15
+ ]
8
16
 
9
17
  attr_accessor :endian
10
18
  attr_accessor :description
@@ -22,6 +30,7 @@ module Origen
22
30
  @virtual_pins = options.delete(:virtual_pin) || options.delete(:virtual_pins)
23
31
  @other_pins = options.delete(:other_pin) || options.delete(:other_pins)
24
32
  @endian = options[:endian]
33
+ @rtl_name = options[:rtl_name]
25
34
  @description = options[:description] || options[:desc]
26
35
  @options = options
27
36
  @store = []
@@ -31,6 +40,18 @@ module Origen
31
40
  on_init(owner, options)
32
41
  end
33
42
 
43
+ def rtl_name
44
+ (@rtl_name || id).to_s
45
+ end
46
+
47
+ def global_path_to
48
+ "dut.pins(:#{id})"
49
+ end
50
+
51
+ def org_file_intercepted_methods
52
+ ORG_FILE_INTERCEPTED_METHODS
53
+ end
54
+
34
55
  # Returns the value held by the pin group as a string formatted to the current tester's pattern syntax
35
56
  #
36
57
  # @example
@@ -70,7 +91,7 @@ module Origen
70
91
  fail 'When setting vector_formatted_value on a pin group you must supply values for all pins!'
71
92
  end
72
93
  val.split(//).reverse.each_with_index do |val, i|
73
- self[i].vector_formatted_value = val
94
+ myself[i].vector_formatted_value = val
74
95
  end
75
96
  @vector_formatted_value = val
76
97
  end
@@ -140,12 +161,12 @@ module Origen
140
161
 
141
162
  def sort!(&block)
142
163
  @store = sort(&block)
143
- self
164
+ myself
144
165
  end
145
166
 
146
167
  def sort_by!
147
168
  @store = sort_by
148
- self
169
+ myself
149
170
  end
150
171
 
151
172
  def []=(index, pin)
@@ -207,11 +228,11 @@ module Origen
207
228
  alias_method :<<, :add_pin
208
229
 
209
230
  def drive(val)
210
- val = val.data if val.respond_to?('data')
231
+ value = clean_value(value)
211
232
  each_with_index do |pin, i|
212
233
  pin.drive(val[size - i - 1])
213
234
  end
214
- self
235
+ myself
215
236
  end
216
237
 
217
238
  def drive!(val)
@@ -222,7 +243,7 @@ module Origen
222
243
  # Set all pins in pin group to drive 1's on future cycles
223
244
  def drive_hi
224
245
  each(&:drive_hi)
225
- self
246
+ myself
226
247
  end
227
248
 
228
249
  def drive_hi!
@@ -233,7 +254,7 @@ module Origen
233
254
  # Set all pins in pin group to drive 0's on future cycles
234
255
  def drive_lo
235
256
  each(&:drive_lo)
236
- self
257
+ myself
237
258
  end
238
259
 
239
260
  def drive_lo!
@@ -245,7 +266,7 @@ module Origen
245
266
  # For example on a J750 high-voltage channel the pin state would be set to "2"
246
267
  def drive_very_hi
247
268
  each(&:drive_very_hi)
248
- self
269
+ myself
249
270
  end
250
271
 
251
272
  def drive_very_hi!
@@ -255,7 +276,7 @@ module Origen
255
276
 
256
277
  def drive_mem
257
278
  each(&:drive_mem)
258
- self
279
+ myself
259
280
  end
260
281
 
261
282
  def drive_mem!
@@ -265,7 +286,7 @@ module Origen
265
286
 
266
287
  def expect_mem
267
288
  each(&:expect_mem)
268
- self
289
+ myself
269
290
  end
270
291
 
271
292
  def expect_mem!
@@ -293,7 +314,7 @@ module Origen
293
314
 
294
315
  def toggle
295
316
  each(&:toggle)
296
- self
317
+ myself
297
318
  end
298
319
 
299
320
  def toggle!
@@ -303,13 +324,13 @@ module Origen
303
324
 
304
325
  def repeat_previous=(bool)
305
326
  each { |pin| pin.repeat_previous = bool }
306
- self
327
+ myself
307
328
  end
308
329
 
309
330
  # Mark the (data) from all the pins in the pin group to be captured
310
331
  def capture
311
332
  each(&:capture)
312
- self
333
+ myself
313
334
  end
314
335
  alias_method :store, :capture
315
336
 
@@ -320,8 +341,16 @@ module Origen
320
341
  alias_method :store!, :capture!
321
342
 
322
343
  def restore_state
323
- each(&:save)
344
+ save
324
345
  yield
346
+ restore
347
+ end
348
+
349
+ def save
350
+ each(&:save)
351
+ end
352
+
353
+ def restore
325
354
  each(&:restore)
326
355
  end
327
356
 
@@ -334,6 +363,7 @@ module Origen
334
363
  end
335
364
 
336
365
  def assert(value, options = {})
366
+ value = clean_value(value)
337
367
  each_with_index do |pin, i|
338
368
  if !value.respond_to?('data')
339
369
  pin.assert(value[size - i - 1], options)
@@ -343,7 +373,7 @@ module Origen
343
373
  pin.dont_care
344
374
  end
345
375
  end
346
- self
376
+ myself
347
377
  end
348
378
  alias_method :compare, :assert
349
379
  alias_method :expect, :assert
@@ -358,7 +388,7 @@ module Origen
358
388
  # Set all pins in the pin group to expect 1's on future cycles
359
389
  def assert_hi(options = {})
360
390
  each { |pin| pin.assert_hi(options) }
361
- self
391
+ myself
362
392
  end
363
393
  alias_method :expect_hi, :assert_hi
364
394
  alias_method :compare_hi, :assert_hi
@@ -373,7 +403,7 @@ module Origen
373
403
  # Set all pins in the pin group to expect 0's on future cycles
374
404
  def assert_lo(options = {})
375
405
  each { |pin| pin.assert_lo(options) }
376
- self
406
+ myself
377
407
  end
378
408
  alias_method :expect_lo, :assert_lo
379
409
  alias_method :compare_lo, :assert_lo
@@ -388,7 +418,7 @@ module Origen
388
418
  # Set all pins in the pin group to X on future cycles
389
419
  def dont_care
390
420
  each(&:dont_care)
391
- self
421
+ myself
392
422
  end
393
423
 
394
424
  def dont_care!
@@ -456,13 +486,23 @@ pins(:some_group).map(&:id).sort
456
486
  end
457
487
  end
458
488
 
459
- # Delete this pingroup (self)
489
+ # Delete this pingroup (myself)
460
490
  def delete!
461
- owner.delete_pin(self)
491
+ owner.delete_pin(myself)
462
492
  end
463
493
 
464
494
  private
465
495
 
496
+ def clean_value(val)
497
+ return val if val.respond_to?(:contains_bits?)
498
+ val = val.data if val.respond_to?('data')
499
+ if val.is_a?(String) || val.is_a?(Symbol)
500
+ Origen::Value.new(val)
501
+ else
502
+ val
503
+ end
504
+ end
505
+
466
506
  # Cleans up indexed references to pins, e.g. makes these equal:
467
507
  #
468
508
  # pins(:pb)[0,1,2,3]
@@ -501,7 +541,7 @@ pins(:some_group).map(&:id).sort
501
541
  else
502
542
  # Allow getters if all pins are the same
503
543
  ref = first.send(method, *args)
504
- if self.all? { |pin| pin.send(method, *args) == ref }
544
+ if myself.all? { |pin| pin.send(method, *args) == ref }
505
545
  ref
506
546
  else
507
547
  fail "The pins held by pin collection #{id} have different values for #{method}"