Pattern Generator
Creating Patterns
Patterns are generated by regular Ruby files that should live within the pattern
directory - a sub-directory within there is fine and is in fact encouraged to help
keep things organized as the number of patterns increases.
However keep in mind that each pattern should be uniquely named - i.e. no other files of the
same name should live in
any of the sub-directories of pattern
.
Each pattern file should have the following structure:
Pattern.create do
# Pattern specific content goes here
end
Startup and shutdown sequences will generally be the same for all patterns and these should be implemented by using the callbacks that support pattern generation.
Any options supplied to Pattern.create
will be passed into the startup
and
shutdown
methods when they are called, thereby providing a mechanism for per-pattern
customization of the startup/shutdown sequences.
Here is an example of an SoC controller with some startup and shutdown callbacks implemented:
class MyDeviceController
include Origen::Controller
def startup(options)
options = {
mode: :functional_test,
}.merge(options)
if options[:mode] == :functional_test
enter_functional_test_mode
elsif options[:mode] == :bist
enter_bist_test_mode
else
raise "Unknown mode requested - #{options[:mode]}"
end
end
def shutdown(options)
options = {
reset: true,
}.merge(options)
reset_device if options[:reset]
end
end
So by default this pattern will enter functional test mode at the start and reset the device at the end:
Pattern.create do
# Pattern specific content goes here
end
This one will enter BIST mode instead at the start:
Pattern.create(mode: :bist) do
# Pattern specific content goes here
end
and this one would exit without resetting the device:
Pattern.create(mode: :bist, reset: false) do
# Pattern specific content goes here
end
Origen provides a framework in which you can build very complex patterns that remain easy to maintain, but as with any tool it is also possible to use it to create something with which to hang yourself!
In order to avoid going down a path that will lead to an unmaintainable mess, it is strongly recommended that the following rules are observed:
- Patterns should not talk to the current tester object directly
- Patterns should not attempt to control pin states
- Patterns should not attempt to access registers directly
Probably the most tempting one to break is the last one, however generally manipulating register states outside of the owning model is a sign of poor application design and breaking the encapsulation that should be provided by a model representing a silicon module. Instead the model’s controller should provide an external interface which would remain constant even if the internal operation of a given operation changes significantly from one silicon revision to the next. See the Controller guides for more.
If the above rules are followed pattern source files should typically be very small and should generally only call a handful of methods on the target object(s), here are a few examples:
# Pattern to measure the output of the Vreg module
Pattern.create do
$dut.vreg.measure
end
# Pattern to measure the output of the Vreg module for a specific setting
Pattern.create do
$dut.vreg.measure(setting: 12)
end
# Pattern to program a checkerboard and then read it
Pattern.create do
$dut.nvm.program(pattern: :ckbd)
$dut.nvm.read(pattern: :ckbd)
end