module Origen::Specs

Constants

FEATURE_TYPES
NOTE_TYPES
SPEC_TYPES

Added :impedance and :power to the spec types

SpecTableAttr

Attributes

_creation_info[W]
_doc_resources[W]
_documentation[W]
_exhibits[W]
_mode_selects[W]
_notes[W]
_overrides[W]
_power_supplies[W]
_spec_features[W]
_specs[W]
_version_history[W]
description[RW]

Detailed description for the ip block

Public Instance Methods

creation_info(author, date, version, src_info = {}, tool_info = {}) click to toggle source
# File lib/origen/specs.rb, line 216
def creation_info(author, date, version, src_info = {}, tool_info = {})
  # Create a new Information Information.  Should only be one.
  @_creation_info = Creation_Info.new(author, date, version, src_info, tool_info)
end
delete_all_doc_resources() click to toggle source
# File lib/origen/specs.rb, line 528
def delete_all_doc_resources
  @_doc_resources = nil
end
delete_all_documentation() click to toggle source
# File lib/origen/specs.rb, line 556
def delete_all_documentation
  @_documentation = nil
end
delete_all_exhibits() click to toggle source

Delete all exhibits

# File lib/origen/specs.rb, line 524
def delete_all_exhibits
  @_exhibits = nil
end
delete_all_mode_selects() click to toggle source
# File lib/origen/specs.rb, line 544
def delete_all_mode_selects
  @_mode_selects = nil
end
delete_all_notes() click to toggle source

Delete all notes

# File lib/origen/specs.rb, line 519
def delete_all_notes
  @_notes = nil
end
delete_all_overrides() click to toggle source
# File lib/origen/specs.rb, line 532
def delete_all_overrides
  @_overrides = nil
end
delete_all_power_supplies() click to toggle source
# File lib/origen/specs.rb, line 536
def delete_all_power_supplies
  @_power_supplies = nil
end
delete_all_specs() click to toggle source

Delete all specs

# File lib/origen/specs.rb, line 514
def delete_all_specs
  @_specs = nil
end
delete_all_version_history() click to toggle source
# File lib/origen/specs.rb, line 540
def delete_all_version_history
  @_version_history = nil
end
delete_creation_info() click to toggle source
# File lib/origen/specs.rb, line 548
def delete_creation_info
  @_creation_info = nil
end
delete_spec_features() click to toggle source
# File lib/origen/specs.rb, line 552
def delete_spec_features
  @_spec_features = nil
end
doc_resource(selector = {}, table_title = {}, text = {}, options = {}) click to toggle source
# File lib/origen/specs.rb, line 169
def doc_resource(selector = {}, table_title = {}, text = {}, options = {})
  # Welguisz:  No idea why this is here, but keeping it here because it follows other blocks
  _doc_resources
  mode = selector[:mode]
  type = selector[:type]
  sub_type = selector[:sub_type]
  audience = selector[:audience]
  # Create a new Document Resource and place it in the Doc Resources 4-D Hash
  @_doc_resources[mode][type][sub_type][audience] = Doc_Resource.new(selector, table_title, text, options)
end
doc_resources(options = {}) click to toggle source
# File lib/origen/specs.rb, line 312
def doc_resources(options = {})
  options = {
    mode:     nil,
    type:     nil,
    sub_type: nil,
    audience: nil
  }.update(options)
  return nil if @_doc_resources.nil?
  return nil if @_doc_resources.empty?

  dr_found = Hash.new do |h, k|
    h[k] = Hash.new do |hh, kk|
      hh[kk] = Hash.new do |hhh, kkk|
        hhh[kkk] = {}
      end
    end
  end
  filter_hash(@_doc_resources, options[:mode]).each do |_mode, hash|
    filter_hash(hash, options[:type]).each do |_type, hash_|
      filter_hash(hash_, options[:sub_type]).each do |_sub_type, hash__|
        filter_hash(hash__, options[:audience]).each do |_audience, spec|
          dr_found[_mode][_type][_sub_type][_audience] = spec
        end
      end
    end
  end
  if dr_found.empty?
    nil
  else
    dr_found
  end
end
documentation(header_info, selection, applicable_devices, link) click to toggle source

Adds a new documentation notion to the block

# File lib/origen/specs.rb, line 140
def documentation(header_info, selection, applicable_devices, link)
  _documentation
  # Create a new documenation and place it in the 5-D hash
  @_documentation[header_info[:section]][header_info[:subsection]][selection[:interface]][selection[:type]][selection[:sub_type]][selection[:mode]][selection[:audience]] = Documentation.new(header_info, selection, applicable_devices, link)
end
documentations(options = {}) click to toggle source
# File lib/origen/specs.rb, line 345
def documentations(options = {})
  options = {
    section:    nil,
    subsection: nil,
    interface:  nil,
    mode:       nil,
    type:       nil,
    sub_type:   nil,
    audience:   nil
  }.update(options)
  return nil if @_documentation.nil?
  return nil if @_documentation.empty?

  doc_found = Hash.new do |h, k|
    h[k] = Hash.new do |hh, kk|
      hh[kk] = Hash.new do |hhh, kkk|
        hhh[kkk] = Hash.new do |hhhh, kkkk|
          hhhh[kkkk] = Hash.new do |hhhhh, kkkkk|
            hhhhh[kkkkk] = Hash.new do |hhhhhh, kkkkkk|
              hhhhhh[kkkkkk] = {}
            end
          end
        end
      end
    end
  end
  filter_hash(@_documentation, options[:section]).each do |_section, hash|
    filter_hash(hash, options[:subsection]).each do |_subsection, hash_|
      filter_hash(hash_, options[:interface]).each do |_interface, hash__|
        filter_hash(hash__, options[:type]).each do |_type, hash___|
          filter_hash(hash___, options[:sub_type]).each do |_sub_type, hash____|
            filter_hash(hash____, options[:mode]).each do |_mode, hash_____|
              filter_hash(hash_____, options[:audience]).each do |_audience, doc|
                doc_found[_section][_subsection][_interface][_type][_sub_type][_mode][_audience] = doc
              end
            end
          end
        end
      end
    end
  end
  if doc_found.empty?
    nil
  else
    doc_found
  end
end
exhibit(id, type, overrides = {}, options = {}) click to toggle source
# File lib/origen/specs.rb, line 162
def exhibit(id, type, overrides = {}, options = {})
  # Welguisz:  No idea why this is here, but keeping it here because it follows other blocks
  _exhibits
  # Create a new Exhibit and place it in the exhibits 3-D Hash
  @_exhibits[options[:block_id]][id][type] = Exhibit.new(id, type, overrides, options)
end
exhibits(options = {}) click to toggle source
# File lib/origen/specs.rb, line 284
def exhibits(options = {})
  options = {
    block: nil,
    id:    nil,
    type:  nil
  }.update(options)
  return nil if @_exhibits.nil?
  return nil if @_exhibits.empty?

  ex_found = Hash.new do |h, k|
    h[k] = Hash.new do |hh, kk|
      hh[kk] = {}
    end
  end
  filter_hash(@_exhibits, options[:block]).each do |_block, hash|
    filter_hash(hash, options[:id]).each do |_id, hash_|
      filter_hash(hash_, options[:type]).each do |_type, exh|
        ex_found[_block][_id][_type] = exh
      end
    end
  end
  if ex_found.empty?
    nil
  else
    ex_found
  end
end
get_creation_info() click to toggle source
# File lib/origen/specs.rb, line 221
def get_creation_info
  @_creation_info
end
get_modes() click to toggle source

Returns the modes for this block

# File lib/origen/specs.rb, line 120
def get_modes
  @_modes
end
has_spec?(s, options = {}) click to toggle source

Check if the current IP has a spec

# File lib/origen/specs.rb, line 125
def has_spec?(s, options = {})
  _specs
  options = {
    type:          nil,
    sub_type:      nil,
    mode:          current_mode.nil? ? nil : current_mode.name,
    spec:          nil,
    symbol:        false,
    creating_spec: false
  }.update(options)
  options[:spec] = s
  !!show_specs(options)
end
has_specs?(options = {}) click to toggle source

Returns Boolean based on whether the calling object has any defined specs If the mode option is selected then the search is narrowed

# File lib/origen/specs.rb, line 102
def has_specs?(options = {})
  _specs
  options = {
    type:          nil,
    sub_type:      nil,
    mode:          current_mode.nil? ? nil : current_mode.name,
    spec:          nil,
    symbol:        false,
    creating_spec: false
  }.update(options)
  if @_specs.nil? || @_specs == {}
    false
  else
    !!show_specs(options)
  end
end
info() click to toggle source
# File lib/origen/specs.rb, line 509
def info
  @_creation_info
end
mode_select(block_information, mode_usage, power_information) click to toggle source
# File lib/origen/specs.rb, line 207
def mode_select(block_information, mode_usage, power_information)
  # Welguisz:  No idea why this is here, but keeping it here because it follows other blocks
  _mode_selects
  # See if the mode will be used.  If so, create a new Mode Select and place it in mode_selects 2-D Hash
  if block_information[:usage]
    @_mode_selects[block_information[:name]][mode_usage[:mode]] = Mode_Select.new(block_information, mode_usage, power_information)
  end
end
mode_selects(options = {}) click to toggle source
# File lib/origen/specs.rb, line 431
def mode_selects(options = {})
  options = {
    block: nil,
    mode:  nil
  }.update(options)
  return nil if @_mode_selects.nil?
  return nil if @_mode_selects.empty?

  modes_found = Hash.new do |h, k|
    h[k] = {}
  end
  filter_hash(@_mode_selects, options[:block]).each do |block, hash|
    filter_hash(hash, options[:mode]).each do |mode, sel|
      modes_found[block][mode] = sel
    end
  end
  if modes_found.empty?
    nil
  else
    modes_found
  end
end
note(id, type, options = {}) click to toggle source

Define and instantiate a Note object

# File lib/origen/specs.rb, line 155
def note(id, type, options = {})
  # Welguisz:  No idea why this is here, but keeping it here because it follows other blocks
  _notes
  # Create a new note and place it in the notes 2-D Hash
  @_notes[id][type] = Note.new(id, type, options)
end
notes(options = {}) click to toggle source

Returns a Note object from the notes hash

# File lib/origen/specs.rb, line 226
def notes(options = {})
  # Create a default 2 item hash and update if options is supplied
  options = {
    id:   nil,
    type: nil
  }.update(options)
  return nil if @_notes.nil?
  return nil if @_notes.empty?

  # Empty 2-D Hash to be used for notes found based on id and type
  notes_found = Hash.new do |h, k|
    # h is the id portion of the hash
    # k is the type portion of the hash
    h[k] = {}
  end
  # Filter @notes based off of the id
  filter_hash(@_notes, options[:id]).each do |id, hash|
    # Filter hash based off of the type
    filter_hash(hash, options[:type]).each do |type, note|
      # Store the note into note_found
      notes_found[id][type] = note
    end
  end
  if notes_found.empty?
    nil
  elsif notes_found.size == 1
    notes_found.values.first.values.first
  else
    notes_found
  end
end
override(block_options = {}, find_spec = {}, values = {}, options = {}) click to toggle source
# File lib/origen/specs.rb, line 188
def override(block_options = {}, find_spec = {}, values = {}, options = {})
  # Welguisz:  No idea why this is here, but keeping it here because it follows other blocks
  _overrides
  block = block_options[:block]
  spec_ref = find_spec[:spec_id]
  mode_ref = find_spec[:mode_ref]
  sub_type = find_spec[:sub_type]
  audience = find_spec[:audience]
  # Create a new Override and place it in the overrides 5-D Hash
  @_overrides[block][spec_ref][mode_ref][sub_type][audience] = Override.new(block_options, find_spec, values, options)
end
overrides(options = {}) click to toggle source
# File lib/origen/specs.rb, line 393
def overrides(options = {})
  options = {
    block:    nil,
    spec_ref: nil,
    mode_ref: nil,
    sub_type: nil,
    audience: nil
  }.update(options)
  return nil if @_overrides.nil?
  return nil if @_overrides.empty?

  overrides_found = Hash.new do |h, k|
    h[k] = Hash.new do |hh, kk|
      hh[kk] = Hash.new do |hhh, kkk|
        hhh[kkk] = Hash.new do |hhhh, kkkk|
          hhhh[kkkk] = {}
        end
      end
    end
  end
  filter_hash(@_overrides, options[:block]).each do |_block, hash|
    filter_hash(hash, options[:spec_ref]).each do |_spec_ref, hash_|
      filter_hash(hash_, options[:mode_ref]).each do |_mode_ref, hash__|
        filter_hash(hash__, options[:sub_type]).each do |_sub_type, hash___|
          filter_hash(hash___, options[:audience]).each do |_audience, override|
            overrides_found[_block][_spec_ref][_mode_ref][_sub_type][_audience] = override
          end
        end
      end
    end
  end
  if overrides_found.empty?
    nil
  else
    overrides_found
  end
end
power_supplies(options = {}) click to toggle source
# File lib/origen/specs.rb, line 454
def power_supplies(options = {})
  options = {
    gen: nil,
    act: nil
  }.update(options)
  ps_found = Hash.new do |h, k|
    h[k] = {}
  end
  return nil if @_power_supplies.nil?
  return nil if @_power_supplies.empty?

  filter_hash(@_power_supplies, options[:gen]).each do |gen, hash|
    filter_hash(hash, options[:act]).each do |act, sel|
      ps_found[gen][act] = sel
    end
  end
  if ps_found.empty?
    nil
  else
    ps_found
  end
end
power_supply(gen, act) click to toggle source
# File lib/origen/specs.rb, line 200
def power_supply(gen, act)
  # Welguisz:  No idea why this is here, but keeping it here because it follows other blocks
  _power_supplies
  # Create a new Power Supply and place it in the power supplies 2-D Hash
  @_power_supplies[gen][act] = Power_Supply.new(gen, act)
end
spec(name, type = nil, mode = nil, &block) click to toggle source

Define and instantiate a Spec object

# File lib/origen/specs.rb, line 69
def spec(name, type = nil, mode = nil, &block)
  return specs(name, type) unless block_given?
  fail 'A type argument is required when defining a spec!' unless type

  _specs
  name = name_audit(name)
  fail 'Specification names must be of SPEC_TYPES Symbol or String and cannot start with a number' if name.nil?
  fail "Spec type must be one of #{SPEC_TYPES.join(', ')}" unless SPEC_TYPES.include? type

  type = type
  mode = get_mode if mode.nil?
  owner_name = ''
  if respond_to?(:name) && send(:name)
    owner_name = self.name.to_s.downcase.to_sym
  elsif self == Origen.top_level
    owner_name = self.class.to_s.split('::').last.downcase.to_sym
  else
    owner_name = self.class.to_s.split('::').last.downcase.to_sym
  end
  spec_placeholder = Spec
                     .new(name, type, mode, owner_name, &block)
  # Check if the spec already exists
  if has_spec?(name, type: type, mode: mode, sub_type: spec_placeholder.sub_type, creating_spec: true)
    # Spec already exists.  Go ahead flag error and drop processing.
    # This is a fatal error.
    fail "Spec already exists for name: #{name}, type: #{type}, mode: #{mode} for object #{self}"
  end

  @_specs[name][mode][type][spec_placeholder.sub_type] = spec_placeholder
end
spec_feature(id, attrs, device, text, internal_comment) click to toggle source

Adds a new feature to the block

# File lib/origen/specs.rb, line 147
def spec_feature(id, attrs, device, text, internal_comment)
  # Welguisz:  No idea why this is here, but keeping it here because it follows other blocks
  _spec_features
  # Create a new feature and place it in the features 2-D Hash
  @_spec_features[id][device] = Spec_Features.new(id, attrs, device, text, internal_comment)
end
spec_features(options = {}) click to toggle source
# File lib/origen/specs.rb, line 258
def spec_features(options = {})
  options = {
    id:     nil,
    device: nil
  }.update(options)
  return @_spec_features if options[:id].nil? && options[:device].nil?
  return nil if @_spec_features.nil?
  return nil if @_spec_features.empty?

  features_found = Hash.new do |h, k|
    h[k] = {}
  end
  filter_hash(@_spec_features, options[:id]).each do |id, hash|
    filter_hash(hash, options[:device]).each do |device, feat|
      features_found[id][device] = feat
    end
  end
  if features_found.empty?
    nil
  elsif features_found.size == 1
    features_found.values.first.values.first
  else
    features_found
  end
end
specs(s = nil, options = {}) click to toggle source

Returns a hash of hash containing all specs/modes If no spec is specified then all specs are returned via inspect If a spec is specified, a spec object will be returned if found in the current mode. If a mode option is passed and no spec is passed it will filter the specs inspect display by the mode and visa-versa

# File lib/origen/specs.rb, line 45
def specs(s = nil, options = {})
  options = {
    type:          nil,
    sub_type:      nil,
    mode:          current_mode.nil? ? nil : current_mode.name,
    spec:          nil,
    symbol:        false,
    creating_spec: false
  }.update(options || {})
  _specs
  if s.nil?
    show_specs(options)
  elsif s.is_a? Hash
    # no spec was passed but some option was passed
    options.update(s)
    show_specs(options)
  else
    # a spec was passed
    options[:spec] = s
    show_specs(options)
  end
end
version_histories(options = {}) click to toggle source
# File lib/origen/specs.rb, line 477
def version_histories(options = {})
  options = {
    date:   nil,
    author: nil,
    label:  nil
  }.update(options)
  vh_found = Hash.new do |h, k|
    h[k] = Hash.new do |hh, kk|
      hh[kk] = {}
    end
  end
  return nil if @_version_history.nil?
  return nil if @_version_history.empty?

  filter_hash(@_version_history, options[:date]).each do |date, hash|
    filter_hash(hash, options[:author]).each do |author, hash1|
      filter_hash(hash1, options[:label]).each do |label, ver|
        vh_found[date][author][label] = ver
      end
    end
  end
  if vh_found.empty?
    nil
  else
    vh_found
  end
end
version_history(date, author, changes, label = nil, mark_external_internal = nil) click to toggle source
# File lib/origen/specs.rb, line 180
def version_history(date, author, changes, label = nil, mark_external_internal = nil)
  # Welguisz:  No idea why this is here, but keeping it here because it follows other blocks
  _version_history
  # Create a new Version History and place it in the version history 2-D Hash
  tmp_ver_history = Version_History.new(date, author, changes, label, mark_external_internal)
  @_version_history[date][author][label] = tmp_ver_history
end
versions() click to toggle source
# File lib/origen/specs.rb, line 505
def versions
  @_version_history
end

Private Instance Methods

_creation_info() click to toggle source
# File lib/origen/specs.rb, line 652
def _creation_info
  @_creation_info = nil
end
_doc_resources() click to toggle source
# File lib/origen/specs.rb, line 594
def _doc_resources
  @_doc_resources ||= Hash.new do |h, k|
    h[k] = Hash.new do |hh, kk|
      hh[kk] = Hash.new do |hhh, kkk|
        hhh[kkk] = {}
      end
    end
  end
end
_documentation() click to toggle source
# File lib/origen/specs.rb, line 604
def _documentation
  @_documentation ||= Hash.new do |h, k|
    h[k] = Hash.new do |hh, kk|
      hh[kk] = Hash.new do |hhh, kkk|
        hhh[kkk] = Hash.new do |hhhh, kkkk|
          hhhh[kkkk] = Hash.new do |hhhhh, kkkkk|
            hhhhh[kkkkk] = Hash.new do |hhhhhh, kkkkkk|
              hhhhhh[kkkkkk] = {}
            end
          end
        end
      end
    end
  end
end
_exhibits() click to toggle source
# File lib/origen/specs.rb, line 586
def _exhibits
  @_exhibits ||= Hash.new do |h, k|
    h[k] = Hash.new do |hh, kk|
      hh[kk] = {}
    end
  end
end
_mode_selects() click to toggle source
# File lib/origen/specs.rb, line 638
def _mode_selects
  @_mode_selects ||= Hash.new do |h, k|
    h[k] = {}
  end
end
_notes() click to toggle source

Two-dimensional hash with note id and type as the keys

# File lib/origen/specs.rb, line 574
def _notes
  @_notes ||= Hash.new do |h, k|
    h[k] = {}
  end
end
_overrides() click to toggle source
# File lib/origen/specs.rb, line 620
def _overrides
  @_overrides ||= Hash.new do |h, k|
    h[k] = Hash.new do |hh, kk|
      hh[kk] = Hash.new do |hhh, kkk|
        hhh[kkk] = Hash.new do |hhhh, kkkk|
          hhhh[kkkk] = {}
        end
      end
    end
  end
end
_power_supplies() click to toggle source
# File lib/origen/specs.rb, line 632
def _power_supplies
  @_power_supplies ||= Hash.new do |h, k|
    h[k] = {}
  end
end
_spec_features() click to toggle source
# File lib/origen/specs.rb, line 580
def _spec_features
  @_spec_features ||= Hash.new do |h, k|
    h[k] = {}
  end
end
_specs() click to toggle source
# File lib/origen/specs.rb, line 562
def _specs
  # 4D hash with name, type, mode, and sub_type as keys
  @_specs ||= Hash.new do |h, k|
    h[k] = Hash.new do |hh, kk|
      hh[kk] = Hash.new do |hhh, kkk|
        hhh[kkk] = {}
      end
    end
  end
end
_version_history() click to toggle source
# File lib/origen/specs.rb, line 644
def _version_history
  @_version_history ||= Hash.new do |h, k|
    h[k] = Hash.new do |hh, kk|
      hh[kk] = {}
    end
  end
end
filter_hash(hash, filter, debug = false) click to toggle source

Return a hash based on the filter provided

# File lib/origen/specs.rb, line 657
def filter_hash(hash, filter, debug = false)
  fail 'Hash argument is not a Hash!' unless hash.is_a? Hash

  filtered_hash = {}
  select_logic = case filter
    when String then 'k.nil? ? false : k[Regexp.new(filter)] && k.length == filter.length'
    when (Fixnum || Integer || Float || Numeric) then "k[Regexp.new('#{filter}')]"
    when Regexp then 'k[filter]'
    when Symbol then
      'k == filter'
    when NilClass then true # Return all specs if a filter is set to nil (i.e. user doesn't care about this filter)
    else true
                 end
  filtered_hash = hash.select do |k, v|
    # binding.pry if filter == 'SubSection A'
    [TrueClass, FalseClass].include?(select_logic.class) ? select_logic : eval(select_logic)
  end
  filtered_hash
end
show_specs(options = {}) click to toggle source

Filters the 4D hash to find specs for all user visible API

# File lib/origen/specs.rb, line 678
def show_specs(options = {})
  options = {
    mode:              nil,
    spec:              nil,
    type:              nil,
    sub_type:          nil,
    specs_to_be_shown: SpecArray.new,
    owner:             nil,
    symbol:            false,
    creating_spec:     false
  }.update(options)
  options[:symbol] ? symbol = options.delete(:spec) : symbol = nil
  specs_to_be_shown = options[:specs_to_be_shown]
  filter_hash(_specs, options[:spec]).each do |_spec, hash|
    filter_hash(hash, options[:mode]).each do |_mode, hash_|
      filter_hash(hash_, options[:type]).each do |_type, hash__|
        filter_hash(hash__, options[:sub_type]).each do |_sub_type, spec|
          if symbol
            if spec.symbol && (spec.symbol.gsub(/<.*?>/, '').downcase.to_sym == symbol)
              specs_to_be_shown << spec
            end
          else
            specs_to_be_shown << spec
          end
        end
      end
    end
  end
  # If no specs were found must check the possibility another search
  # should be started with mode set to :local or :global
  if specs_to_be_shown.empty?
    # Don't want to re-call this method if the callee is trying to create a spec and just wants to know
    # if there is a spec with the exact same options
    if options[:creating_spec] == false
      # Doesn't make sense to recall the method however if the mode is already set to :global or :local
      unless [:global, :local, nil].include?(options[:mode])
        # Need to check if there are :global or :local specs that match the filter(s) as well
        if self == Origen.top_level
          options[:mode] = :global
        else
          options[:mode] = :local
        end
        options[:specs_to_be_shown] = specs_to_be_shown
        Origen.log.debug "re-calling show_specs with options #{options}"
        return show_specs(options)
      end
    end
    Origen.log.debug "Returning no specs for options #{options}"
    nil
  elsif specs_to_be_shown.size == 1
    print_to_console(specs_to_be_shown) if options[:verbose] == true
    Origen.log.debug "returning one spec #{specs_to_be_shown.first.name}"
    specs_to_be_shown.first
  else
    Origen.log.debug "returning an array of specs during initial search: #{specs_to_be_shown}"
    specs_to_be_shown
  end
end
specs_to_table_string(specs_to_be_shown) click to toggle source

Method to print a spec table to the console

# File lib/origen/specs.rb, line 738
def specs_to_table_string(specs_to_be_shown)
  whitespace_padding = 3
  table = []
  attrs_to_be_shown = {
    name:        SpecTableAttr.new('Name', true, 'Name'.length + whitespace_padding),
    symbol:      SpecTableAttr.new('Symbol', false, 'Symbol'.length + whitespace_padding),
    mode:        SpecTableAttr.new('Mode',      true,  'Mode'.length + whitespace_padding),
    type:        SpecTableAttr.new('Type',      true,  'Type'.length + whitespace_padding),
    sub_type:    SpecTableAttr.new('Sub-Type', false, 'Sub-Type'.length + whitespace_padding),
    # spec SpecTableAttribute :description is called parameter in the spec table output to match historical docs
    description: SpecTableAttr.new('Parameter', false, 'Parameter'.length + whitespace_padding),
    min:         SpecTableAttr.new('Min',       false, 'Min'.length + whitespace_padding),
    typ:         SpecTableAttr.new('Typ',       false, 'Typ'.length + whitespace_padding),
    max:         SpecTableAttr.new('Max',       false, 'Max'.length + whitespace_padding),
    unit:        SpecTableAttr.new('Unit', false, 'Unit'.length + whitespace_padding),
    audience:    SpecTableAttr.new('Audience', false, 'Audience'.length + whitespace_padding)
    # notes:       SpecTableAttr.new('Notes',     false, 'Notes'.length + whitespace_padding)
  }
  # Calculate the padding needed in the spec table for the longest attr of all specs
  specs_to_be_shown.each do |spec|
    attrs_to_be_shown.each do |attr_name, attr_struct|
      unless spec.send(attr_name).nil?
        if spec.send(attr_name).class == Origen::Specs::Spec::Limit
          next if spec.send(attr_name).value.nil?

          current_padding = spec.send(attr_name).value.to_s.length + whitespace_padding
        else
          current_padding = spec.send(attr_name).to_s.length + whitespace_padding
        end
        attr_struct.padding = current_padding if attr_struct.padding < current_padding
        attr_struct.show = true # We found real data for this attr on at least one spec so show it in the spec table
      end
    end
  end
  # Now that each spec attribute padding construct the spec table header
  header = ''
  attrs_to_be_shown.each do |_attr_name, attr_struct|
    next if attr_struct.show == false

    header += "| #{attr_struct.table_text}".ljust(attr_struct.padding)
  end
  header += '|'
  ip_header = "| IP: #{specs_to_be_shown.first.ip_name} ".ljust(header.length - 1)
  ip_header += '|'
  table << '=' * header.length
  table << ip_header
  table << '=' * header.length
  table << header
  table << '-' * header.length
  # Create the data lines in the spec table
  specs_to_be_shown.each do |spec|
    data = ''
    attrs_to_be_shown.each do |attr_name, attr_struct|
      next if attr_struct.show == false

      if spec.send(attr_name).class == Origen::Specs::Spec::Limit
        data += "| #{spec.send(attr_name).value}".ljust(attr_struct.padding)
      else
        data += "| #{spec.send(attr_name)}".ljust(attr_struct.padding)
      end
    end
    table << data += '|'
  end
  table << '-' * header.length
  table.flatten.join("\n")
end