• Guides
  • Videos
  • Publications
  • API
  • Github
  • Community
  • Release Notes
  • Plugins
Installing Origen
  • Introduction
  • How to Install
  • How to Install (Windows)
  • Company Customization
  • Understanding Gems
  • Invoking Considerations
  • Workspace Management
Getting Started with Origen
  • Core concepts
  • Creating a New App
  • Directory Structure
  • The Initial Commit
  • Creating New Files
  • Understanding Blocks
  • Application Architecture
Runtime Environment
  • Introduction
  • Mode
  • Environment
  • Target
  • Production Targets
  • Global Setup
  • Load Order
  • Programming
Models
  • Introduction
  • Naming
  • Definition & Hierarchy
  • Adding Attributes
  • Versioning
  • Bugs & Features
  • Package, Mode & Configuration
  • Registers
  • Pins
  • Power Domains
  • Hardware Attributes
  • Parameters
  • Specifications
  • Fuses
  • Generic Components
  • Creating Your Own Components
Compiler (Views)
  • Introduction
  • Creating Templates
  • Using Sub-Templates
  • Helpers
  • Running The Compiler
  • Inline Compiler
Controllers
  • Introduction
  • Shadow Controllers
  • Direct Controllers
Pattern Generator
  • Introduction
  • Creating Patterns
  • Pins
  • Timing and Waiting
  • Registers
  • Documenting Patterns
  • Generating by Name
  • Common API
  • J750 API
  • V93K API
  • UltraFlex API
  • STIL & Other Formats
  • Custom Testers
  • Running The PatGen
  • Concurrent Patterns
Test Program Generator
  • Introduction
  • Philosophy
  • Creating Flows
  • Managing Flow Control
  • Creating an Interface
  • Additional Resources
  • Dynamic Custom Code
  • Characterization API
  • J750 API
  • V93K Common API
  • V93K SMT7 API
  • V93K SMT8 API
  • UltraFLEX API
  • Documenting the Program
  • Creating Custom Testers
  • Running the ProgGen
Decompilation
  • Overview & Example
  • Decompiling, Adding Pins, & Executing
  • Working with Decompiled Patterns
  • Platform Specifics
Simulation
  • Introduction
  • How It Works
  • Compiling the DUT
  • AMS Support
  • Environment Setup
  • Application Setup
  • Simulating Patterns
  • Simulating Flows
  • Direct DUT Manipulation
  • Simulator Log Output
  • Artifacts
  • Debugging
Documentation Generator
  • Introduction
  • Markdown
  • Linking
  • Styling
  • Testing
  • API Generation
  • Deploying
Plugins
  • Introduction
  • Using a Plugin
  • Creating a Plugin
  • Current & Default Plugins
  • Dev Environment
  • Dev Considerations
  • Paths & Origen.root
  • Config & Origen.app
Miscellaneous
  • Revision Control
  • Origen Remotes
  • Lint Testing
  • Session Store
  • LSF API
  • Users, Emails & Maillists
  • Utilities & Helpers
  • Ruby Extensions
  • Logger
  • Adding Commands
  • Overriding Commands
  • Callbacks
  • Application Callbacks
  • Miscellaneous Topics
Advanced Topics
  • Introduction
  • Invocation Customization
  • Custom App Generators

Models

Parameters


A given model, or indeed an application, will often have some parameters associated with it. While any standard Ruby accessors and instance variables can be used to define such parameters the following API is provided to define them in a standardized way. The advantages to using this API vs. a roll-your-own solution are as follows:

  • The API provides a number of features that go above and beyond what basic Ruby attribute accessors provide, this would require significant application-side code to replicate
  • Using standard APIs gives your code a familiar look and feel to any new developers who may work on it in future
  • You will be able to benefit from future additions to the Origen ecosystem that hook into this API, e.g. a documentation helper to automatically generate a parameter summary will almost certainly emerge

Basic Idea

Parameters are defined as a group of named values that will apply in a given context, many different sets of values to apply in different contexts can be defined. A context can be used to represent any abstract concept that you like, but a good example would be to have a set of parameter values that will apply at probe, a different set for final test and a different set for spec operation.

The current parameter context can be set and changed dynamically at runtime as required by your application, typically this would be set on a per-target/environment basis or for pattern generation on a per-pattern basis. A common approach for pattern generation is to leverage sourceless pattern generation and employ the convention that the first field in the pattern name refers to the spec context - e.g. probe_mypat, ft_mypat, spec_mypat. It is then trivial to set the parameter context based on the pattern name, thereby providing a bulletproof way to update any given parameter for every probe pattern by simply updating its value in the probe parameter set definition.

Including the Parameters API

To use the parameters API in an abstract class the following module can be included:

include Origen::Parameters

However this is already included the Origen::Model and Origen::TopLevel modules and any class which includes those will already have access to this API.

Defining a Set of Parameters

Parameters are defined as shown below, it is always a good idea to create a parameter context called :default, these are the values that will be enabled when a parameter context has not explicitly been set:

define_params :default do |params|
  params.tprog = 20.uS
  params.terase = 100.mS
end

Parameters can be organized into namespaces by simply writing them, no upfront definition is required and there is no limit to how deeply nested they can be:

define_params :default do |params|
  params.program.time = 20.uS
  params.erase.time = 100.mS
  params.erase.pulse_count = 10
  params.test.dc.vdd.min = 1.5
  params.test.dc.vdd.max = 2.5
end

Parameters are read back in application code via the params method:

params.test.dc.vdd.min   # => 1.5

Each namespace in the chain returns an object that can be used like a hash:

def print_erase_parameters
  params.erase.each do |name, value|
    puts "#{name}: #{value}"
  end
end

print_erase_parameters   # => time: 0.1 
                         # => pulse_count: 10

In some cases, it is useful to have one object access another’s parameters (e.g. a sub-block can reference the top-level parameters sets). However, in this case the calling object may not necessarily be aware of which parameters have been created. The param? method provides a quick way to combine an existence test while attempting to retrieve the value of a specific parameter.

param?('test.dc.vdd.min')   # => 1.5
param?('test.dc.vdd.nom')   # => nil

# Example to set bin using a top-level parameter or default to 12
#   if the top-level parameter has not been set (i.e. does not exist)
my_block_bin = dut.param?('testprogram.bin.my_block') || 12

The current parameter context is set as follows:

params.context        # => :default
params = :probe
params.context        # => :probe
with_params :ft do
  params.context      # => :ft
end
params.context        # => :probe

Tracking the Context of Another Object

The parameter context for a given object can be configured to automatically track that of another object by specifying a Ruby path to the object to be tracked as shown below:

# A short hand is available to track the parameter context from the top level ($dut)
class MyObject
  include Origen::Model
  parameters_context :top
end

# Or you can supply a path to the object in the form of a string, here the path reference is local to the MyObject
# instance
class MyObject
  include Origen::Model
  parameters_context 'parent.mbist'
end

# Or another example where the target object is found via the global scope
class MyObject
  include Origen::Model
  parameters_context '$dut.pll'
end

Then whenever the parameter context is set on the tracked object the same context name will be applied when referencing a parameter within the tracking object, for example:

$dut.params.context           # => :default
my_object.params.context      # => :default
$dut.params.context = :probe
$dut.params.context           # => :probe
my_object.params.context      # => :probe

Late Defined Parameters

Occasionally the need may arise to base a parameter value on a property of the model or the wider environment that is not yet finalized or known at the time when the parameter definition code is being executed. In that case the parameter can be defined as a function and Origen will hold off evaluating it until the last possible moment when it is first referenced:

define_params :default do  |params|
  params.test.dc.vdd.min = -> { $dut.vdd * 0.9 }
end

Such parameters will behave identically to standard parameters in all respects and consumers will not be able to tell if a given parameter originated from a function.

Defining Child Sets

Complete parameter sets can be defined for different named contexts, however in many cases only a subset of the parameters will have different values vs. another context. To make maintenance of such cases efficient the API allows parameter sets to be defined in a hierarchy such that a given set can be defined with a parent and if it does not define a value for a given parameter then the value from the parent will be returned instead.

Parameter sets can inherit from within the same object scope or from another DUT object entirely. Local inheritance passes the name of another parameter set as a Symbol. To inherit from another object a String must be passed that starts with ‘dut’ or ‘top, and is delimited by periods. Here is how the string argument is parsed:

str_arg = 'dut.ddr.default'
arg_array = str_arg.split('.')
['dut',top'].include?(arg_array[0]).should == true
dut_path_to_object = arg_array[1..-2]    # => 'ddr'
parameter_context = arg_array[-1].to_sym # => :default
Local Inheritance
define_params :ate, inherit: :default do |params|
  params.erase.time = 40.mS
end

define_params :probe, inherit: :ate do |params|
  params.erase.time = 20.mS
  params.erase.pulse_count = 5
end

define_params :ft, inherit: :ate do |params|
  params.erase.pulse_count = 7
end

with_params :probe do
  params.program.time        # => 20uS (inherited from :default)
  params.erase.time          # => 20ms
  params.erase.pulse_count   # => 5
end

with_params :ft do
  params.program.time        # => 20uS (inherited from :default)
  params.erase.time          # => 40ms (inherited from :ate)
  params.erase.pulse_count   # => 7
end
Remote Inheritance
define_params :ate, inherit: 'dut.ddr.default' do |params|
  params.erase.time = 40.mS
end

Sometimes the parameter definition for a child context should be a function of the value from the parent, when defining a child context the parent can be accessed like this:

define_params :ate, inherit: :default do |params, parent|
  params.test.dc.vdd.min = parent.test.dc.vdd.min * 0.9
  params.test.dc.vdd.max = parent.test.dc.vdd.max * 1.1
end

params.context            # => :default
params.test.dc.vdd.min    # => 1.5
params.test.dc.vdd.max    # => 2.5
params = :ate
params.test.dc.vdd.min    # => 1.35
params.test.dc.vdd.max    # => 2.75

The context can also be explicitly supplied when fetching a parameter, this will override the parameter context that would otherwise be applied:

params.context                  # => :default
params.test.dc.vdd.min          # => 1.5
params(:ate).test.dc.vdd.min    # => 1.35
Multiple Inheritance

Multiple inheritance is also supported by supplying an array of parent IDs (or remote paths) for the :inherit option:

define_params :set1 do |params|
  params.spec_a = 10.uA
end

define_params :set2 do |params|
  params.spec_b = 2.5
end

define_params :soc, inherit: [:set1, :set2] do |params, parents|
  params.spec_c = 100.mV
  # The parents is a Hash in this case if you need to reference upstream values:
  #   parents  =>  { set1: <param set1>, set2: <param set2> }
  params.spec_b = parents[:set2].spec_b * 2
end

params = :soc
params.spec_a     # => 10.uA
params.spec_b     # => 5.0
params.spec_c     # => 100.mV

The order of the parents specifies the order of precedence if multiple parents define the same parameter - those occuring later will override the value inherited from an earlier parent:

define_params :set1 do |params|
  params.spec_a = 10.uA
end

define_params :set2 do |params|
  params.spec_a = 20.uA
end

define_params :soc1, inherit: [:set1, :set2] do |params, parents|
end

define_params :soc2, inherit: [:set2, :set1] do |params, parents|
end

params = :soc1
params.spec_a     # => 20.uA
params = :soc2
params.spec_a     # => 10.uA

Live Updating Parameters

When a parameter is referenced a static value is returned which thereafter has no relationship to the current parameter context, for example:

terase = params.erase.time
params.erase.time                # => 100ms
terase                           # => 100ms
params = :probe                 
params.erase.time                # => 20ms
terase                           # => 100ms

The above should not be surprising and is what would normally be expected, however through the magic of Ruby a live updating parameter can be returned by referring to it via params.live:

terase = params.live.erase.time
terase                           # => 100ms
params = :probe               
terase                           # => 20ms

This is an experimental feature and developers are encouraged to play around with it and report back on any useful applications that they may find for it. Potentially this is a good way to expose parameters via an interface to 3rd parties without coupling them tightly to the namespacing and organization of the parameters within the owning class.

It is certainly only really useful when applied in conjunction with parameter contexts that can change within the scope of a pattern or other Origen thread of execution. While the examples so far have focussed on parameter contexts that will be permanent for a given thread, like probe or ft, contexts can be used to represent more dynamic concepts. For example a given NVM pattern may read the flash under different read conditions where the configuration for each one is modelled by parameter contexts defined within the read controller.

Another possible use case is to bind register bit values to parameters, due to the way that Origen stores register data at bit level a register cannot simply be written to a live parameter, however a dedicated API is provided for this case:

reg :erase, 0x0 do
  bits 3..0, :pulses
end

erase.pulses.data    # => 0
erase.pulses.bind params.live.erase.pulse_count
erase.pulses.data    # => 10
params = :probe
erase.pulses.data    # => 5

In other words anytime that register gets written in the course of a pattern generation run its value will automatically track the current parameter context.


Comments

Generated with the Origen Semiconductor Developer's Kit

Origen is released under the terms of the MIT license