Class: Origen::Pins::Pin

Inherits:
Object show all
Includes:
OrgFile::Interceptable, PinCommon
Defined in:
lib/origen/pins/pin.rb

Direct Known Subclasses

GroundPin, OtherPin, PowerPin, VirtualPin

Constant Summary collapse

ORG_FILE_INTERCEPTED_METHODS =

Don't include the ! method in here, the cycle will be captured at the tester level and it would cause a double cycle in the org file if also captured at the pin

[
  :suspend, :resume, :repeat_previous=,
  :drive_hi, :write_hi, :drive_very_hi, :drive_lo, :write_lo, :drive_mem, :expect_mem,
  :assert_hi, :expect_hi, :compare_hi, :read_hi, :assert_lo, :expect_lo, :compare_lo, :read_lo, :dont_care,
  :drive, :write, :assert, :compare, :expect, :read, :assert_midband, :compare_midband, :expect_midband, :read_midband,
  :toggle, :capture, :store
]
FUNCTION_SCOPED_ATTRIBUTES =

Any attributes listed here will be looked up for the current function defined by the current mode and configuration context before falling back to a default

[:name, :direction, :option, :group, :ip_block, :meta]
PACKAGE_SCOPED_ATTRIBUTES =

Any attributes listed here will be looked up for the current package context before falling back to a default

[:location, :dib_assignment, :dib_meta]
TYPES =

Pin Types, 'digital' and 'analog' are legacy types kept for backwards compatibility

[:analog, :digital, :signal, :ground, :power, :virtual]

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from OrgFile::Interceptable

#__interceptor__=, included, #myself

Methods included from PinCommon

#add_configuration, #add_mode, #add_package, #enabled?, #enabled_in_configuration?, #enabled_in_mode?, #enabled_in_package?, #finalize, #id=, #to_sym

Constructor Details

#initialize(id, owner, options = {}) ⇒ Pin

Should be instantiated through the HasPins macros



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/origen/pins/pin.rb', line 68

def initialize(id, owner, options = {}) # :nodoc:
  options = {
    reset:        :dont_care,
    invert:       false,
    direction:    :io,
    open_drain:   false,
    ext_pullup:   false,
    ext_pulldown: false,
    rtl_name:     nil
  }.merge(options)
  @aliases = {}
  @functions = {}
  @direction = sanitize_direction(options[:direction])
  @invert = options[:invert]
  @reset = options[:reset]
  @force = options[:force] & 1
  @id = id
  @name = options[:name]
  @rtl_name = options[:rtl_name]
  @suspend = false
  @order = options[:order]
  @supply = options[:supply]
  @open_drain = options[:open_drain]
  @ext_pullup = options[:ext_pullup]
  @ext_pulldown = options[:ext_pulldown]
  @type = options[:type]
  @dib_assignment = [] # Array to handle multi-site testing
  @size = 1
  @value = 0
  @clock = nil
  @meta = options[:meta] || {}
  @dib_meta = options[:dib_meta] || {}
  @state_meta = {}
  @_saved_state = []
  @_saved_value = []
  @_saved_suspend = []
  @_saved_invert = []
  @_saved_repeat_previous = []
  on_init(owner, options)
  # Assign the initial state from the method so that any inversion is picked up...
  send(@reset)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *args, &block) ⇒ Object



1178
1179
1180
1181
1182
1183
1184
# File 'lib/origen/pins/pin.rb', line 1178

def method_missing(m, *args, &block)
  if meta.include? m
    meta[m]
  else
    super
  end
end

Instance Attribute Details

#aliasesObject (readonly)

Returns a hash containing the aliases associated with the given pin



37
38
39
# File 'lib/origen/pins/pin.rb', line 37

def aliases
  @aliases
end

#descriptionObject

Returns the value of attribute description.



56
57
58
# File 'lib/origen/pins/pin.rb', line 56

def description
  @description
end

#ext_pulldownObject

Boolean on whether pin has external pull-down



48
49
50
# File 'lib/origen/pins/pin.rb', line 48

def ext_pulldown
  @ext_pulldown
end

#ext_pullupObject

Boolean on whether pin has external pull-up



46
47
48
# File 'lib/origen/pins/pin.rb', line 46

def ext_pullup
  @ext_pullup
end

#forceObject

Value to be forced on the pin, e.g. during simulation



54
55
56
# File 'lib/origen/pins/pin.rb', line 54

def force
  @force
end

#functionsObject

Returns a hash containing the functions associated with the given pin



39
40
41
# File 'lib/origen/pins/pin.rb', line 39

def functions
  @functions
end

#invertObject

Inverts pin states for drive and compare, can be useful if a timing set change requires clocks to drive low for example when all pattern logic has been set up to drive them high.



30
31
32
# File 'lib/origen/pins/pin.rb', line 30

def invert
  @invert
end

#notesObject

Returns the value of attribute notes.



57
58
59
# File 'lib/origen/pins/pin.rb', line 57

def notes
  @notes
end

#open_drainObject

Boolean on whether pin is open drain



44
45
46
# File 'lib/origen/pins/pin.rb', line 44

def open_drain
  @open_drain
end

#orderObject

Returns the value of attribute order.



28
29
30
# File 'lib/origen/pins/pin.rb', line 28

def order
  @order
end

#ownerObject (readonly)

Returns the value of attribute owner.



34
35
36
# File 'lib/origen/pins/pin.rb', line 34

def owner
  @owner
end

#repeat_previousObject

Attribute used to generate vectors where the pin state is assigned the repeat_previous opcode, used by Tester#repeat_previous



33
34
35
# File 'lib/origen/pins/pin.rb', line 33

def repeat_previous
  @repeat_previous
end

#rtl_nameObject



147
148
149
150
151
152
153
# File 'lib/origen/pins/pin.rb', line 147

def rtl_name
  if primary_group
    (@rtl_name || "#{primary_group.id}#{primary_group_index}").to_s
  else
    (@rtl_name || id).to_s
  end
end

#sizeObject (readonly)

Returns the value of attribute size.



35
36
37
# File 'lib/origen/pins/pin.rb', line 35

def size
  @size
end

#state_metaObject (readonly)

Returns a hash containing any meta data associated with the current pin state

my_pin.read!(1, meta: { position: 10 })
my_pin.state_meta    # => { position: 10 }
my_pin.dont_care
my_pin.state_meta    # => {}


65
66
67
# File 'lib/origen/pins/pin.rb', line 65

def state_meta
  @state_meta
end

#supplyObject

Internal power supply pin is connected to



41
42
43
# File 'lib/origen/pins/pin.rb', line 41

def supply
  @supply
end

#supply_strObject

Returns the value of attribute supply_str.



42
43
44
# File 'lib/origen/pins/pin.rb', line 42

def supply_str
  @supply_str
end

#typeObject

Pin type, either :analog or :digital



50
51
52
# File 'lib/origen/pins/pin.rb', line 50

def type
  @type
end

Instance Method Details

#<=>(other_pin) ⇒ Object

When sorting pins do it by ID



193
194
195
# File 'lib/origen/pins/pin.rb', line 193

def <=>(other_pin)
  @id <=> other_pin.id
end

#add_alias(id, options = {}) ⇒ Object

Add an alias to the given pin.

If the options contain a package, mode or configuration reference then the alias will only work under that context.



574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
# File 'lib/origen/pins/pin.rb', line 574

def add_alias(id, options = {})
  obj = options.delete(:obj) || myself
  if aliases[id]
    aliases[id][:packages] += resolve_packages(options)
    aliases[id][:modes] += resolve_modes(options)
    aliases[id][:configurations] += resolve_configurations(options)
    aliases[id][:packages].uniq!
    aliases[id][:modes].uniq!
    aliases[id][:configurations].uniq!
  else
    aliases[id] = {
      packages:       resolve_packages(options),
      modes:          resolve_modes(options),
      configurations: resolve_configurations(options)
    }
    Origen.pin_bank.register_alias(id, obj, options)
  end
end

#add_dib_assignment(str, options = {}) ⇒ Object Also known as: add_dib_info, add_channel

Add a Device Interface Board (e.g. probecard at wafer probe or loadboard at final package test) assignment to the pin. Some refer to this as a channel but API name is meant to be generic.



466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
# File 'lib/origen/pins/pin.rb', line 466

def add_dib_assignment(str, options = {})
  options = {
    site: 0
  }.merge(options)
  packages = resolve_packages(options)
  if packages.empty?
    @dib_assignment[options[:site]] = str
    add_alias str.to_s.symbolize, package: :all, mode: :all, configuration: :all
  else
    packages.each do |package_id|
      package_id = package_id.respond_to?(:id) ? package_id.id : package_id
      myself.packages[package_id] ||= {}
      myself.packages[package_id][:dib_assignment] ||= []
      myself.packages[package_id][:dib_assignment][options[:site]] = str
      add_alias str.to_s.symbolize, package: package_id, mode: :all, configuration: :all
    end
  end
end

#add_dib_meta(pkg, options) ⇒ Object



487
488
489
490
491
492
493
494
495
496
497
# File 'lib/origen/pins/pin.rb', line 487

def add_dib_meta(pkg, options)
  unless Origen.top_level.packages.include? pkg
    Origen.log.error("Cannot add DIB metadata for package '#{pkg}', that package has not been added yet!")
    fail
  end
  options.each do |attr, attr_value|
    packages[pkg][:dib_meta] ||= {}
    packages[pkg][:dib_meta][attr] = attr_value
    add_alias attr_value.to_s.symbolize, package: pkg, mode: :all, configuration: :all
  end
end

#add_function(id, options = {}) ⇒ Object

Add a function to the pin.

Examples:

Adding a mode-specific function

pin.add_function :tdi, :direction => :input
pin.add_function :nvm_fail, :mode => :nvmbist, :direction => :output


530
531
532
533
534
535
# File 'lib/origen/pins/pin.rb', line 530

def add_function(id, options = {})
  id = id.to_sym
  add_function_attributes(options.merge(name: id, id: id.to_sym))
  f = FunctionProxy.new(id, myself)
  add_alias id, packages: :all, obj: f
end

#add_function_attributes(options = {}) ⇒ Object



537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
# File 'lib/origen/pins/pin.rb', line 537

def add_function_attributes(options = {})
  id = options.delete(:id)
  modes = resolve_modes(options)
  configurations = resolve_configurations(options)
  options[:direction] = sanitize_direction(options[:direction]) if options[:direction]
  if modes.empty?
    modes = [:all]
  end
  if configurations.empty?
    configurations = [:all]
  end
  # Supports newer attribute lookup by function ID
  if id
    functions[:ids] ||= {}
    if functions[:ids][id]
      functions[:ids][id] = functions[:ids][id].merge!(options)
    else
      functions[:ids][id] = options.dup
    end
  end
  # Supports older attribute lookup by mode context
  modes.each do |mode|
    configurations.each do |configuration|
      functions[mode.to_sym] ||= {}
      if functions[mode.to_sym][configuration.to_sym]
        functions[mode.to_sym][configuration.to_sym] = functions[mode.to_sym][configuration.to_sym].merge!(options)
      else
        functions[mode.to_sym][configuration.to_sym] = options
      end
    end
  end
end

#add_location(str, options = {}) ⇒ Object Also known as: add_locn

Add a location identifier to the pin, this is a free format field which can be a pin number or BGA co-ordinate for example.

Examples:

Adding a location by package

$dut.pin(:pin3).add_location "B3", :package => :p1
$dut.pin(:pin3).add_location "B2", :package => :p2


430
431
432
433
434
435
436
437
438
439
440
441
442
443
# File 'lib/origen/pins/pin.rb', line 430

def add_location(str, options = {})
  packages = resolve_packages(options)
  if packages.empty?
    @location = str
    add_alias str.to_s.symbolize, package: :all, mode: :all, configuration: :all
  else
    packages.each do |package_id|
      package_id = package_id.respond_to?(:id) ? package_id.id : package_id
      myself.packages[package_id] ||= {}
      myself.packages[package_id][:location] = str
      add_alias str.to_s.symbolize, package: package_id, mode: :all, configuration: :all
    end
  end
end

#assert(value, options = {}) ⇒ Object Also known as: compare, expect, read

Pass in 0 or 1 to have the pin expect_lo or expect_hi respectively. This is useful when programatically setting the pin state.

Example

[0,1,1,0].each do |level|
    $pin(:d_in).assert(level)
end


861
862
863
864
# File 'lib/origen/pins/pin.rb', line 861

def assert(value, options = {})
  set_state_with_options(:compare, options)
  set_value(value)
end

#assert!(*args) ⇒ Object Also known as: compare!, expect!, read!



869
870
871
872
# File 'lib/origen/pins/pin.rb', line 869

def assert!(*args)
  assert(*args)
  cycle
end

#assert_hi(options = {}) ⇒ Object Also known as: expect_hi, compare_hi, read_hi

Set the pin to expect a 1 on future cycles



786
787
788
789
# File 'lib/origen/pins/pin.rb', line 786

def assert_hi(options = {})
  set_state_with_options(:compare, options)
  set_value(1)
end

#assert_hi!(options = {}) ⇒ Object Also known as: expect_hi!, compare_hi!, read_hi!



794
795
796
797
# File 'lib/origen/pins/pin.rb', line 794

def assert_hi!(options = {})
  assert_hi(options)
  cycle
end

#assert_lo(options = {}) ⇒ Object Also known as: expect_lo, compare_lo, read_lo

Set the pin to expect a 0 on future cycles



803
804
805
806
807
808
809
810
811
812
813
814
# File 'lib/origen/pins/pin.rb', line 803

def assert_lo(options = {})
  set_state_with_options(:compare, options)
  set_value(0)
  # Planning to add the active load logic to the tester instead...
  # options = { :active => false    #if active true means to take tester active load capability into account
  #          }.merge(options)
  # unless state_to_be_inverted?
  #  myself.state = ($tester.active_loads || !options[:active]) ? $tester.pin_state(:expect_lo) : $tester.pin_state(:dont_care)
  # else
  #  myself.state = ($tester.active_loads || !options[:active]) ? $tester.pin_state(:expect_hi) : $tester.pin_state(:dont_care)
  # end
end

#assert_lo!(options = {}) ⇒ Object Also known as: expect_lo!, compare_lo!, read_lo!



819
820
821
822
# File 'lib/origen/pins/pin.rb', line 819

def assert_lo!(options = {})
  assert_lo(options)
  cycle
end

#assert_midband(options = {}) ⇒ Object Also known as: compare_midband, expect_midband, read_midband



877
878
879
# File 'lib/origen/pins/pin.rb', line 877

def assert_midband(options = {})
  set_state_with_options(:compare_midband, options)
end

#assert_midband!(options = {}) ⇒ Object Also known as: compare_midband!, expect_midband!, read_midband!



884
885
886
887
# File 'lib/origen/pins/pin.rb', line 884

def assert_midband!(options = {})
  assert_midband(options)
  cycle
end

#belongs_to_a_pin_group?Boolean

Returns true if the pin belongs to a pin group.

add_pins :jtag, size: 6
add_pin  :done
add_pin_alias :fail, :jtag, pin: 4

pin(:done).belongs_to_a_pin_group?  # => false
pin(:fail).belongs_to_a_pin_group?  # => true

Returns:

  • (Boolean)


635
636
637
# File 'lib/origen/pins/pin.rb', line 635

def belongs_to_a_pin_group?
  !groups.empty?
end

#capture(options = {}) ⇒ Object Also known as: store

Mark the (data) from the pin to be captured



945
946
947
# File 'lib/origen/pins/pin.rb', line 945

def capture(options = {})
  set_state_with_options(:capture, options)
end

#capture!(options = {}) ⇒ Object Also known as: store!

Mark the (data) from the pin to be captured and trigger a cycle



951
952
953
954
# File 'lib/origen/pins/pin.rb', line 951

def capture!(options = {})
  capture(options)
  cycle
end

#clear_mask(options = { context: nil, size: nil }) ⇒ Object Also known as: clr_mask, cmask



1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
# File 'lib/origen/pins/pin.rb', line 1136

def clear_mask(options = { context: nil, size: nil })
  context = options[:context]
  size = options[:size]

  index = context.is_a?(Integer) ? context : self.index(context: context)

  if index.nil? && context.nil?
    # If the index is nil and no context was given, no implicit index could be resolved
    fail("Could not discern pin :#{name}'s implicit index!")
  elsif index.nil?
    # If the index is nil and some context was given, then the pin is not in the given context
    fail("Pin :#{name} is not a member of the given context!")
  end

  if size && context && !context.is_a?(Integer)
    # A context was given, that was not just an Integer, and size was given
    # Raise an exception as these two conflict.
    fail('Both a sized context (e.g. pin group) and a :size option cannot be used simultaneously!')
  elsif size
    # A size option was given. Use that.
    ((2**size) - 1) ^ (1 << index)
  elsif context.is_a?(Symbol)
    ((2**groups[context].instance_variable_get(:@store).size) - 1) ^ (1 << index)
  elsif context.respond_to?(:size) && !context.is_a?(Integer)
    # PinCollection or Array
    ((2**context.size) - 1) ^ (1 << index)
  else
    # No size option was given. Use the implicit index instead.
    (2**index) - 1
  end
end

#compare_wave(code = nil) ⇒ Object

Returns the compare cycle wave assigned to the pin based on the currently enabled timeset, or nil if none is set Note that if a timeset is set then all pins will always return a wave as they will pick up a default waveform if none is explicitly assigned to it.



137
138
139
140
141
142
143
144
145
# File 'lib/origen/pins/pin.rb', line 137

def compare_wave(code = nil)
  if t = dut.current_timeset
    # Cache this for performance since potentially this is something that could be called on
    # every cycle in some applications
    @compare_waves ||= {}
    @compare_waves[t.id] ||= {}
    @compare_waves[t.id][code] ||= dut.current_timeset.send(:wave_for, myself, type: :compare, code: code)
  end
end

#comparing?Boolean

Returns true if the pin is currently in a compare state

Returns:

  • (Boolean)


898
899
900
901
# File 'lib/origen/pins/pin.rb', line 898

def comparing?
  !@suspend &&
    state == :compare
end

#comparing_mem?Boolean

Returns true if the pin is currently in a compare mem state

Returns:

  • (Boolean)


904
905
906
907
# File 'lib/origen/pins/pin.rb', line 904

def comparing_mem?
  !@suspend &&
    state == :expect_mem
end

#comparing_midband?Boolean

Returns true if the pin is currently in a compare state

Returns:

  • (Boolean)


910
911
912
913
# File 'lib/origen/pins/pin.rb', line 910

def comparing_midband?
  !@suspend &&
    state == :compare_midband
end

#cycleObject

:nodoc:



715
716
717
# File 'lib/origen/pins/pin.rb', line 715

def cycle # :nodoc:
  Origen.tester.cycle
end

#delete!Object

Delete this pin (myself). Used bang in method name to keep same for pins and pin collections. Pin collections already had a delete method which deletes a pin from the collection. Needed delete! to indicate it is deleting the actual pin or pin group calling the method.



1058
1059
1060
# File 'lib/origen/pins/pin.rb', line 1058

def delete!
  owner.delete_pin(myself)
end

#describe(options = {}) ⇒ Object



322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
# File 'lib/origen/pins/pin.rb', line 322

def describe(options = {})
  desc = ['********************']
  desc << "Pin id: #{id}"
  func_aliases = []
  unless functions.empty?
    desc << ''
    desc << 'Functions'
    desc << '---------'
    functions.each do |mode, configurations|
      unless mode == :ids
        configurations.each do |configuration, attrs|
          a = ":#{attrs[:name]}".ljust(30)
          func_aliases << attrs[:name]
          unless mode == :all
            a += ":modes => [#{[mode].flatten.map { |id| ':' + id.to_s }.join(', ')}]"
            prev = true
          end
          unless configuration == :all
            a += ' ; ' if prev
            a += ":configurations => [#{[configuration].flatten.map { |id| ':' + id.to_s }.join(', ')}]"
          end
          desc << a
        end
      end
    end
  end
  unless aliases.empty?
    desc << ''
    desc << 'Aliases'
    desc << '-------'
    aliases.each do |name, context|
      unless func_aliases.include?(name)
        a = ":#{name}".ljust(30)
        unless context[:packages].empty? || context[:packages] == [:all]
          a += ":packages => [#{context[:packages].map { |id| ':' + id.to_s }.join(', ')}]"
          prev = true
        end
        unless context[:modes].empty? || context[:modes] == [:all]
          a += ' ; ' if prev
          a += ":modes => [#{context[:modes].map { |id| ':' + id.to_s }.join(', ')}]"
          prev = true
        end
        unless context[:configurations].empty? || context[:configurations] == [:all]
          a += ' ; ' if prev
          a += ":configurations => [#{context[:configurations].map { |id| ':' + id.to_s }.join(', ')}]"
        end
        desc << a
      end
    end
  end
  unless Origen.top_level.modes.empty?
    desc << ''
    desc << 'Modes'
    desc << '-------'
    Origen.top_level.modes.each do |name|
      unless option(mode: name).nil?
        a = ":#{name}".ljust(30) + ":mode => #{option(mode: name)}"
        desc << a
      end
    end
  end
  unless groups.empty?
    desc << ''
    desc << 'Groups'
    desc << '------'
    desc << groups.map { |name, _group| ':' + name.to_s }.join(', ')
  end
  desc << '********************'
  if options[:return]
    desc
  else
    puts desc.join("\n")
  end
end

#direction=(val) ⇒ Object

Sets the default direction of the pin, :input, :output or :io (default). If a function specific direction has been specified that will override this value.



521
522
523
# File 'lib/origen/pins/pin.rb', line 521

def direction=(val)
  @direction = sanitize_direction(val)
end

#disable_clock(options = {}) ⇒ Object



1016
1017
1018
1019
# File 'lib/origen/pins/pin.rb', line 1016

def disable_clock(options = {})
  @clock.stop_clock(options)
  @clock = nil
end

#dont_care(options = {}) ⇒ Object

Set the pin to X on future cycles



828
829
830
# File 'lib/origen/pins/pin.rb', line 828

def dont_care(options = {})
  set_state_with_options(:dont_care, options)
end

#dont_care!(options = {}) ⇒ Object



832
833
834
835
# File 'lib/origen/pins/pin.rb', line 832

def dont_care!(options = {})
  dont_care(options)
  cycle
end

#drive(value, options = {}) ⇒ Object Also known as: write

Pass in 0 or 1 to have the pin drive_lo or drive_hi respectively. This is useful when programatically setting the pin state.

Example

[0,1,1,0].each do |level|
    $pin(:d_in).drive(level)
end


843
844
845
846
# File 'lib/origen/pins/pin.rb', line 843

def drive(value, options = {})
  set_state_with_options(:drive, options)
  set_value(value)
end

#drive!(value, options = {}) ⇒ Object Also known as: write!



849
850
851
852
# File 'lib/origen/pins/pin.rb', line 849

def drive!(value, options = {})
  drive(value, options)
  cycle
end

#drive_hi(options = {}) ⇒ Object Also known as: write_hi

Set the pin to drive a 1 on future cycles



730
731
732
733
# File 'lib/origen/pins/pin.rb', line 730

def drive_hi(options = {})
  set_state_with_options(:drive, options)
  set_value(1)
end

#drive_hi!(options = {}) ⇒ Object Also known as: write_hi!



736
737
738
739
# File 'lib/origen/pins/pin.rb', line 736

def drive_hi!(options = {})
  drive_hi(options)
  cycle
end

#drive_lo(options = {}) ⇒ Object Also known as: write_lo

Set the pin to drive a 0 on future cycles



755
756
757
758
# File 'lib/origen/pins/pin.rb', line 755

def drive_lo(options = {})
  set_state_with_options(:drive, options)
  set_value(0)
end

#drive_lo!(options = {}) ⇒ Object Also known as: write_lo!



761
762
763
764
# File 'lib/origen/pins/pin.rb', line 761

def drive_lo!(options = {})
  drive_lo(options)
  cycle
end

#drive_mem(options = {}) ⇒ Object



767
768
769
# File 'lib/origen/pins/pin.rb', line 767

def drive_mem(options = {})
  set_state_with_options(:drive_mem, options)
end

#drive_mem!(options = {}) ⇒ Object



771
772
773
774
# File 'lib/origen/pins/pin.rb', line 771

def drive_mem!(options = {})
  drive_mem(options)
  cycle
end

#drive_very_hi(options = {}) ⇒ Object

Set the pin to drive a high voltage on future cycles (if the tester supports it). For example on a J750 high-voltage channel the pin state would be set to “2”



744
745
746
747
# File 'lib/origen/pins/pin.rb', line 744

def drive_very_hi(options = {})
  set_state_with_options(:drive_very_hi, options)
  set_value(1)
end

#drive_very_hi!(options = {}) ⇒ Object



749
750
751
752
# File 'lib/origen/pins/pin.rb', line 749

def drive_very_hi!(options = {})
  drive_very_hi(options)
  cycle
end

#drive_wave(code = nil) ⇒ Object

Returns the drive cycle wave assigned to the pin based on the currently enabled timeset, or nil if none is set. Note that if a timeset is set then all pins will always return a wave as they will pick up a default waveform if none is explicitly assigned to it.



123
124
125
126
127
128
129
130
131
# File 'lib/origen/pins/pin.rb', line 123

def drive_wave(code = nil)
  if t = dut.current_timeset
    # Cache this for performance since potentially this is something that could be called on
    # every cycle in some applications
    @drive_waves ||= {}
    @drive_waves[t.id] ||= {}
    @drive_waves[t.id][code] ||= dut.current_timeset.send(:wave_for, myself, type: :drive, code: code)
  end
end

#driving?Boolean

Returns true if the pin is currently in a drive state

Returns:

  • (Boolean)


916
917
918
919
# File 'lib/origen/pins/pin.rb', line 916

def driving?
  !@suspend &&
    (state == :drive || state == :drive_very_hi)
end

#driving_mem?Boolean

Returns true if the pin is currently in a drive mem state

Returns:

  • (Boolean)


922
923
924
925
# File 'lib/origen/pins/pin.rb', line 922

def driving_mem?
  !@suspend &&
    state == :drive_mem
end

#duty_cyclesObject



1040
1041
1042
# File 'lib/origen/pins/pin.rb', line 1040

def duty_cycles
  @clock.cycles_per_duty
end

#enable_clock(options = {}) ⇒ Object



1012
1013
1014
# File 'lib/origen/pins/pin.rb', line 1012

def enable_clock(options = {})
  @clock = PinClock.new(myself, options)
end

#expect_mem(options = {}) ⇒ Object



776
777
778
# File 'lib/origen/pins/pin.rb', line 776

def expect_mem(options = {})
  set_state_with_options(:expect_mem, options)
end

#expect_mem!(options = {}) ⇒ Object



780
781
782
783
# File 'lib/origen/pins/pin.rb', line 780

def expect_mem!(options = {})
  expect_mem(options)
  cycle
end

#function_scoped_nameObject



272
# File 'lib/origen/pins/pin.rb', line 272

alias_method :function_scoped_name, :name

#global_path_toObject



111
112
113
# File 'lib/origen/pins/pin.rb', line 111

def global_path_to
  "dut.pins(:#{id})"
end

#goodbyeObject

See Pin#hello



187
188
189
190
# File 'lib/origen/pins/pin.rb', line 187

def goodbye
  @@hello_pins.delete(myself)
  puts "Pin #{name} has stopped toggling"
end

#groupObject Also known as: primary_group

If the pin was defined initially as part of a group then this will return that group, otherwise it will return nil



399
400
401
# File 'lib/origen/pins/pin.rb', line 399

def group
  @primary_group
end

#group_indexObject Also known as: primary_group_index

If the pin is a member of a primary group, this returns its index number within that group, otherwise returns nil



406
407
408
# File 'lib/origen/pins/pin.rb', line 406

def group_index
  @primary_group_index
end

#groupsObject Also known as: pin_groups

Returns a hash containing the pin groups that the given pin is a member of



412
413
414
415
416
417
# File 'lib/origen/pins/pin.rb', line 412

def groups
  # Origen.pin_bank.all_pin_groups.select do |name, group|
  @groups ||= Origen.pin_bank.pin_groups.select do |_name, group|
    group.include?(myself)
  end
end

#half_periodObject



1044
1045
1046
# File 'lib/origen/pins/pin.rb', line 1044

def half_period
  @clock.cycles_per_half_period
end

#has_alias?(id, options = {}) ⇒ Boolean

Returns true if the pin has the given alias within the given or current context

Returns:

  • (Boolean)


594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
# File 'lib/origen/pins/pin.rb', line 594

def has_alias?(id, options = {})
  if aliases[id]
    if options[:ignore_context]
      true
    else
      packages = resolve_packages(options)
      modes = resolve_modes(options)
      configurations = resolve_configurations(options)
      begin
        aliases[id][:packages].include?(:all) || aliases[id][:packages].empty? ||
          packages.any? { |package| aliases[id][:packages].include?(package) }
      end && begin
        aliases[id][:modes].include?(:all) || aliases[id][:modes].empty? ||
          modes.any? { |mode| aliases[id][:modes].include?(mode) }
      end && begin
        aliases[id][:configurations].include?(:all) || aliases[id][:configurations].empty? ||
          configurations.any? { |config| aliases[id][:configurations].include?(config) }
      end
    end
  else
    false
  end
end

#helloObject

Causes the pin to continuously drive 1 for 2 seconds and then drive 0 for 2 seconds.

This is not an API that is intended to be used within a pattern. Rather it is a debug aid when setting up something like a bench test environment that uses Origen Link. For example you would call this method on a pin from a console session, then confirm with a multimeter that the pin is toggling on the relevant hardware.

Call Pin#goodbye to stop it.

Examples:

Call from an origen console like this


dut.pin(:tdi).hello


167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/origen/pins/pin.rb', line 167

def hello
  drive_hi
  @@hello_pins ||= []
  @@hello_pins << myself unless @@hello_pins.include?(myself)
  @@hello_loop ||= Thread.new do
    loop do
      @@hello_pins.each(&:toggle)
      if $tester
        # Add a dummy timeset if one is not set yet, doesn't really matter what it is in this case
        # and better not to force the user to setup a debug workaround due to running outside of a pattern
        $tester.set_timeset('hello_world', 40) unless $tester.timeset
        $tester.cycle
      end
      sleep 2
    end
  end
  puts "Pin #{name} is toggling with a period of 2 seconds"
end

#high_voltage?Boolean

Returns true if pin is in high voltage state

Returns:

  • (Boolean)


928
929
930
931
# File 'lib/origen/pins/pin.rb', line 928

def high_voltage?
  !@suspend &&
    state == :drive_very_hi
end

#index(options = { context: nil }) ⇒ Object



1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
# File 'lib/origen/pins/pin.rb', line 1098

def index(options = { context: nil })
  context = options[:context]
  if context.is_a?(Symbol)
    # Context pin group provided
    group = groups[context].instance_variable_get(:@store)
    if group
      group.index(self)
    end
  elsif context.is_a?(Array)
    # Anonymous pin group given
    context.map { |p| p.is_a?(Symbol) ? owner.pin(p) : p }.index(self)
  else
    # Try an index based off of the pin name.
    # Only works if the pin ends in a decimal. Otherwise, returns nil.
    i = name.to_s.index(/\d+$/)
    if i
      name.to_s[i..-1].to_i
    end
  end
end

#index?(options = { context: nil }) ⇒ Boolean

Returns:

  • (Boolean)


1094
1095
1096
# File 'lib/origen/pins/pin.rb', line 1094

def index?(options = { context: nil })
  !!index(options).nil?
end

#inspectObject



318
319
320
# File 'lib/origen/pins/pin.rb', line 318

def inspect
  "<#{myself.class}:#{object_id}>"
end

#invalidate_group_cacheObject



420
421
422
# File 'lib/origen/pins/pin.rb', line 420

def invalidate_group_cache
  @groups = nil
end

#invalidate_vector_cacheObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



295
296
297
298
# File 'lib/origen/pins/pin.rb', line 295

def invalidate_vector_cache
  @vector_formatted_value = nil
  groups.each { |_name, group| group.invalidate_vector_cache }
end

#inverted?Boolean

Returns the state of invert

Returns:

  • (Boolean)


893
894
895
# File 'lib/origen/pins/pin.rb', line 893

def inverted?
  @invert
end

#is_a_clock?Boolean

Returns:

  • (Boolean)


1004
1005
1006
# File 'lib/origen/pins/pin.rb', line 1004

def is_a_clock?
  !(@clock.nil?)
end

#is_a_running_clock?Boolean

Returns:

  • (Boolean)


1008
1009
1010
# File 'lib/origen/pins/pin.rb', line 1008

def is_a_running_clock?
  @clock.running?
end

#is_alias_of?(name) ⇒ Boolean

Returns true if the pin is an alias of the given pin name

Returns:

  • (Boolean)


619
620
621
622
623
624
625
# File 'lib/origen/pins/pin.rb', line 619

def is_alias_of?(name)
  if Origen.pin_bank.find(name)
    Origen.pin_bank.find(name).id == Origen.pin_bank.find(myself).id
  else
    false
  end
end

#is_not_a_clock?Boolean

Returns:

  • (Boolean)


1000
1001
1002
# File 'lib/origen/pins/pin.rb', line 1000

def is_not_a_clock?
  @clock.nil?
end

#mask(options = { context: nil }) ⇒ Object Also known as: set_mask, smask



1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
# File 'lib/origen/pins/pin.rb', line 1119

def mask(options = { context: nil })
  context = options[:context]
  index = context.is_a?(Integer) ? context : self.index(context: context)

  if index.nil? && context.nil?
    # If the index is nil and no context was given, no implicit index could be resolved
    fail("Could not discern pin :#{name}'s implicit index!")
  elsif index.nil?
    # If the index is nil and some context was given, then the pin is not in the given context
    fail("Pin :#{name} is not a member of the given context!")
  end

  2**index
end

#name(options = {}) ⇒ Object

Returns the name of the pin, if a name has been specifically assigned by the application (via name=) then this will be returned, otherwise the name of the current function if present will be returned, and then as a last resort the ID of the pin



277
278
279
280
# File 'lib/origen/pins/pin.rb', line 277

def name(options = {})
  # Return a specifically assigned name in preference to a function name
  (options.empty? ? @name : nil) || function_scoped_name(options) || @id
end

#name=(val) ⇒ Object



197
198
199
# File 'lib/origen/pins/pin.rb', line 197

def name=(val)
  @name = val
end

#named?(n) ⇒ Boolean

Returns:

  • (Boolean)


1170
1171
1172
1173
1174
1175
1176
# File 'lib/origen/pins/pin.rb', line 1170

def named?(n)
  if n.is_a?(Regexp)
    [name.to_s, *aliases.keys].any? { |na| na =~ n }
  else
    [name.to_s, *aliases.keys.map(&:to_s)].include?(n.to_s)
  end
end

#next_edgeObject



1036
1037
1038
# File 'lib/origen/pins/pin.rb', line 1036

def next_edge
  @clock.next_edge
end

#org_file_intercepted_methodsObject



115
116
117
# File 'lib/origen/pins/pin.rb', line 115

def org_file_intercepted_methods
  ORG_FILE_INTERCEPTED_METHODS
end

#repeat_previous?Boolean

Returns:

  • (Boolean)


664
665
666
# File 'lib/origen/pins/pin.rb', line 664

def repeat_previous?
  @repeat_previous
end

#respond_to_missing?(m, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


1186
1187
1188
# File 'lib/origen/pins/pin.rb', line 1186

def respond_to_missing?(m, include_private = false)
  meta[m] || super
end

#restoreObject

Restores the state of the pin to the last time save was called



991
992
993
994
995
996
997
998
# File 'lib/origen/pins/pin.rb', line 991

def restore
  invalidate_vector_cache
  @state = @_saved_state.pop
  @value = @_saved_value.pop
  @suspend = @_saved_suspend.pop
  @invert = @_saved_invert.pop
  @repeat_previous = @_saved_repeat_previous.pop
end

#restore_stateObject

Restores the state of the pin at the end of the given block to the state it was in at the start of the block

pin(:invoke).driving?  # => true
pin(:invoke).restore_state do
  pin(:invoke).dont_care
  pin(:invoke).driving?  # => false
end
pin(:invoke).driving?  # => true


974
975
976
977
978
# File 'lib/origen/pins/pin.rb', line 974

def restore_state
  save
  yield
  restore
end

#resumeObject

Will resume compares on this pin



654
655
656
657
# File 'lib/origen/pins/pin.rb', line 654

def resume
  invalidate_vector_cache
  @suspend = false
end

#sanitize_direction(val) ⇒ Object



504
505
506
507
508
509
510
511
512
513
514
515
516
517
# File 'lib/origen/pins/pin.rb', line 504

def sanitize_direction(val)
  if val
    val = val.to_s.downcase.gsub(/\//, '')
    if val =~ /i.*o/
      :io
    elsif val =~ /^i/
      :input
    elsif val =~ /^o/
      :output
    else
      fail "Unknown pin direction: #{val}"
    end
  end
end

#saveObject

Saves the current state of the pin, allowing it to be restored to the current state by calling the restore method



982
983
984
985
986
987
988
# File 'lib/origen/pins/pin.rb', line 982

def save
  @_saved_state << @state
  @_saved_value << @value
  @_saved_suspend << @suspend
  @_saved_invert << @invert
  @_saved_repeat_previous << @repeat_previous
end

#set_state(state) ⇒ Object



673
674
675
676
677
# File 'lib/origen/pins/pin.rb', line 673

def set_state(state)
  invalidate_vector_cache
  @repeat_previous = false
  @state = state
end

#set_state_with_options(state, options = {}) ⇒ Object



668
669
670
671
# File 'lib/origen/pins/pin.rb', line 668

def set_state_with_options(state, options = {})
  @state_meta = options[:meta] || {}
  set_state(state)
end

#set_value(val) ⇒ Object Also known as: data=



679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
# File 'lib/origen/pins/pin.rb', line 679

def set_value(val)
  orig = val
  invalidate_vector_cache
  if val.is_a?(String) || val.is_a?(Symbol)
    val = val.to_s
    if val =~ /^(b|h).+/
      val = Origen::Value.new(val)
    else
      @vector_formatted_value = val
      return
    end
  end
  if val.is_a?(Origen::Value)
    val = val[0]
  else
    # If val is a data bit extract the value of it
    val = val.respond_to?(:data) ? val.data : val
    # Assume driving/asserting a nil value means 0
    val ||= 0
    if !val.x_or_z? && val > 1
      fail "Attempt to set a value of #{val} on pin #{name}"
    end
  end
  @repeat_previous = false
  if val.x_or_z?
    dont_care
  else
    if inverted?
      @value = val == 0 ? 1 : 0
    else
      @value = val
    end
  end
end

#sitesObject

Returns the number of test sites enabled for the pin



500
501
502
# File 'lib/origen/pins/pin.rb', line 500

def sites
  dib_assignment.size
end

#start_clock(options = {}) ⇒ Object Also known as: resume_clock



1025
1026
1027
1028
# File 'lib/origen/pins/pin.rb', line 1025

def start_clock(options = {})
  enable_clock(options) if myself.is_not_a_clock?
  @clock.start_clock(options)
end

#stateObject



719
720
721
# File 'lib/origen/pins/pin.rb', line 719

def state
  @state
end

#state=(value) ⇒ Object



723
724
725
726
727
# File 'lib/origen/pins/pin.rb', line 723

def state=(value)
  invalidate_vector_cache
  @state_meta = {}
  @state = value
end

#stop_clock(options = {}) ⇒ Object Also known as: pause_clock



1031
1032
1033
# File 'lib/origen/pins/pin.rb', line 1031

def stop_clock(options = {})
  @clock.stop_clock(options)
end

#suspendObject



644
645
646
647
# File 'lib/origen/pins/pin.rb', line 644

def suspend
  invalidate_vector_cache
  @suspend = true
end

#suspended?Boolean

Returns:

  • (Boolean)


649
650
651
# File 'lib/origen/pins/pin.rb', line 649

def suspended?
  @suspend
end

#to_be_captured?Boolean Also known as: to_be_stored?, is_to_be_stored?, is_to_be_captured?

Returns true if the (data) from the pin is marked to be captured

Returns:

  • (Boolean)


958
959
960
# File 'lib/origen/pins/pin.rb', line 958

def to_be_captured?
  state == :capture
end

#to_vectorObject

Returns the value held by the pin as a string formatted to the current tester's pattern syntax

Examples:


pin.drive_hi
pin.to_vector   # => "1"
pin.expect_lo
pin.to_vector   # => "L"


290
291
292
# File 'lib/origen/pins/pin.rb', line 290

def to_vector
  @vector_formatted_value ||= Origen.tester.format_pin_state(myself)
end

#toggleObject



933
934
935
936
937
# File 'lib/origen/pins/pin.rb', line 933

def toggle
  unless state == :dont_care
    set_value(value == 0 ? 1 : 0)
  end
end

#toggle!Object



939
940
941
942
# File 'lib/origen/pins/pin.rb', line 939

def toggle!
  toggle
  cycle
end

#toggle_clockObject



1048
1049
1050
1051
1052
# File 'lib/origen/pins/pin.rb', line 1048

def toggle_clock
  fail "ERROR: Clock on #{@owner.name} not running." unless is_a_running_clock?

  @clock.toggle
end

#update_clockObject



1021
1022
1023
# File 'lib/origen/pins/pin.rb', line 1021

def update_clock
  @clock.update_clock
end

#update_packages(options = {}) ⇒ Object Also known as: update_package

Add a way to update packages for the pins after the pins have been added.

dut.add_pin :p1 dut.add_package: package1 dut.add_package: package2 dut.pin(:p1).packages # => {} dut.pin(:p1).update_packages :packages # => [:package1, :package2] dut.pin(:p1).packages # => :package1=>{, :package2=>{}}

Examples:

Updating a package after the pin has been added



455
456
457
458
459
460
461
# File 'lib/origen/pins/pin.rb', line 455

def update_packages(options = {})
  packages = resolve_packages(options)
  packages.each do |package_id|
    package_id = package_id.respond_to?(:id) ? package_id.id : package_id
    myself.packages[package_id] ||= {}
  end
end

#valueObject Also known as: data



639
640
641
# File 'lib/origen/pins/pin.rb', line 639

def value
  @value
end

#vector_formatted_value=(val) ⇒ Object

Set the pin value and state from a string formatted to the current tester's pattern syntax, this is the opposite of the to_vector method

Examples:


pin.vector_formatted_value = "L"
pin.driving?                      # => false
pin.value                         # => 0
pin.vector_formatted_value = "1"
pin.driving?                      # => true
pin.value                         # => 1


311
312
313
314
315
316
# File 'lib/origen/pins/pin.rb', line 311

def vector_formatted_value=(val)
  unless @vector_formatted_value == val
    Origen.tester.update_pin_from_formatted_state(myself, val)
    @vector_formatted_value = val
  end
end