module Origen::SubBlocks

Public Class Methods

lazy=(value) click to toggle source
# File lib/origen/sub_blocks.rb, line 44
def self.lazy=(value)
  @lazy = value
end
lazy?() click to toggle source

Returns the default

# File lib/origen/sub_blocks.rb, line 40
def self.lazy?
  @lazy || false
end

Public Instance Methods

all_sub_blocks() click to toggle source

Returns an array containing all descendant child objects of the given sub-block, i.e. this returns an array containing children’s children as well

Note that this returns an array instead of a hash since there could be naming collisions in the hash keys

# File lib/origen/sub_blocks.rb, line 267
def all_sub_blocks
  @all_sub_blocks ||= (sub_blocks_array + sub_blocks_array.map(&:all_sub_blocks)).flatten
end
children(*args)
Alias for: sub_blocks
children_array()
Alias for: sub_blocks_array
custom_attrs() click to toggle source

Returns a hash containing all options that were passed to the sub_block definition

# File lib/origen/sub_blocks.rb, line 49
def custom_attrs
  @custom_attrs
end
delete_sub_blocks() click to toggle source

Delete all sub_blocks by emptying the Hash

# File lib/origen/sub_blocks.rb, line 253
def delete_sub_blocks
  @sub_blocks = {}
end
has_fuses?() click to toggle source
# File lib/origen/sub_blocks.rb, line 281
def has_fuses?
  fuses.empty? ? false : true
end
has_regs?()
Alias for: owns_registers?
has_tests?() click to toggle source
# File lib/origen/sub_blocks.rb, line 285
def has_tests?
  tests.empty? ? false : true
end
init_sub_blocks(*args) click to toggle source

This will be called whenever an object that includes this module is instantiated

@api private

# File lib/origen/sub_blocks.rb, line 7
def init_sub_blocks(*args)
  options = args.find { |a| a.is_a?(Hash) }
  @custom_attrs = (options ? options.dup : {}).with_indifferent_access
  # Delete these keys which are either meta data added by Origen or are already covered by
  # dedicated methods
  %w(parent name base_address reg_base_address base).each do |key|
    @custom_attrs.delete(key)
  end
  if options
    # Using reg_base_address for storage to avoid class with the original Origen base
    # address API, but will accept any of these
    @reg_base_address = options.delete(:reg_base_address) ||
                        options.delete(:base_address) || options.delete(:base) || 0
    if options[:_instance] # to be deprecated as part of multi-instance removal below
      if @reg_base_address.is_a?(Array)
        @reg_base_address = @reg_base_address[options[:_instance]]
      elsif options[:base_address_step]
        @reg_base_address = @reg_base_address + (options[:_instance] * options[:base_address_step])
      end
    end
    @domain_names = [options.delete(:domain) || options.delete(:domains)].flatten.compact
    @domain_specified = !@domain_names.empty?
    @path = options.delete(:path)
    @abs_path = options.delete(:abs_path) || options.delete(:absolute_path)
  end
  if is_a?(SubBlock)
    options.each do |k, v|
      send("#{k}=", v)
    end
  end
end
namespace() click to toggle source
# File lib/origen/sub_blocks.rb, line 427
def namespace
  self.class.to_s.sub(/::[^:]*$/, '')
end
owns_registers?() click to toggle source

Returns true if the given sub block owns at least one register

# File lib/origen/sub_blocks.rb, line 272
def owns_registers?
  if regs
    regs.is_a?(Origen::Registers::RegCollection) && !regs.empty?
  else
    false
  end
end
Also aliased as: has_regs?
sub_block(name = nil, options = {}) click to toggle source
# File lib/origen/sub_blocks.rb, line 289
def sub_block(name = nil, options = {})
  name, options = nil, name if name.is_a?(Hash)
  return sub_blocks unless name

  if name.is_a?(Class)
    return sub_blocks.select { |n, s| s.is_a?(name) }
  elsif name.origen_sub_block?
    return sub_block(name.class)
  end

  if i = options.delete(:instances)
    # permit creating multiple instances of a particular sub_block class
    # can pass array for base_address, which will be processed above
    Origen.deprecate 'instances: option to sub_block is deprecated, use sub_block_groups instead'
    group_name = name =~ /s$/ ? name : "#{name}s" # take care if name already with 's' is passed
    unless respond_to?(group_name)
      sub_block_groups group_name do
        i.times do |j|
          o = options.dup
          o[:_instance] = j
          sub_block("#{name}#{j}", o)
        end
      end
    end
  else
    block = Placeholder.new(self, name, options)
    # Allow additional attributes to be added to an existing sub-block if it hasn't
    # been instantiated yet. This is not supported yet for instantiated sub-blocks since
    # there are probably a lot more corner-cases to consider, and hopefully no one will
    # really need this anyway.
    # Note that override is to recreate an existing sub-block, not adding additional
    # attributes to an existing one
    if options[:override]
      sub_blocks.delete(name.to_s)
      if options[:class_name]
        constantizable = !!options[:class_name].safe_constantize
        # this is to handle the case where a previously instantiated subblock wont allow
        # the current class name to exist
        # e.g. NamespaceA::B::C
        # =>  NameSpaceX::Y::Z
        # After requiring the files, constants become sane again:
        # e.g. NamespaceA::B::C
        # =>  NameSpaceA::B::C
        if constantizable && (options[:class_name] != options[:class_name].constantize.to_s)
          block_dir = options[:block_file] || _find_block_dir(options)
          # files that aren't initializing a new namespace and have special loading shouldn't be required
          # the code they contain may try to call methods that dont exist yet
          skip_require_files = options[:skip_require_files] || %w(attributes parameters pins registers sub_blocks timesets)
          Dir.glob("#{block_dir}/*.rb").each do |file|
            next if skip_require_files.include?(Pathname.new(file).basename('.rb').to_s)

            require file
          end
        end
      end
    else
      if sub_blocks[name] && !sub_blocks[name].is_a?(Placeholder)
        fail "You have already defined a sub-block named #{name} within class #{self.class}"
      end
    end
    if respond_to?(name) && !(singleton_class.instance_methods.include?(name) && options[:override])
      callers = Origen.split_caller_line caller[0]
      Origen.log.warning "The sub_block defined at #{Pathname.new(callers[0]).relative_path_from(Pathname.pwd)}:#{callers[1]} is overriding an existing method called #{name}"
    end
    define_singleton_method name do
      sub_blocks[name]
    end
    if sub_blocks[name] && sub_blocks[name].is_a?(Placeholder)
      sub_blocks[name].add_attributes(options)
    else
      sub_blocks[name] = block
    end
    unless @current_group.nil? # a group is currently open, store sub_block id only
      @current_group << name
    end
    if options.key?(:lazy)
      lazy = options[:lazy]
    else
      lazy = Origen::SubBlocks.lazy?
    end
    lazy ? block : block.materialize
  end
end
sub_block_group(id, options = {}) { || ... } click to toggle source

Create a group of associated sub_blocks under a group name permits each sub_block to be of a different class e.g. sub_block_group :my_ip_group do

sub_block :ip0, class_name: 'IP0', base_address: 0x000000
sub_block :ip1, class_name: 'IP1', base_address: 0x000200
sub_block :ip2, class_name: 'IP2', base_address: 0x000400
sub_block :ip3, class_name: 'IP3', base_address: 0x000600

end

creates an array referenced by method called ‘my_ip_group’ which contains the sub_blocks ‘ip0’, ‘ip1’, ‘ip2’, ‘ip3’.

Can also indicate a custom class container to hold these. This custom class container MUST support a ‘<<’ method in order to add new sub_blocks to the container instance.

e.g. sub_block_group :my_ip_group, class_name: ‘MYGRP’ do

sub_block :ip0, class_name: 'IP0', base_address: 0x000000
sub_block :ip1, class_name: 'IP1', base_address: 0x000200
sub_block :ip2, class_name: 'IP2', base_address: 0x000400
sub_block :ip3, class_name: 'IP3', base_address: 0x000600

end

# File lib/origen/sub_blocks.rb, line 399
def sub_block_group(id, options = {})
  @current_group = []    # open group
  yield                  # any sub_block calls within this block will have their ID added to @current_group
  my_group = @current_group.dup
  if respond_to?(id)
    callers = Origen.split_caller_line caller[0]
    Origen.log.warning "The sub_block_group defined at #{Pathname.new(callers[0]).relative_path_from(Pathname.pwd)}:#{callers[1]} is overriding an existing method called #{id}"
  end
  # Define a singleton method which will be called every time the sub_block_group is referenced
  # This is not called here but later when referenced
  define_singleton_method "#{id}" do
    sub_block_groups[id]
  end
  # Instantiate group
  if options[:class_name]
    b = Object.const_get(options[:class_name]).new
  else
    b = [] # Will use Array if no class defined
  end
  # Add sub_blocks to group
  my_group.each do |group_id|
    b << send(group_id)
  end
  sub_block_groups[id] = b
  @current_group = nil # close group
end
Also aliased as: sub_blocks_group
sub_block_groups(*args, &block) click to toggle source

Returns a hash containing all sub block groups thus far added if no arguments given. If given a code block, will serve as alias to sub_block_group method. Does not handle arguments, no need at this time.

# File lib/origen/sub_blocks.rb, line 240
def sub_block_groups(*args, &block)
  if block_given?
    sub_block_group(*args, &block)
  else
    if args.empty?
      @sub_block_groups ||= {}.with_indifferent_access
    else
      fail 'sub_block_groups not meant to take arguments!'
    end
  end
end
sub_blocks(*args) click to toggle source

Returns a hash containing all immediate children of the given sub-block

# File lib/origen/sub_blocks.rb, line 227
def sub_blocks(*args)
  if args.empty?
    @sub_blocks ||= {}.with_indifferent_access
  else
    sub_block(*args)
  end
end
Also aliased as: children
sub_blocks_array() click to toggle source
# File lib/origen/sub_blocks.rb, line 257
def sub_blocks_array
  sub_blocks.map { |_name, sub_block| sub_block }
end
Also aliased as: children_array
sub_blocks_group(id, options = {})
Alias for: sub_block_group

Private Instance Methods

_find_block_dir(options, current_path = nil, remaining_namespace = nil) click to toggle source

@api private find the block directory path containing the namespace of options

# File lib/origen/sub_blocks.rb, line 435
def _find_block_dir(options, current_path = nil, remaining_namespace = nil)
  current_path ||= Pathname.new("#{Origen.root}/app/blocks")
  remaining_namespace ||= options[:class_name].split('::')[1..-1].map(&:underscore)
  current_namespace = remaining_namespace.shift
  if current_namespace
    if current_path.join(current_namespace).exist?
      _find_block_dir(options, current_path.join(current_namespace), remaining_namespace)
    elsif current_path.join("derivatives/#{current_namespace}").exist?
      _find_block_dir(options, current_path.join("derivatives/#{current_namespace}"), remaining_namespace)
    elsif current_path.join("sub_blocks/#{current_namespace}").exist?
      _find_block_dir(options, current_path.join("sub_blocks/#{current_namespace}"), remaining_namespace)
    else
      Origen.log.error "Could not find block dir for namespace #{options[:class_name]}!"
      fail
    end
  else
    if current_path.join('model.rb').exist?
      current_path.to_s
    else
      Origen.log.error "Could not find block dir for namespace #{options[:class_name]}!"
      fail
    end
  end
end
instantiate_sub_block(name, klass, options) click to toggle source
# File lib/origen/sub_blocks.rb, line 460
def instantiate_sub_block(name, klass, options)
  return sub_blocks[name] unless sub_blocks[name].is_a?(Placeholder)

  sub_blocks[name] = klass.new(options.merge(parent: self, name: name))
end