% render "layouts/guides.html" do
### Flow Considerations
By default, a top-level `Flow.create` call in Origen will generate a standalone V93K testflow file which is
internally wrapped by a flow group, like this:
~~~text
group {
// Flow content here
}
~~~
When such flows are imported into a master flow file, SmarTest does not provide a standard enable mechanism
to control which sub-flows are executed.
However, Origen provides the ability to generate V93K flow modules with an enable-word wrapper, thereby allowing
the top-level flow to easily enable/disable the execution of flow modules via flow variables.
By enabling this feature in the target like this:
~~~ruby
OrigenTesters::V93K.new(add_flow_enable: :enabled)
~~~
the flow will now generate like this:
~~~text
group {
if @_ENABLE == 1 {
// Flow content here
}
}
~~~
The `@_ENABLE` variable will be initialized to 1 in the generated variables file for the given flow,
meaning that the module will run by default if the top-level flow does nothing with this variable.
Alternatively, the variable can be initialized to off like this:
~~~ruby
OrigenTesters::V93K.new(add_flow_enable: :disabled)
~~~
Meaning that by default, the module will not run and the top-level flow must always enable it by including
`@_ENABLE = 1` before hitting the module.
Setting this attribute in the target means that it will apply to all flows. Alternatively, it can be set within
the flow itself (or the interface) if it is necessary to use this feature for only a subset of flows, or to override
the default setting for a particular flow.
Here is an example:
~~~ruby
Flow.create interface: 'MyApp::Interface' do
# Ensure that this flow is always generated with an enable word wrapper that is enabled by default
self.add_flow_enable = :enabled
# Some functional test
func :blah
end
~~~
This same API may be used to implement similar features on other platforms in future, but for now only the V93K is implemented.
### Interface Considerations
Be sure to read and understand the guide to
[Creating an Interface](<%= path "guides/program/interface" %>) before
reading this section.
This guide will describe the API to generate V93K/SmarTest test program
components from within an interface file.
To re-cap this is the shell required to implement an interface:
~~~ruby
# lib/vreg/interface.rb
module Vreg
class Interface
include OrigenTesters::ProgramGenerators
# An example method that can be called from your test flow to generate a functional test
def func(name, options={})
# If your interface supports multiple platforms, add conditional logic like this, if you
# only ever want to support one platform then you don't need this
if tester.j750?
# Functional test implementation for J750
elsif tester.v93k?
# Functional test implementation for V93K
end
end
end
end
~~~
The OrigenTesters::ProgramGenerators
will provide the interface
with access to all of the platform generator APIs for the platforms that it supports.
If your interface supports multiple platforms then add conditional logic to separate
them as shown above.
#### Creating a Test Suite
Most of the effort in generating a V93K test program is in generating the test suites and their
associated test methods.
A new test suite and test method can be instantiated and linked together like this:
~~~ruby
t = test_suites.add(:vreg_func)
t.test_method = test_methods.origen.functional_test
~~~
These lines of code do the following things:
* Instantiates a new test suite object and assigns it to the local variable t
* Sets its name to 'vreg_func' and inserts it into the flow file (but not into the actual test flow)
* Instantiates a new functional test method object and attaches it to the test suite
* Inserts the test method into the flow file (but not into the actual test flow)
You will of course want to then decorate your new test with attributes that are specific
to your application, here for example to set the levels and timing:
~~~ruby
t.tim_equ_set = 15
t.tim_spec_set = 1
t.timset = 1
t.lev_equ_set = 20
t.lev_spec_set = 8
t.levset = 1
~~~
If the test method provides parameters, you can set them in the same way. As a convenience,
Origen will automatically work out whether the reference is to a parameter of the test suite
or of the test method, and will assign it accordingly.
For example, let's say this functional test method had a parameter named checkShutdown
, you
could set that like this:
~~~ruby
t.check_shutdown = 1 # By Ruby convention, use the lower-cased underscored version of the C++ name
# The above is a shorthand equivalent to:
t.test_method.check_shutdown = 1
~~~
Attributes can also be passed in when instantiating the new test suite/method, this is equivalent
if you prefer:
~~~
t = test_suites.add(:vreg_func, tim_equ_set: 15, tim_spec_set: 1, timset: 1, lev_equ_set: 20)
t.test_method = test_methods.origen.functional_test(check_shutdown: 1)
~~~
#### Limits
The limits can be set for all test objects using the following API, see here for some examples
[of the available unit helpers](<%= path 'guides/misc/coreext/#Unit_Helpers' %>):
~~~ruby
t.lo_limit = 100.uA
t.hi_limit = 150.uA
~~~
#### Built-in Test Methods
SmarTest comes with a standard AC and DC test method library and Origen provides a built-in API to
generate a test flow which uses those test methods, here are some examples:
~~~ruby
# Execute a functional test
test_method = test_methods.ac_tml.ac_test.functional_test
# A basic DC voltage measurement
test_method = test_methods.dc_tml.dc_test.general_pmu force_mode: 'CURR', force_value: 100.uA
~~~
Generally the parameter naming is the lower-cased and underscored version of the name that appears
in the SMT documentation.
See the [DC library API](http://origen-sdk.org/testers/api/OrigenTesters/SmartestBasedTester/Base/TestMethods/DcTml.html)
and the [AC library API](http://origen-sdk.org/testers/api/OrigenTesters/SmartestBasedTester/Base/TestMethods/AcTml.html)
for up-to-date details of the implemented test methods and the parameter names.
However, some of these test methods are not particularly good and the recommendation from Advantest these
days is generally not to use them.
Since that means there is now a void where a universally available test method library should be, work is
underway to provide an Origen standard test method library.
The aim of this is to provide a complete generation solution from Origen so that those who have
a fairly conventional use case can rapidly build a complete test program from off-the-shelf
components, but that is still a work in progress and not yet ready for prime time use.
Many users of the V93K program generator however, are likely to want to use it in combination
with their own custom test method library...
#### Custom Test Methods
An API exists to define the naming and parameter signature of test methods provided by
a 3rd party library, enabling them to be used within an interface exactly like in the examples above.
Additionally, it is possible to define helper methods that are associated with each test method,
making them easier to use within an Origen test program interface.
This is best shown by example, here is how to define a custom test method library and a custom
test method within an Origen interface:
~~~ruby
# lib/vreg/interface.rb
module Vreg
class Interface
include OrigenTesters::ProgramGenerators
def initialize(options={})
add_my_tml if tester.v93k?
end
# Define the test methods from a custom V93K library
def add_my_tml
# The identifier you give here is what you will use to access the test methods from your interface
# code, for example: test_methods.my_tml.my_test
#
# This will also be the C++ namespace that is used within SMT to access the test method classes
# defined in this library.
add_tml :my_tml,
# [OPTIONAL] If you need the C++ namespace to be different to the above identifier then you can
# specify the C++ name like this:
class_name: 'MyTmlNamespace',
# Here is a test definition.
# The identifier should be lower-cased and underscored, in-keeping with Ruby naming conventions.
# By default the class name will be the camel-cased version of this identifier, so 'myTest' in
# this case.
my_test: {
# [OPTIONAL] The C++ test method class name can be overridden from the default like this:
class_name: 'MyTestClass',
# Parameters can be defined with an underscored symbol as the name, this can be used
# if the C++ implementation follows the standard V93K convention of calling the attribute
# the camel cased version, starting with a lower-cased letter, i.e. 'testerState' in this
# first example.
# The attribute definition has two required parameters, the type and the default value.
# The type can be :string, :current, :voltage, :time, :frequency, integer, :double or :boolean
pin_list: [:string, ''],
samples: [:integer, 1],
precharge_voltage: [:voltage, 0],
settling_time: [:time, 0],
# An optional parameter that sets the limits name in the 'testmethodlimits' section
# of the generated .tf file. Defaults to 'Functional' if not provided.
test_name: [:string, 'SpecSearch']
# An optional 3rd parameter can be supplied to provide an array of allowed values. If supplied,
# Origen will raise an error upon an attempt to set it to an unlisted value.
tester_state: [:string, 'CONNECTED', %w(CONNECTED UNCHANGED DISCONNECTED)],
force_mode: [:string, 'VOLT', %w(VOLT CURR)],
# The name of another parameter can be supplied as the type argument, meaning that the type
# here will be either :current or :voltage depending on the value of :force_mode
force_value: [:force_mode, 3800.mV],
# In cases where the C++ library has deviated from standard attribute naming conventions
# (camel-cased with lower cased first character), the absolute attribute name can be given
# as a string.
# The Origen accessor for these will be the underscored version, with '.' characters
# converted to underscores e.g. tm.an_unusual_name
'An.UnusualName' => [:string, 'NO', %w(NO YES)],
# Attribute aliases can be defined like this:
aliases: {
my_name: 'An.UnusualName',
precharge: :precharge_voltage,
},
# Define any methods you want the test method to have
methods: {
# If you define a method called 'finalize', it will be called automatically before the test
# method is finally rendered, making it a good place to do any last minute attribute
# manipulation based on the final values that have been set by the user.
# The test method object itself will be passed in as an argument.
#
# In this example it will set the pre-charge if it has not already been set and a voltage is
# being forced above a given threshold.
finalize: -> (tm) {
if tm.force_mode == 'VOLT' && tm.precharge_voltage == 0 && tm.force_value > 3.5.V
# Set the pre-charge level to 1V below the force value
tm.precharge_voltage = tm.force_value - 1.V
end
},
# Example of a custom helper method, here to provide a single method to force a current and
# which will configure multiple test method attributes.
force_current: -> (tm, value) {
tm.force_mode = 'CURR'
tm.force_value = value
},
}
},
my_other_test: {
# Define another test in exactly the same way...
}
end
end
end
~~~
Here is an example of how the above definition might be used with test program interface logic:
~~~ruby
# An example method that can be called from your test flow to generate a DC measurement test like this:
#
# measure :vreg, force: 10.uA, lo_limit: 1.25, hi_limit: 1.75
#
# measure :iref, force: 1.2.V, lo_limit: 20.uA, hi_limit: 30.uA, type: :current
def measure(name, options={})
t = test_suites.add(name, options)
t.test_method = test_methods.my_tml.my_test(pin_list: '@')
if options[:type] == :current
# Force mode is 'VOLT' by default per the above definition
t.force_value = options[:force]
else
# Here calling the helper method to configure the method for force current mode
t.force_current(options[:force])
end
end
~~~
#### Distribute as a Plugin
Commonly, a custom test method library will not be specific to any one test program application and
it will be used by many test programs within a group or company.
In such a case, you don't want to have the Origen definition of the given library be duplicated in all
of your applications. Rather, it is preferable to develop and maintain the definition in a central place
and then include it in all of the applications that wish to use the library.
This can be easily achieved by wrapping the Origen definition
[in an Origen plugin](<%= path 'guides/plugins/introduction' %>).
Here is an example of how to package a library definition for inclusion in a plugin:
~~~ruby
# lib/my_library.rb within the my_library plugin
module MyLibrary
# Define the test methods from a custom V93K library
def add_my_library
# The definition here is identical to the original example above
add_tml :my_tml,
# [OPTIONAL] If you need the C++ namespace to be different to the above identifier then you can
# specify the C++ name like this:
class_name: 'MyTmlNamespace',
# Here is a test definition.
# The identifier should be lower-cased and underscored, in-keeping with Ruby naming conventions.
# By default the class name will be the camel-cased version of this identifier, so 'myTest' in
# this case.
my_test: {
# ...
end
end
# [OPTIONAL] You can also supply complete interface method definitions which use this library
# An example method that can be called from your test flow to generate a DC measurement test like this:
#
# measure :vreg, force: 10.uA, lo_limit: 1.25, hi_limit: 1.75
#
# measure :iref, force: 1.2.V, lo_limit: 20.uA, hi_limit: 30.uA, type: :current
def measure(name, options={})
t = test_suites.add(name, options)
t.test_method = test_methods.my_tml.my_test(pin_list: '@')
if options[:type] == :current
# Force mode is 'VOLT' by default per the above definition
t.force_value = options[:force]
else
# Here calling the helper method to configure the method for force current mode
t.force_current(options[:force])
end
end
end
~~~
Then simply add the plugin to a given application, and it can be used within an interface like this:
~~~ruby
module MyApp
class Interface
include OrigenTesters::ProgramGenerators
include MyLibrary
def initialize(options={})
add_my_library
end
# You don't need to do anything here, and your flow will already support the measure method!
# Some application-specific flow method that uses the library:
def some_test(name, options = {})
t = test_suites.add(name, options)
t.test_method = test_methods.my_tml.my_other_test
t.some_parameter = #...
end
end
end
~~~
For a more advanced integration which gets rid of the need to even call `add_my_library`, you
can refer to how the `origen_std_lib` interface integration works
[here](https://github.com/Origen-SDK/origen_std_lib/blob/master/plugin/lib/origen_std_lib.rb).
### Test Name Uniqueness
Test (suite) naming collisions can occur when importing multiple independent test flow modules into a
V93K master flow file.
To prevent that from ever occurring, Origen will generate and append a unique signature to the end of
all test names by default, for example:
~~~ruby
t = test_suites.add("my_test_name", options)
t.name # => "my_test_name_E32ABE8"
~~~
Applications can override this default behavior by setting the corresponding test interface attribute,
`unique_test_names`, to one of the following values:
* `:signature` - this is the default which will generate a unique signature as shown in the above example
* `nil` - no value will be appended to the test names at all
* `:flowname` - the name of the current top-level flow will be appended to all test names
* Setting this attribute to any other value will append that value directly to all test names
This attribute can be set in the [environment file](<%= path 'guides/runtime/environment' %>) when instantiating
the tester:
~~~ruby
OrigenTesters::V93K.new unique_test_names: nil
~~~
This provides a single place to control the behavior within a [monolithic application architecture](<%= path 'guides/starting/architecture/#Monolithic_Application_Architecture' %>).
However, under a [distributed application architecture](<%= path 'guides/starting/architecture/#Distributed_Application_Architecture' %>)
a given test flow module may be generated under a target/environment that is controlled by a 3rd party.
In that case, it is recommended to either set it at the flow-level, which will override any setting set at the
environment-level:
~~~ruby
# program/wt1_start.rb
Flow.create interface: 'MyApp::Interface', unique_test_names: 'wt1' do
end
~~~
Or, it can be set directly within your interface logic which will take the highest precedence:
~~~ruby
# lib/my_app/interface.rb
self.unique_test_names = :flowname
~~~
% end