def add_pin(id = nil, options = {}, &_block)
      id, options = nil, id if id.is_a?(Hash)
      power_pin = options.delete(:power_pin)
      ground_pin = options.delete(:ground_pin)
      virtual_pin = options.delete(:virtual_pin)
      other_pin = options.delete(:other_pin)
      if options[:size] && options[:size] > 1
        group = PinCollection.new(self, options.merge(placeholder: true))
        group.id = id if id
        options = {
          name: ''
        }.merge(options)

        rtl_name = options[:rtl_name]
        force = options[:force]
        offset = options.delete(:offset) || 0
        options.delete(:size).times do |i|
          pin_index = offset + i
          options[:name] = "#{id}#{pin_index}".to_sym
          options[:rtl_name] = "#{rtl_name}#{pin_index}".to_sym if rtl_name
          options[:force] = force[pin_index] if force

          if power_pin
            group[i] = PowerPin.new(pin_index, self, options)
          elsif ground_pin
            group[i] = GroundPin.new(pin_index, self, options)
          elsif virtual_pin
            group[i] = VirtualPin.new(pin_index, self, options)
          elsif other_pin
            group[i] = OtherPin.new(pin_index, self, options)
          else
            group[i] = Pin.new(pin_index, self, options)
          end
          group[i].invalidate_group_cache
        end
        yield group if block_given?
        group.each do |pin|
          pin.send(:primary_group_index=, pin.id)
          pin.id = "#{group.id}#{pin.id}".to_sym
          pin.send(:primary_group=, group)
          pin.finalize
        end
        if group.size == 1
          Origen.pin_bank.add_pin(group.first, self, options)
        else
          Origen.pin_bank.add_pin_group(group, self, options)
        end
      else
        if power_pin
          pin = PowerPin.new(id || :temp, self, options)
        elsif ground_pin
          pin = GroundPin.new(id || :temp, self, options)
        elsif virtual_pin
          pin = VirtualPin.new(id || :temp, self, options)
        elsif other_pin
          pin = OtherPin.new(id || :temp, self, options)
        else
          pin = Pin.new(id || :temp, self, options)
        end
        yield pin if block_given?
        pin.finalize
        Origen.pin_bank.add_pin(pin, self, options)
      end
    end
def add_pin(id = nil, options = {}, &_block)
      id, options = nil, id if id.is_a?(Hash)
      power_pin = options.delete(:power_pin)
      ground_pin = options.delete(:ground_pin)
      virtual_pin = options.delete(:virtual_pin)
      other_pin = options.delete(:other_pin)
      if options[:size] && options[:size] > 1
        group = PinCollection.new(self, options.merge(placeholder: true))
        group.id = id if id
        options = {
          name: ''
        }.merge(options)

        rtl_name = options[:rtl_name]
        force = options[:force]
        offset = options.delete(:offset) || 0
        options.delete(:size).times do |i|
          pin_index = offset + i
          options[:name] = "#{id}#{pin_index}".to_sym
          options[:rtl_name] = "#{rtl_name}#{pin_index}".to_sym if rtl_name
          options[:force] = force[pin_index] if force

          if power_pin
            group[i] = PowerPin.new(pin_index, self, options)
          elsif ground_pin
            group[i] = GroundPin.new(pin_index, self, options)
          elsif virtual_pin
            group[i] = VirtualPin.new(pin_index, self, options)
          elsif other_pin
            group[i] = OtherPin.new(pin_index, self, options)
          else
            group[i] = Pin.new(pin_index, self, options)
          end
          group[i].invalidate_group_cache
        end
        yield group if block_given?
        group.each do |pin|
          pin.send(:primary_group_index=, pin.id)
          pin.id = "#{group.id}#{pin.id}".to_sym
          pin.send(:primary_group=, group)
          pin.finalize
        end
        if group.size == 1
          Origen.pin_bank.add_pin(group.first, self, options)
        else
          Origen.pin_bank.add_pin_group(group, self, options)
        end
      else
        if power_pin
          pin = PowerPin.new(id || :temp, self, options)
        elsif ground_pin
          pin = GroundPin.new(id || :temp, self, options)
        elsif virtual_pin
          pin = VirtualPin.new(id || :temp, self, options)
        elsif other_pin
          pin = OtherPin.new(id || :temp, self, options)
        else
          pin = Pin.new(id || :temp, self, options)
        end
        yield pin if block_given?
        pin.finalize
        Origen.pin_bank.add_pin(pin, self, options)
      end
    end
Use this method to add any pins that are considered owned by the given object.
 Pins declared via this method will be accessible within the object via
 pin(:pinname) or if you prefer self.pin(:pinname). Externally you would refer
 to it via $top.pin(:pinname) or $soc.pin(:pinname) or even
 $top.sub_module.pin(:pinname) depending on where you called this method.
 Pins are output in the pattern in the order that they are declared.
 A minimum declaration is this:
   add_pin  :d_out        # A single pin that will be set to :dont_care by default
 To set the initial state at the same time:
   add_pin  :d_in,   :reset => :drive_hi
   add_pin  :invoke, :reset => :drive_lo
 You can override the name that appears in the pattern by providing a string
 as the last argument
   add_pin  :done,   :reset => :expect_hi, :name => "bist_done"
   add_pin  :fail,                         :name => "bist_fail"