Pattern Generator
Common API
All tester drivers support the common API described in this guide. By building your patterns using this API your will be able to generate them for any ATE that is supported by Origen.
Some tester drivers may expose additional methods to leverage some key features of the given ATE which do not have direct equivalents on other systems. You may or may not choose to use these in your application. If you do, then be aware that you are introducing some logic which cannot be automatically translated to other ATEs. In that case you will have to implement the alternative implementation for other platforms on the application side, something like this:
if $tester.uflex?
# An implementation that uses a method that only exists on the UltraFLEX driver,
# this will make the test run more efficiently on that platform
else
# Conventional implementation using the common API for all other platforms
end
Of course some applications may only ever wish to target a specific ATE, in that case you can freely pick from the common and ATE-specific APIs.
This API is currently provided by the Origen Testers plugin. In addition to the primary methods discussed below, all tester drivers support the methods described in the following API docs:
Here are each of the main methods supported by the common API.
These are the basic methods for generating vectors.
cycle(options = {})
Generate a tester cycle or cycles:
$tester.cycle
$tester.cycle repeat: 1000
As this is such a commonly used method, there are some convenience methods available, this is equivalent to the above example:
1.cycle
1000.cycles
A very common pattern when working at this level is to setup some pin states and then trigger a cycle:
pin(:tdi).drive(1)
$tester.cycle
pin(:tdi).drive(0)
$tester.cycle
All of the pin state methods support a bang (!
) variant which will automatically
call a single cycle after setting the pin state, this is equivalent to the above:
pin(:tdi).drive!(1)
pin(:tdi).drive!(0)
wait(options = {})
Repeats the last vector for the specified about of time. The time can be specified in cycles or a time, multiple arguments will be added together:
$tester.wait cycles: 1000 # Equivalent to $tester.cycle(repeat: 1000)
$tester.wait time_in_us: 1000 # Wait for 1000us
$tester.wait time_in_ms: 1 # Wait for 1ms
$tester.wait time_in_ms: 1, time_in_us: 1000, cycles: 100 # Wait for 2ms + 100 cycles
The wait method can also be called with additional arguments to generate a dynamic wait, i.e. a match loop. Here for example to wait for up to 2 seconds for the done pin to go high:
$tester.wait match: true, time_in_s: 2, pin: pin(:done), state: :high
The above API is somewhat verbose, a cleaner one is available by supplying a block to generate the vectors which much pass for the match to resolve. This is equivalent to the previous example:
$tester.wait match: true, time_in_s: 2 do
pin(:done).assert!(1)
end
This block form also allows much more complex match conditions to be described, here to wait for either the fail pin to go high, OR the done pin to go high:
$tester.wait match: true, time_in_s: 2 do |conditions, fail|
conditions.add do
pin(:done).assert!(1)
end
conditions.add do
pin(:fail).assert!(1)
end
end
To AND these conditions would simply be:
$tester.wait match: true, time_in_s: 2 do
pin(:done).assert(1)
pin(:fail).assert(1)
1.cycle
end
ignore_fails(*pins)
Ignore fails on the given pins for the duration of the given block, this has the effect of temporarily setting the states of the given pins to don’t care.
# Temporarily ignore mis-compares on the fail and data pins
$tester.ignore_fails(pin(:fail), pins(:data)) do
# Any vectors generated in here will force the state of the given pins to X
end
store(*pins)
Instruct the tester to capture the data on the given pins from the vector that was generated last, note that it does not actually generate a new vector.
Sometimes when generating vectors within a loop you may want to retrospectively capture a previous vector, passing in an offset option will allow you to do this.
Here are some examples:
$tester.cycle # This is the vector that we want to capture
$tester.store pin(:d0), pin(:d1) # Capture the data on the d0 and d1 pins
$tester.cycle # This one gets stored
$tester.cycle
$tester.cycle
$tester.store pin(:d0), pin(:d1), offset: -2 # Just realized I need to capture that earlier vector
Note that this API is for engineers who are writing protocol drivers, most test IP would be written at a higher level, e.g.
atd_result.data.store! # Capture the value of the ATD result bits to the tester
store_next_cycle(*pins)
Similar to the above, this API allows driver creators to indicate that the next vector, wherever that may be generated, should be captured:
$tester.store_next_cycle pin(:d0), pin(:d1)
# This is the vector that will be captured, in real life this could be done after returning
# to a caller
$tester.cycle
capture_style
Testers support different ways of capturing vector data. For all tester types the default capture style is hram (history ram). For UltraFlex digcap is additionally supported. Change from the default like this:
# change capture style
# if the digcap isn't support for the current tester, default behavior (hram) is used
tester.capture_style = :digcap
# change back to hram capture style
tester.capture_style = :hram
# temporarily change the capture style for this cycle
tester.store_next_cycle pin(:d0), capture_style: :digcap
configure capture memory
Origen will create any instrument definitions required when capture memory is used. However, it may be desirable to alter the configuration settings. Here is an example of how to do this:
# configure TDO as a 16-bit instrument (default size is the number of pins - 1 in this case)
tester.capture_memory :digcap do |mem|
mem.pin :tdo, size: 16
end
overlay
Testers support different ways of modifying vector data during run time. This practice is referred to here as “overlay”. Overlay is requested through an optional argument to cycle:
# setup overlay parameters
overlay_options = {}
# Required - what pin(s) are being overlayed?
overlay_options[:pins] = dut.pin(:tdi)
# Required - what is the overlay string? This will become a label or subroutine name
overlay_options[:overlay_str] = ovl_reg[i].overlay_str
tester.cycle overlay: overlay_options
# Generate another overlay cycle, holding the same data as the previous cycle
overlay_options[:change_data] = false
tester.cycle overlay: overlay_options
# Now a new piece of data needs to be sent
overlay_options[:change_data] = true
tester.cycle overlay: overlay_options
overlay_style
The default overlay style is subroutine (vectors that will be modified are replaced by a call to a subroutine). Change from the default like this:
# if requested sytle is not available for the current tester it will default to :subroutine
tester.overlay_style = :digsrc
tester.overlay_style = :subroutine
tester.overlay_style = :label
tester.overlay_style = :handshake
# change the overlay style for this cycle only by adding :overlay_style to the overlay_options
overlay_options[:overlay_style] = :label
tester.cycle overlay: overlay_options
Not all overlay styles are supported on all testers and if the requested style is not supported a warning will be logged and it will fall back to the default style (:subroutine).
Here is a brief summary of what each type does:
- digsrc
- The vectors to be modified are updated with the data value held in a tester memory.
- subroutine
- The vectors to be modified are removed from the pattern and replaced by a call to a another (subroutine) pattern.
- label
- A label is inserted into the pattern immediately before the vectors to be modified.
- handshake
- The vectors to be modified are removed from the pattern and replaced by a handshake with the tester.
configure source memory
Origen will create any necessary instruments statements. Add configuration information to source memory like this:
tester.source_memory do |mem|
mem.pin :tdi, size: 32, format: :binary, data_type: :long
end
start_subroutine(name), end_subroutine
Use these methods to write a pattern subroutine:
$tester.start_subroutine "wait_for_done"
$tester.wait match: true, time_in_s: 2 do
pin(:done).assert!(1)
end
$tester.end_subroutine
call_subroutine(name, options = {})
Call a pattern subroutine, an offset can be given to retrospectively jump to a subroutine from a previous vector:
$tester.call_subroutine "wait_for_done"
1.cycle
1.cycle # A branch will also be made after completing this vector
1.cycle
1.cycle
$tester.call_subroutine "wait_for_done", offset: -2
label(name)
Inject an arbitrary label into the pattern:
$tester.label "on_failed"
branch_to(label)
Branch to a label:
$tester.branch_to "on_failed"
loop_vectors(name, number_of_loops)
Execute the vectors generated within the given block n times:
$tester.loop_vectors("my_loop", 3) do # Do this 3 times...
$tester.cycle
end
freq_count(pin)
Setup to measure the frequency on the given pin:
$tester.freq_count pin(:clk_out)
microcode(code, options = {})
This can be used to inject arbitrary microcode into the pattern, which of course is inherently coupling your logic to a specific test platform - so use sparingly!
An offset can be given to apply the microcode to previously generated vectors.
$tester.microcode 'set_cpu (cpuC)'
1.cycle
1.cycle # cpuB will be set here
1.cycle
1.cycle
$tester.microcode 'set_cpu (cpuB)', offset: -2
Free-Running Clock on Existing Pin
Set up a pin to be a free-running clock with the vector generation (with respect to toggling the pin at the appropriate intervals) automatically taken care of.
See Pin Clock Functionality for details on the API.