module Origen::Registers

Origen provides a powerful register class which you are encouraged to use when you wish to interact with a silicon register (or RAM location). By interacting with the register on silicon through the register API your pattern will automatically track silicon state, so you can set and forget bits in the patgen the same as you would do with a physical register. Include this module to add registers to your block, then use the macros described below to instantiate register objects

include Origen::Registers

Attributes

bit_order[W]
name[RW]
owner[RW]

Public Class Methods

bit_metadata() click to toggle source

@api private Returns a lookup table containing all custom bit metadata defined by objects in an application

# File lib/origen/registers.rb, line 84
def bit_metadata
  @@bit_metadata ||= {}
end
default_bit_meta_data(*args, &block) click to toggle source

An alias for default_bit_metadata

# File lib/origen/registers.rb, line 116
def default_bit_meta_data(*args, &block)
  default_bit_metadata(*args, &block)
end
default_bit_metadata() { |collector| ... } click to toggle source

Can be called to add app specific meta data to all bits

# File lib/origen/registers.rb, line 105
def default_bit_metadata
  Origen::Registers.bit_metadata[:global] ||= {}
  if block_given?
    collector = Origen::Utility::Collector.new
    yield collector
    Origen::Registers.bit_metadata[:global].merge!(collector.to_h)
  end
  Origen::Registers.bit_metadata[:global]
end
default_reg_meta_data(*args, &block) click to toggle source

An alias for default_reg_metadata

# File lib/origen/registers.rb, line 100
def default_reg_meta_data(*args, &block)
  default_reg_metadata(*args, &block)
end
default_reg_metadata() { |collector| ... } click to toggle source

Can be called to add app specific meta data to all registers

# File lib/origen/registers.rb, line 89
def default_reg_metadata
  Origen::Registers.reg_metadata[:global] ||= {}
  if block_given?
    collector = Origen::Utility::Collector.new
    yield collector
    Origen::Registers.reg_metadata[:global].merge!(collector.to_h)
  end
  Origen::Registers.reg_metadata[:global]
end
reg_metadata() click to toggle source

@api private Returns a lookup table containing all custom register metadata defined by objects in an application

# File lib/origen/registers.rb, line 77
def reg_metadata
  @@reg_metadata ||= {}
end

Public Instance Methods

_registers() click to toggle source

All register objects are stored here, but they should be accessed via the _reg method to ensure that feature scoping is applied

@api private

# File lib/origen/registers.rb, line 125
def _registers
  @_registers ||= RegCollection.new(self)
end
add_reg(id, address, size = nil, bit_info = {}) { |self| ... } click to toggle source

Add a register. When adding a register you must supply a name, an address, size in bits, and bit definitions, any bits that are not declared will be filled with dummy bit objects that are not writable and will read back as 0.

@example

          Name    Address  Size   Bit Definitions
add_reg :control,  0x00,    16    :mode    => { :pos => 8, :bits => 8 },
                                  # Leaving out bits does 1 by default
                                  :launch  => { :pos => 6 },
                                  # The default reset state is 0, specify an alternative..
                                  :status  => { :pos => 4, :bits => 2, :res => 0b11 },
                                  :fail    => { :pos => 2 },
                                  :done    => { :pos => 0 }

Can be called on any object to add a register to it

# File lib/origen/registers.rb, line 308
def add_reg(id, address, size = nil, bit_info = {}, &_block)
  if address.is_a?(Hash)
    fail 'add_reg requires the address to be supplied as the 2nd argument, e.g. add_reg :my_reg, 0x1000'
  end

  size, bit_info = nil, size if size.is_a?(Hash)
  size ||= bit_info.delete(:size) || 32
  description = bit_info.delete(:description)

  local_vars = {}

  Reg::REG_LEVEL_ATTRIBUTES.each do |attribute, meta|
    aliases = [attribute[1..-1].to_sym]
    aliases += meta[:aliases] if meta[:aliases]
    aliases.each { |_a| local_vars[attribute] = bit_info.delete(_a) if bit_info.key?(_a) }
  end

  local_vars[:_reset] ||= :memory if local_vars[:_memory]
  @min_reg_address ||= address
  @max_reg_address ||= address
  # Must set an initial value, otherwise max_address_reg_size will be nil if a sub_block contains only
  # a single register.
  @max_address_reg_size ||= size
  @min_reg_address = address if address < @min_reg_address
  if address > @max_reg_address
    @max_address_reg_size = size
    @max_reg_address = address
  end
  @reg_define_file ||= define_file(caller[0])

  if block_given?
    @new_reg_attrs = { meta: bit_info }
    yield self
    bit_info = @new_reg_attrs
  else
    # If no block given then init with all writable bits unless bit_info has
    # been supplied
    unless bit_info.any? { |k, v| v.is_a?(Hash) && v[:pos] }
      bit_info = { d: { pos: 0, bits: size }.merge(bit_info) }
    end
  end
  if _registers[id] && Origen.config.strict_errors
    puts ''
    puts "Add register error, you have already added a register named #{id} to #{self.class}"
    puts ''
    fail 'Duplicate register error!'
  else
    attributes = {
      define_file: @reg_define_file,
      address:     address,
      size:        size,
      bit_info:    bit_info,
      description: description
    }
    Reg::REG_LEVEL_ATTRIBUTES.each do |attribute, _meta|
      attributes[attribute] = local_vars[attribute]
    end
    _registers[id] = Placeholder.new(self, id, attributes)
  end
  @reg_define_file = nil
end
add_reg32(id, address, args = {}, &block) click to toggle source
# File lib/origen/registers.rb, line 463
def add_reg32(id, address, args = {}, &block)
  @reg_define_file = define_file(caller[0])
  add_reg(id, address, 32, args, &block)
end
bit(index, name, attrs = {}) click to toggle source

Called within an add_reg block to define bits

# File lib/origen/registers.rb, line 386
def bit(index, name, attrs = {})
  if index.is_a?(Range)
    msb = index.first
    lsb = index.last
    msb, lsb = lsb, msb if lsb > msb
    pos = lsb
    bits = (msb - lsb).abs + 1
  elsif index.is_a?(Numeric)
    pos = index
    bits = 1
  else
    fail 'No valid index supplied when defining a register bit!'
  end

  # Traynor, this could be more elegant
  # its just a dirty way to make the value of the
  # key in @new_reg_atts hash array (ie name) tie to
  # a value that is an array of hashes describing
  # data for each scrambled bit
  attrs = attrs.merge(pos: pos, bits: bits)
  temparray = []
  if @new_reg_attrs[name].nil?
    @new_reg_attrs[name] = attrs
  else
    if @new_reg_attrs[name].is_a? Hash
      temparray.push(@new_reg_attrs[name])
    else
      temparray = @new_reg_attrs[name]
    end
    temparray.push(attrs)
    # added the sort so that the order the registers bits is described is not important
    @new_reg_attrs[name] = temparray.sort { |a, b| b[:pos] <=> a[:pos] }

  end
end
Also aliased as: bits
bit_order() click to toggle source

Returns the bit order attribute of the model (either :msb0 or :lsb0). If not explicitly defined on this model it will be inherited from the parent and will default to :lsb0 at the top-level

# File lib/origen/registers.rb, line 33
def bit_order
  @bit_order ||= if parent
                   parent.bit_order
                 else
                   :lsb0
                 end
end
bits(index, name, attrs = {})
Alias for: bit
contains_bits?(obj) click to toggle source

Returns true if the given object is one of the recognized Origen bit containers (bit collection, reg or container).

# File lib/origen/registers.rb, line 283
def contains_bits?(obj)
  obj.respond_to?(:contains_bits?) && obj.contains_bits?
end
default_bit_meta_data()
default_bit_metadata() { |collector| ... } click to toggle source
# File lib/origen/registers.rb, line 437
def default_bit_metadata
  Origen::Registers.bit_metadata[self.class] ||= {}
  if block_given?
    collector = Origen::Utility::Collector.new
    yield collector
    Origen::Registers.bit_metadata[self.class].merge!(collector.to_h)
  end
  Origen::Registers.bit_metadata[self.class]
end
Also aliased as: default_bit_meta_data
default_reg_meta_data()
default_reg_metadata() { |collector| ... } click to toggle source

Can be called to add app specific meta data that is isolated to all registers defined within a given class

# File lib/origen/registers.rb, line 426
def default_reg_metadata
  Origen::Registers.reg_metadata[self.class] ||= {}
  if block_given?
    collector = Origen::Utility::Collector.new
    yield collector
    Origen::Registers.reg_metadata[self.class].merge!(collector.to_h)
  end
  Origen::Registers.reg_metadata[self.class]
end
Also aliased as: default_reg_meta_data
define_file(file) click to toggle source

@api private

# File lib/origen/registers.rb, line 376
def define_file(file)
  if Origen.running_on_windows?
    fields = file.split(':')
    "#{fields[0]}:#{fields[1]}"
  else
    file.split(':').first
  end
end
del_reg(id) click to toggle source

Delete an existing register

# File lib/origen/registers.rb, line 371
def del_reg(id)
  _registers.delete(id)
end
delete_registers() click to toggle source
# File lib/origen/registers.rb, line 65
def delete_registers
  @_registers = nil
end
dummy_reg(size = 16) click to toggle source

Creates a dummy register. Equivalent to Reg.dummy except the reg owner is assigned as the caller rather than Reg. Use this if you need to call read! or write! on the dummy register object.

# File lib/origen/registers.rb, line 667
def dummy_reg(size = 16)
  Reg.new(self, 0, size, :dummy, init_as_writable: true)
end
has_reg(name, params = {})
Alias for: has_reg?
has_reg?(name, params = {}) click to toggle source

Returns true if the object contains a register matching the given name

# File lib/origen/registers.rb, line 491
def has_reg?(name, params = {})
  params = {
    test_for_true_false: true
  }.update(params)
  if params.key?(:enabled_features) || params.key?(:enabled_feature)
    !!get_registers(params).include?(name)
  else
    params[:enabled_features] = :default
    !!get_registers(params).include?(name)
  end
end
Also aliased as: has_reg
instantiate_reg(id, attrs) click to toggle source

@api private

# File lib/origen/registers.rb, line 449
def instantiate_reg(id, attrs)
  return _registers[id] unless _registers[id].is_a?(Origen::Registers::Placeholder)

  attributes = {
    define_file: attrs[:define_file],
    description: attrs[:description]
  }
  Reg::REG_LEVEL_ATTRIBUTES.each do |attribute, _meta|
    attributes[attribute] = attrs[attribute]
  end
  _registers[id] = Reg.new(self, attrs[:address], attrs[:size], id,
                           attrs[:bit_info].merge(attributes))
end
is_a_bit?(obj) click to toggle source

Returns true if the given object is an Origen bit

# File lib/origen/registers.rb, line 288
def is_a_bit?(obj)
  obj.is_a?(Origen::Registers::Bit)
end
max_address_reg_size() click to toggle source

Returns the size (in bits) of the register with the highest address, can be useful in combination with max_reg_address to work out the range of addresses containing registers

# File lib/origen/registers.rb, line 481
def max_address_reg_size
  @max_address_reg_size
end
max_reg_address() click to toggle source

Returns the highest address of all registers that have been added

# File lib/origen/registers.rb, line 474
def max_reg_address
  @max_reg_address || 0
end
min_reg_address() click to toggle source

Returns the lowest address of all registers that have been added

# File lib/origen/registers.rb, line 469
def min_reg_address
  @min_reg_address || 0
end
read_register_missing!(reg) click to toggle source
# File lib/origen/registers.rb, line 688
    def read_register_missing!(reg)
      klass = (try(:controller) || self).class
      puts ''
      puts ''
      puts <<-EOT
You have made a request to read register: #{reg.name}, however the #{klass}
class does not know how to do this yet. You should implement a read_register
method in the #{klass} like this:

  def read_register(reg, options={})
    <logic to handle reading the reg object here>
  end
      EOT
      puts ''
      exit 1
    end
reg(*args, &block) click to toggle source

Returns

-the register object matching the given name
-or a hash of all registes matching a given regular expression
-or a hash of all registers, associated with a feature, if no name is specified.

Can also be used to define a new register if a block is supplied in which case it is equivalent to calling add_reg with a block.

# File lib/origen/registers.rb, line 511
def reg(*args, &block)
  if block_given? || (args[1].is_a?(Integer) && !try(:_initialized?))
    @reg_define_file = define_file(caller[0])
    add_reg(*args, &block)
  else
    # Example use cases:
    # reg(:reg2)
    # reg(:name => :reg2)
    # reg('/reg2/')
    if !args.empty? && args.size == 1 && (args[0].class != Hash || (args[0].key?(:name) && args[0].size == 1))
      if args[0].class == Hash
        name = args[0][:name]
      else
        name = args.first
      end
      if has_reg(name)
        _registers[name]
      elsif name =~ /\/(.+)\//
        regex = Regexp.last_match(1)
        match_registers(regex)
      else
        if Origen.config.strict_errors
          puts ''
          if regs.empty?
            puts "#{self.class} does not have a register named #{name} or it is not enabled."
          else
            puts "#{self.class} does not have a register named #{name} or it is not enabled."
            puts 'You may need to add it. This could also be a typo, these are the valid register names:'
            puts regs.keys
          end
          puts ''
          fail 'Missing register error!'
        end
      end
    # Example use cases:
    # reg(:enabled_features => :all)
    # reg(:name => :reg2, enabled_features => :all)
    # reg(:name => :reg2, enabled_features => :fac)
    elsif !args.empty? && args.size == 1 && args[0].class == Hash
      params = args[0]

      # Example use case:
      # reg(:name => :reg2, :enabled_features => :all)
      if (params.key?(:enabled_features) || params.key?(:enabled_feature)) && params.key?(:name)
        name = params[:name]
        if has_reg(name, params)
          _registers[name]
        else
          reg_missing_error(params)
        end
      # Example use case:
      # reg(:enabled_features =>[:fac, fac2])
      elsif params.size == 1 && params.key?(:enabled_features)
        get_registers(enabled_features: params[:enabled_features])
      end

    # Example use case:
    # reg(:reg2, :enabled_features => :all)
    # reg(:reg2, :enabled_features => :default)
    # reg(:reg2, :enabled_features => :fac)
    elsif !args.empty? && args.size == 2
      name = args[0]
      params = args[1]
      name, params = params, name if name.class == Hash
      if has_reg(name, params)
        _registers[name]
      else
        reg_missing_error(params)
      end
    elsif args.empty?
      if _registers.empty?
        _registers
      else
        get_registers(enabled_features: :default)
      end
    else
      if Origen.config.strict_errors
        fail 'Invalid call to reg method or invalid arguments specified'
      end
    end
  end
end
Also aliased as: regs
regs(*args, &block)
Alias for: reg
reset_registers() click to toggle source

Resets all registers

# File lib/origen/registers.rb, line 486
def reset_registers
  regs.each { |_name, reg| reg.reset }
end
write_register_missing!(reg) click to toggle source
# File lib/origen/registers.rb, line 671
    def write_register_missing!(reg)
      klass = (try(:controller) || self).class
      puts ''
      puts ''
      puts <<-EOT
You have made a request to write register: #{reg.name}, however the #{klass}
class does not know how to do this yet. You should implement a write_register
method in the #{klass} like this:

  def write_register(reg, options={})
    <logic to handle the writing of the reg object here>
  end
      EOT
      puts ''
      exit 1
    end

Private Instance Methods

extract_enabled_features(options) click to toggle source
# File lib/origen/registers.rb, line 622
def extract_enabled_features(options)
  options[:enabled_features] || options[:enabled_feature]
end
get_registers(params) click to toggle source
# File lib/origen/registers.rb, line 626
def get_registers(params)
  params = {
    test_for_true_false: false
  }.update(params)
  regs_to_return = RegCollection.new(self)
  req_features = extract_enabled_features(params)
  if req_features == :all
    regs_to_return = _registers
  elsif req_features == :none
    _registers.each do |k, v|
      regs_to_return[k] = v unless v.has_feature_constraint?
    end
  elsif req_features == :default
    _registers.each do |k, v|
      regs_to_return[k] = v if v.enabled?
    end
  elsif req_features.class == Array
    req_features.each do |req_feat|
      _registers.each do |k, v|
        regs_to_return[k] = v if v.enabled_by_feature?(req_feat) || !v.has_feature_constraint?
      end
    end
  else
    _registers.each do |k, v|
      regs_to_return[k] = v if v.enabled_by_feature?(req_features) || !v.has_feature_constraint?
    end
  end
  if regs_to_return.empty?
    unless params[:test_for_true_false]
      puts 'No register found with the specified feature or the register is disabled!'
      fail 'Missing register error!'
    end
  end
  regs_to_return
end
match_registers(regex) click to toggle source
# File lib/origen/registers.rb, line 597
def match_registers(regex)
  regs_to_return = RegCollection.new(self)
  _registers.each do |k, v|
    regs_to_return[k] = v if k.to_s.match(/#{regex}/)
  end
  regs_to_return
end
Also aliased as: regs_match
reg_missing_error(params) click to toggle source
# File lib/origen/registers.rb, line 606
def reg_missing_error(params)
  if Origen.config.strict_errors
    puts ''
    temp = regs(params)
    if temp.empty?
      puts "#{self.class} does not have a register named #{name} within the supplied feature scope, you need to add it."
    else
      puts "#{self.class} does not have a register named #{name} within the supplied feature scope, you may need to add it."
      puts 'This could also be a typo, these are the valid register names:'
      puts temp.keys
    end
    puts ''
    fail 'Missing register error!'
  end
end
regs_match(regex)
Alias for: match_registers