class Origen::Limits::Limit

Attributes

expr[RW]
owner[RW]
type[RW]
value[W]

Public Class Methods

new(expr, type, owner, options = {}) click to toggle source
# File lib/origen/limits/limit.rb, line 7
def initialize(expr, type, owner, options = {})
  @expr = expr
  @owner = owner
  @type = type
  @value = evaluate_expr
end

Public Instance Methods

exp() click to toggle source

Backwards compatibility

# File lib/origen/limits/limit.rb, line 26
def exp
  @expr
end
value() click to toggle source

If the value is still a String then it could be due to referencing another LimitSet that is yet to be defined

# File lib/origen/limits/limit.rb, line 17
def value
  if @value.is_a?(String)
    evaluate_expr
  else
    @value
  end
end

Private Instance Methods

evaluate_expr() click to toggle source
# File lib/origen/limits/limit.rb, line 65
def evaluate_expr
  return @expr if @expr.is_a?(Numeric)
  return nil if @expr.nil?

  if @expr.is_a? Symbol
    @expr = ':' + @expr.to_s
  else
    @expr.gsub!("\n", ' ')
    @expr.scrub!
  end
  result = false
  if @expr.match(/\:\S+/)
    limit_items = @expr.split(/\:|\s+/).reject(&:empty?)
    if limit_items.size == 1
      return fetch_reference_value(limit_items.first)
    else
      references = @expr.split(/\:|\s+/).select { |var| var.match(/^[a-zA-Z]\S+$/) }
      new_limit_items = [].tap do |limit_ary|
        limit_items.each do |item|
          if references.include? item
            limit_ary << fetch_reference_value(item)
            next
          else
            limit_ary << item
          end
        end
      end
      new_limit = new_limit_items.join(' ')
      new_limit_references = new_limit.split(/\:|\s+/).select { |var| var.match(/^[a-zA-Z]\S+$/) }
      if new_limit_references.empty?
        result = eval(new_limit).round(4)
      else
        return @expr
      end
    end
  elsif !!(@expr.match(/^\d+\.\d+$/)) || !!(@expr.match(/^-\d+\.\d+$/))
    result = Float(@expr).round(4) rescue false # rubocop:disable Style/RescueModifier
  elsif !!(@expr.match(/\d+\.\d+\s+\d+\.\d+/))
    Origen.log.debug "Found two numbers without an operator in the @expr string '#{@expr}', choosing the first..."
    first_number = @expr.match(/(\d+\.\d+)\s+\d+\.\d+/).captures.first
    result = Float(first_number).round(4) rescue false # rubocop:disable Style/RescueModifier
  else
    result = Integer(@expr) rescue false # rubocop:disable Style/RescueModifier
  end
  if result == false
    # Attempt to eval the @expr because users could write a @expr like "3.3 + 50.mV"
    # which would not work with the code above but should eval to a number 3.35
    begin
      result = eval(@expr)
      return result.round(4) if result.is_a? Numeric
    rescue ::SyntaxError, ::NameError, ::TypeError
      Origen.log.debug "Limit '#{@expr}' had to be rescued, storing it as a #{@expr.class}"
      if @expr.is_a? Symbol
        @expr
      else
        "#{@expr}"
      end
    end
  else
    result
  end
end
fetch_reference_value(ref) click to toggle source
# File lib/origen/limits/limit.rb, line 32
def fetch_reference_value(ref)
  ref = ref.to_sym unless ref.is_a?(Symbol)
  # Check if the reference is to another limit set
  if owner.limits.include? ref
    return owner.limits(ref).send(type).value
    # Check if the reference is to a power domain
  end

  if Origen.top_level.respond_to? :power_domains
    if Origen.top_level.power_domains.include? ref
      # Need to check the limit type and retrieve the appropriate value
      case @type.to_s
      when /target|typ/
        return Origen.top_level.power_domains(ref).nominal_voltage
      else
        return Origen.top_level.power_domains(ref).send(@type)
      end
    end
  end
  # Check if the reference is to a clock
  if Origen.top_level.respond_to? :clocks
    if Origen.top_level.clocks.include? ref
      # Need to check the limit type and retrieve the appropriate value
      case @type.to_s
      when /target|typ/
        Origen.top_level.clocks(ref).freq_target
      else
        Origen.top_level.clocks(ref).send(@type)
      end
    end
  end
end