module Origen::SubBlocks
Public Class Methods
# File lib/origen/sub_blocks.rb, line 44 def self.lazy=(value) @lazy = value end
Returns the default
# File lib/origen/sub_blocks.rb, line 40 def self.lazy? @lazy || false end
Public Instance Methods
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
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 all sub_blocks
by emptying the Hash
# File lib/origen/sub_blocks.rb, line 253 def delete_sub_blocks @sub_blocks = {} end
# File lib/origen/sub_blocks.rb, line 281 def has_fuses? fuses.empty? ? false : true end
# File lib/origen/sub_blocks.rb, line 285 def has_tests? tests.empty? ? false : true end
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
# File lib/origen/sub_blocks.rb, line 427 def namespace self.class.to_s.sub(/::[^:]*$/, '') end
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
# 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
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
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
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
# File lib/origen/sub_blocks.rb, line 257 def sub_blocks_array sub_blocks.map { |_name, sub_block| sub_block } end
Private Instance Methods
@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
# 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