class Origen::Specs::Spec
Constants
- ATTRS
- Limit
- SpecAttribute
- TYPES
Public Class Methods
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
# 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
Public Instance Methods
Add a specification note
# 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
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
# 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
Monkey patch of hash/array include? method needed because Origen::Specs#specs
can return a single Spec
instance or an Array
of Specs
# File lib/origen/specs/spec.rb, line 251 def include?(s) s == @name ? true : false end
# File lib/origen/specs/spec.rb, line 113 def inspect $dut.send(:specs_to_table_string, [self]) rescue super end
# 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
Returns the number of notes as an Integer
# File lib/origen/specs/spec.rb, line 272 def note_count @notes.size end
Returns a Note
object from the notes hash
# File lib/origen/specs/spec.rb, line 265 def notes(id = nil) return nil if @notes.nil? @notes.filter(id) end
Returns the trace_matrix name. The Trace Matrix Name is composed of
-
@name
-
@type
-
@subtype
-
@mode
# 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
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}
# 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
Private Instance Methods
This assumes the limit objects are Structs
# File lib/origen/specs/spec.rb, line 289 def diff_limits(limit_one, limit_two = nil) diff_results = Hash.new do |h, k| h[k] = [] end # Only need to loop through limit one ivars because the Limit class cannot # be changed in 3rd party files like the Spec class can be limit_one.members.each do |m| if limit_two.respond_to? m unless limit_one.send(m) == limit_two.send(m) diff_results[m] = [limit_one.send(m), limit_two.send(m)] Origen.log.debug "Found limit difference for member #{m} for #{limit_one} and #{limit_two}" end else # Limit two doesn't have the current instance variable or was not provided # as an argument so log a difference Origen.log.debug "Member #{m} exists for #{limit_one} and does not for #{limit_two}" diff_results[m] = [limit_one.send(m), ''] end end diff_results end
# File lib/origen/specs/spec.rb, line 278 def small_name if @name.to_s[0..@ip_name.to_s.length].include? @ip_name.to_s ret_name = @name.to_s[@ip_name.to_s.length + 1..-1] else ret_name = @name.to_s end ret_name = ret_name.partition('-').last if ret_name.include? '-' ret_name end
# File lib/origen/specs/spec.rb, line 311 def trace_matrix_name_choose name_set = 0 name_set = 8 unless @name.nil? name_set += 4 unless @type.nil? name_set += 2 unless @sub_type.nil? unless @mode.nil? unless (@mode.to_s.include? 'local') || (@mode.to_s.include? 'global') name_set += 1 end end name_set end