Class: Origen::Specs::Spec

Inherits:
Object show all
Defined in:
lib/origen/specs/spec.rb

Defined Under Namespace

Classes: Limit, SpecAttribute

Constant Summary collapse

TYPES =
Origen::Specs::SPEC_TYPES
ATTRS =
{
  ip_name:                    SpecAttribute.new(:ip_name, Symbol, true, :design, 'The parent IP object of the specification'),
  name:                       SpecAttribute.new(:name, Symbol, true, :design, 'Specification Name'),
  type:                       SpecAttribute.new(:type, Symbol, true, :design, "Specification Type, acceptable values: #{TYPES}"),
  sub_type:                   SpecAttribute.new(:sub_type, Symbol, true, :design, 'Specification sub-type (e.g. :max_operating_condition)'),
  mode:                       SpecAttribute.new(:mode, Symbol, true, :design, 'Specification mode, inherited from the owning parent object'),
  symbol:                     SpecAttribute.new(:symbol, String, false, :design, 'Specification symbol, can contain HTML'),
  description:                SpecAttribute.new(:description, String, false, :design, 'Specification description'),
  audience:                   SpecAttribute.new(:audience, Symbol, false, :design, 'Specification audience, acceptable values are :internal and :external'),
  min:                        SpecAttribute.new(:min, Limit, false, :design, 'Specification minimum limit. The limit expression is displayed, not a resolved value'),
  min_ovr:                    SpecAttribute.new(:min_ovr, Limit, false, :design, 'Specification minimum limit at SoC level.  The limit expression is displaye,d not a resolved value'),
  max:                        SpecAttribute.new(:max, Limit, false, :design, 'Specification maximum limit. The limit expression is displayed, not a resolved value'),
  max_ovr:                    SpecAttribute.new(:max_ovr, Limit, false, :design, 'Specification maximum limit at SoC level.  The limit expression is displaye,d not a resolved value'),
  typ:                        SpecAttribute.new(:typ, Limit, false, :design, 'Specification typical limit. The limit expression is displayed, not a resolved value'),
  typ_ovr:                    SpecAttribute.new(:typ_ovr, Limit, false, :design, 'Specification typical limit at SoC level.  The limit expression is displaye,d not a resolved value'),
  unit:                       SpecAttribute.new(:unit, String, false, :design, 'Specification unit of measure'),
  constraints:                SpecAttribute.new(:constraints, String, false, :design, "Single logical expression or a CSV list of logical expressions required for the spec to be valid (e.g. 'GVDD == 1.2V'"),
  limit_type:                 SpecAttribute.new(:limit_type, Symbol, false, :design, 'Auto-generated attribute based on analysis of the spec limits. Acceptable values are :single_sided and :double_sided'),
  notes:                      SpecAttribute.new(:notes, Hash, false, :design, 'Specification notes'),
  disposition_required:       SpecAttribute.new(:disposition_required, TrueClass, false, :pde, 'Boolean representation of whether a specification needs a disposition based on silicon results or customer input'),
  priority:                   SpecAttribute.new(:priority, TrueClass, false, :pde, 'Integer value (1-4) to indicate which priority the cz for this spec will be:  1. Highest priority, for critical or historically risky specs   2. Medium priority, relatively low risk. Not required until all priority 1 specs have been handled  3. Lowest priority, very low risk, low performance specs  4. No plans to characterize'),
  target:                     SpecAttribute.new(:target, String, false, :pde, 'Specification target limit.  Not used for pass/fail results but for data analysis'),
  guardband:                  SpecAttribute.new(:guardband, Limit, false, :pde, 'Specification guardband limit'),
  testable:                   SpecAttribute.new(:testable, TrueClass, false, :pde, 'Boolean representation of whether a specification is testable'),
  tested_at_probe:            SpecAttribute.new(:tested_at_probe, TrueClass, false, :pde, 'Boolean representation of whether a specification is tested at probe'),
  tested_at_ft_hot:           SpecAttribute.new(:tested_at_ft_hot, TrueClass, false, :pde, 'Boolean representation of whether a specification is tested at final test hot temperature'),
  tested_at_ft_ext_hot:       SpecAttribute.new(:tested_at_ft_ext_hot, TrueClass, false, :pde, 'Boolean representation of whether a specification is tested at final test extended hot temperature'),
  tested_at_ft_cold:          SpecAttribute.new(:tested_at_ft_cold, TrueClass, false, :pde, 'Boolean representation of whether a specification is tested at final test cold temperature'),
  tested_at_ft_ext_cold:      SpecAttribute.new(:tested_at_ft_ext_cold, TrueClass, false, :pde, 'Boolean representation of whether a specification is tested at final test extended cold temperature'),
  tested_at_ft_room:          SpecAttribute.new(:tested_at_ft_room, TrueClass, false, :pde, 'Boolean representation of whether a specification is tested at final test room temperature'),
  guaranteed_by_prod_test:    SpecAttribute.new(:guaranteed_by_prod_test, TrueClass, false, :pde, 'Boolean representation of whether a specification is guaranteed by production test'),
  guaranteed_by_proxy_test:   SpecAttribute.new(:guaranteed_by_proxy_test, TrueClass, false, :pde, 'Boolean representation of whether a specification is guaranteed by production test via a proxy test such as BIST'),
  guaranteed_by_construction: SpecAttribute.new(:guaranteed_by_construction, TrueClass, false, :pde, 'Boolean representation of whether a specification is guaranteed by physical construction, design documentation required'),
  guaranteed_by_simulation:   SpecAttribute.new(:guaranteed_by_simulation, TrueClass, false, :pde, 'Boolean representation of whether a specification is tested guaranteed by simulation, design documentation required'),
  cz_on_ate:                  SpecAttribute.new(:cz_on_ate, TrueClass, false, :pde, 'Boolean representation of whether a specification is characterized on ATE'),
  cz_ate_sample_size:         SpecAttribute.new(:cz_ate_sample_size, Integer, false, :pde, 'Integer number representing the sample size of the split used for customer Cpk calculation as tested on ATE'),
  cz_ate_cpk:                 SpecAttribute.new(:cz_ate_cpk, Float, false, :pde, 'Float number representing the customer or representative Cpk of the specification as tested on ATE'),
  cz_on_bench:                SpecAttribute.new(:cz_on_bench, TrueClass, false, :pde, 'Boolean representation of whether a specification is characterized on a bench setup'),
  cz_bench_sample_size:       SpecAttribute.new(:cz_bench_sample_size, Integer, false, :pde, 'Integer number representing the sample size of the split used for customer Cpk calculation on a bench setup'),
  cz_bench_cpk:               SpecAttribute.new(:cz_bench_cpk, Float, false, :pde, 'Float number representing the customer or representative Cpk of the specification as tested on a bench setup'),
  cz_on_system:               SpecAttribute.new(:cz_on_system, TrueClass, false, :pde, 'Boolean representation of whether a specification is characterized in a system setup'),
  cz_system_sample_size:      SpecAttribute.new(:cz_system_sample_size, Integer, false, :pde, 'Integer number representing the sample size of the split used for customer Cpk calculation in a system'),
  cz_system_cpk:              SpecAttribute.new(:cz_system_cpk, Float, false, :pde, 'Float number representing the customer or representative Cpk of the specification as tested in a system')
}

Instance Method Summary collapse

Constructor Details

#initialize(name, type, mode, owner_name, &block) ⇒ Spec

There are at least three attributes needed to define a unique spec.

1) name (e.g. :vdd)
2) type (e.g. :dc)  Possible values are [:dc, :ac, :temperature]
3) mode (e.g. :global).  mode defaults to the current mode found for the parent object

A mode is defined as a device state that requires some sequence of actions to be enabled. A type is a classification moniker that exists without any stimulus required. Some specs require a fourth attribute sub_type to be uniquely defined. For example, a global device level VDD specification would require four attributes to be unique. Here is an example of two spec definitions for a VDD power supply

name = :vdd, type: :dc, mode: :global, sub_type: typical_operating_conditions, typ = "1.0V +/- 30mV"
name = :vdd, type: :dc, mode: :global, sub_type: maximum_operating_conditions, min = -0.3V, max = 1.8V

Whereas a typical DDR timing specification might only need three attributes to be unique

name: :tddkhas, type: :ac, mode: ddr4dr2400, sub_type: nil


81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/origen/specs/spec.rb', line 81

def initialize(name, type, mode, owner_name, &block)
  @name = name_audit(name)
  fail 'Specification names must be of types Symbol or String and cannot start with a number' if @name.nil?
  @type = type
  @sub_type = nil # not necessary to be able to find a unique spec, but required for some specs
  @mode = mode
  @ip_name = owner_name
  @symbol = nil # Meant to be populated with HTML representing the way the spec name should look in a document
  @description = nil
  @min, @typ, @max, @target = nil, nil, nil, nil
  @min_ovr, @typ_ovr, @typ_ovr = nil, nil, nil
  @audience = nil
  @notes = {}
  @exhibits = {}
  @testable = nil
  @guardband = nil
  (block.arity < 1 ? (instance_eval(&block)) : block.call(self)) if block_given?
  fail "Spec type must be one of #{TYPES.join(', ')}" unless TYPES.include? type
  @min = Limit.new(@min)
  @max = Limit.new(@max)
  @typ = Limit.new(@typ)
  @min_ovr = Limit.new(@min_ovr)
  @max_ovr = Limit.new(@max_ovr)
  @typ_ovr = Limit.new(@typ_ovr)
  @guardband = Limit.new(@guardband)
  fail "Spec #{name} failed the limits audit!" unless limits_ok?
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/origen/specs/spec.rb', line 109

def method_missing(method, *args, &block)
  ivar = "@#{method.to_s.gsub('=', '')}"
  ivar_sym = ":#{ivar}"
  if method.to_s =~ /=$/
    define_singleton_method(method) do |val|
      instance_variable_set(ivar, val)
    end
  elsif instance_variables.include? ivar_sym
    instance_variable_get(ivar)
  else
    define_singleton_method(method) do
      instance_variable_get(ivar)
    end
  end
  send(method, *args, &block)
end

Instance Method Details

#add_note(id, options = {}) ⇒ Object

Add a specification note



181
182
183
184
185
186
187
# File 'lib/origen/specs/spec.rb', line 181

def add_note(id, options = {})
  options = {
    type: :spec
  }.update(options)
  # Create the Note instance and add to the notes attribute
  @notes[id] = Origen::Specs::Note.new(id, options[:type], options)
end

#diff(compare_spec) ⇒ Object

Do a ‘diff’ from the current spec (self) and the compare spec Returns a hash with attribute as key and an array of the attribute values that differed



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/origen/specs/spec.rb', line 129

def diff(compare_spec)
  diff_results = Hash.new do |h, k|
    h[k] = []
  end
  # Loop through self's isntance variables first
  instance_variables.each do |ivar|
    ivar_sym = ivar.to_s.gsub('@', '').to_sym
    next if ivar_sym == :notes # temporarily disable until notes diff method written
    ivar_str = ivar.to_s.gsub('@', '')
    if compare_spec.respond_to? ivar_sym
      # Check if the instance variable is a Limit and if so then find
      # all instance_variables and diff them as well
      if instance_variable_get(ivar).class == Origen::Specs::Spec::Limit
        limit_diff_results = diff_limits(instance_variable_get(ivar), compare_spec.instance_variable_get(ivar))
        # Extract the limit diff pairs and merge with updated keys with the diff_results hash
        limit_diff_results.each do |k, v|
          limit_diff_key = "#{ivar_str}_#{k}".to_sym
          diff_results[limit_diff_key] = v
        end
      else
        unless instance_variable_get(ivar) == compare_spec.instance_variable_get(ivar)
          diff_results[ivar_sym] = [instance_variable_get(ivar), compare_spec.instance_variable_get(ivar)]
          Origen.log.debug "Found spec difference for instance variable #{ivar} for #{self} and #{compare_spec}"
        end
      end
    else
      # The compare spec doesn't have the current instance variable
      # so log a difference
      if instance_variable_get(ivar).class == Origen::Specs::Spec::Limit
        limit_diff_results = diff_limits(instance_variable_get(ivar), compare_spec.instance_variable_get(ivar))
        # Extract the limit diff pairs and merge with updated keys with the diff_results hash
        limit_diff_results.each do |k, v|
          limit_diff_key = "#{ivar_str}_#{k}".to_sym
          diff_results[limit_diff_key] = v
        end
      else
        Origen.log.debug "Instance variable #{ivar} exists for #{self} and does not for #{compare_spec}"
        diff_results[ivar_sym] = [instance_variable_get(ivar), '']
      end
    end
  end
  # Loop through unique instance variables for compare_spec
  diff_results
end

#include?(s) ⇒ Boolean

Monkey patch of hash/array include? method needed because Origen::Specs#specs can return a single Spec instance or an Array of Specs

Returns:

  • (Boolean)


176
177
178
# File 'lib/origen/specs/spec.rb', line 176

def include?(s)
  s == @name ? true : false
end

#note_countObject

Returns the number of notes as an Integer



196
197
198
# File 'lib/origen/specs/spec.rb', line 196

def note_count
  @notes.size
end

#notes(id = nil) ⇒ Object

Returns a Note object from the notes hash



190
191
192
193
# File 'lib/origen/specs/spec.rb', line 190

def notes(id = nil)
  return nil if @notes.nil?
  @notes.filter(id)
end