Class: Origen::Specs::Spec

Inherits:
Object show all
Extended by:
Checkers
Includes:
Checkers
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'),
  hidespec:                   SpecAttribute.new(:hidespec, [String, Array], false, :design, 'Add the ability to hide specs based off license plate'),
  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

Methods included from Checkers

evaluate_limit, get_mode, limits_ok?, name_audit

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


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
108
109
110
111
# File 'lib/origen/specs/spec.rb', line 83

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



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/origen/specs/spec.rb', line 183

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



256
257
258
259
260
261
262
# File 'lib/origen/specs/spec.rb', line 256

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



203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/origen/specs/spec.rb', line 203

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)


251
252
253
# File 'lib/origen/specs/spec.rb', line 251

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

#inspectObject



113
114
115
116
117
# File 'lib/origen/specs/spec.rb', line 113

def inspect
  $dut.send(:specs_to_table_string, [self])
rescue
  super
end

#note_countObject

Returns the number of notes as an Integer



272
273
274
# File 'lib/origen/specs/spec.rb', line 272

def note_count
  @notes.size
end

#notes(id = nil) ⇒ Object

Returns a Note object from the notes hash



265
266
267
268
269
# File 'lib/origen/specs/spec.rb', line 265

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

  @notes.filter(id)
end

#trace_matrix_nameObject

Returns the trace_matrix name. The Trace Matrix Name is composed of

  • @name

  • @type

  • @subtype

  • @mode



124
125
126
127
128
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
# File 'lib/origen/specs/spec.rb', line 124

def trace_matrix_name
  name_set = trace_matrix_name_choose
  ret_name = ''
  case name_set
  when 0
    ret_name = ''
  when 1
    ret_name = "#{@mode}"
  when 2
    ret_name = "#{@sub_type}"
  when 3
    ret_name = "#{@sub_type}_#{@mode}"
  when 4
    ret_name = "#{@type}"
  when 5
    ret_name = "#{@type}_#{@mode}"
  when 6
    ret_name = "#{@type}_#{@sub_type}"
  when 7
    ret_name = "#{@type}_#{@sub_type}_#{@mode}"
  when 8
    ret_name = "#{small_name}"
  when 9
    ret_name = "#{small_name}_#{@mode}"
  when 10
    ret_name = "#{small_name}_#{@sub_type}"
  when 11
    ret_name = "#{small_name}_#{@sub_type}_#{@mode}"
  when 12
    ret_name = "#{small_name}_#{@type}"
  when 13
    ret_name = "#{small_name}_#{@type}_#{@mode}"
  when 14
    ret_name = "#{small_name}_#{@type}_#{@sub_type}"
  when 15
    ret_name = "#{small_name}_#{@type}_#{@sub_type}_#{@mode}"
  else
    ret_name = 'Bad trace matrix code'
  end
  ret_name
end

#trace_matrix_name_to_ditaObject

This will create the trace matrix name to be placed into a dita phrase element End goal will be code:xml

<ph audience="internal">trace_matrix_name</ph>

code



171
172
173
174
175
176
177
178
179
180
181
# File 'lib/origen/specs/spec.rb', line 171

def trace_matrix_name_to_dita
  tmp_doc = Nokogiri::XML('<foo><bar /></foo>', nil, 'EUC-JP')

  tmp_node = Nokogiri::XML::Node.new('lines', tmp_doc)
  tmp_node1 = Nokogiri::XML::Node.new('i', tmp_doc)
  tmp_node.set_attribute('audience', 'trace-matrix-id')
  text_node1 = Nokogiri::XML::Text.new("[#{trace_matrix_name}]", tmp_node)
  tmp_node1 << text_node1
  tmp_node << tmp_node1
  tmp_node.at_xpath('.').to_xml
end