Decompilation
Overview & Example
Origen provides some basic functionality for decompiling, or reverse-compiling,
a pattern from its text representation (e.g., .atp for the J750 platform),
returning an object which Origen can work with.
The decompiler attempts to support two, somewhat competing, goals:
- Provide a
universal APIfor working with decompiled patterns from any platform. - Allow platforms to implement the
universal APIin such a way that still maintains the aspects only present on that particular platform (platform-specifics).
The aim is to provide the best of both worlds: a generic-enough,
universal API to accomplish most tasks, without regard to platform-specifics,
but not bar those platform-specifics completely in the event that such
a generic method either isn’t available, isn’t possible, or wouldn’t be applicable
across more than a single platform.
In the context of the decompilation sections, the following definition apply:
- Pattern Source: The text-representation of the a pattern.
- Platform: Producer of
Pattern Sources. In most cases, this will be an ATE, such asj750, orv93k, but this also could beSTILorWGL. - Platform-Specifics: Any aspect which separates this platform from another, outside of the actual parsing and grammar rules.
- (Decompiled) Pattern: The instance of an object returned after successful
decompilation of a
Pattern Sourceby aDecompiler.- Note, this will often be written fully as
decompiled pattern, to avoid additional confusion.
- Note, this will often be written fully as
- Decompiler: The object that takes a
Pattern Sourceand returns aPattern. There are two flavors of this:- In some context, this will be the
generic Decompiler, that is, the abstract base which, itself, can’t actually decompile anything. - However, in most contexts this will refer to a specific platform.
For example, “the J750 decompiler”, refers to the J750’s implementation of the
generic decompiler, or theOrigenTesters::IGXLBasedTester::Patternclass.
- In some context, this will be the
This example shows some basic usage of the decompiler, without assuming you have
a pattern source for a supported platform ready to go. This example makes use of the J750 platform.
If you aren’t familiar with this platform, don’t worry; understanding of the pattern source format is not a requirement
for using the decompiler, specifically in the sense of the universal API.
In order to follow along with these examples, you will need:
- Some
dutobject that does not have the pinstclk,tms,tdo, ortdialready defined (you can still follow along, but you will not receive identical return values from#add_pins(covered later) if these pins are already defined).
The first step to working with a pattern source in Origen is to decompile said source.
The decompiler is accessed directly on the OrigenTesters module, and contains
methods to decompile a source from a given input string.
Consider the source, from a J750 .atp, below:
// Sample pattern text for the J750
// Source located at: lib/origen_testers/igxl_based_tester/decompiler
import tset tp0;
svm_only_file = no;
opcode_mode = extended;
compressed = yes;
vector ($tset, tclk, tdi, tdo, tms)
{
start_label pattern_st:
// Start of vector body
repeat 2 > tp0 X X X X ; // First Vector
repeat 5 > tp0 1 0 X 1 ;
end_module > tp0 X X X X ; // Last Vector
}
Placing this in a String, we can decompile this directly using the the
#decompile_text method and providing the target decompiler:
String already:
OrigenTesters::IGXLBasedTester.sample_direct_source
# A very basic, pre-defined .atp source for the J750 platform
src = OrigenTesters::IGXLBasedTester.sample_direct_source
# Decompile this source.
pat = OrigenTesters.decompile_text(src, decompiler: OrigenTesters::IGXLBasedTester::Pattern)
#=> OrigenTesters::IGXLBasedTester::Pattern object
Since we’ve specified that this is an IGXLBasedTester source, the #decompile_text method
will use that as the target decompiler and return an object corresponding to
that specific platform’s decompiler: OrigenTesters::IGXLBasedTester::Pattern.
If you have your own pattern source you’d rather compile, the #decompile method
will accept a filename either as a String or Pathname object:
pat = OrigenTesters.decompile('path/to/src.atp')
#=> (for a source ending with .atp)
#=> OrigenTesters::IGXLBasedTester::Pattern object
Now, we can interact with our decompiled pattern. Some easy things we may want to do:
- Query which pins are present in the pattern source
- Add those pins to the
DUT - Iterate through the vectors, printing the repeat count and the pin states
- Execute the source in its entirety, in the context of the current
DUT
There’s two methods available to retrieve the pins: #pins and #pin_sizes.
# Return an array of pins, in the order they appear in the pattern
pat.pins
#=> [:tclk, :tdi, :tdo, :tms]
# Return the pin names and their respective size
pat.pin_sizes
#=> {:tclk=>1, :tdi=>1, :tdo=>1, :tms=>1}
One of the most common operations with respect to the pins is to simply add any
missing pins to the current dut. The decompiled pattern has a built-in method
to do just that:
# Assume the current dut has no pins
dut.pins
#=> {}
pat.add_pins
#=> [:tclk, :tdi, :tdo, :tms]
dut.pins
#=> {:tclk=><Origen::Pins::Pin:47002383086100>, :tdi=><Origen::Pins::Pin:47002383082480>, :tdo=><Origen::Pins::Pin:47002383109240>, :tms=><Origen::Pins::Pin:47002383145880>}
#add_pins will return any pins it added to the dut. For example, if the dut
already had all the pins from the pattern defined, #add_pins would’ve returned
an empty array. Running the above a second time:
# Assume the current dut has no pins
dut.pins
#=> {:tclk=><Origen::Pins::Pin:47002383086100>, :tdi=><Origen::Pins::Pin:47002383082480>, :tdo=><Origen::Pins::Pin:47002383109240>, :tms=><Origen::Pins::Pin:47002383145880>}
pat.add_pins
#=> []
dut.pins
#=> {:tclk=><Origen::Pins::Pin:47002383086100>, :tdi=><Origen::Pins::Pin:47002383082480>, :tdo=><Origen::Pins::Pin:47002383109240>, :tms=><Origen::Pins::Pin:47002383145880>}
We can iterate through each ‘vector’ in the decompiled pattern with #each_vector.
This method takes a block and runs it for each ‘vector’ encountered. Notice the
quotes around ‘vector’. Each v in the example above is actually a VectorBodyElement object
that acts as a placeholder for any element type that could appear.
Each vector body element has a type associated with it to discern exactly
what it is:
pat.each_vector { |v| puts v.type }
:start_label
:comment_block
:vector
:vector
:vector
#=> nil
Now that we have the type, we can access the underlying element.
In the example below, we’ll check the type first and, in the event of a :vector,
access the underlying element and print its repeat count and pin states.
pat.each_vector { |v| puts "(#{v.element.repeat}) #{v.element.pin_states}" if v.type == :vector }
(2) ["X", "X", "X", "X"]
(5) ["1", "0", "X", "1"]
(1) ["X", "X", "X", "X"]
#=> nil
#each_vector returns nil, NOT an
array containing all the vectors like a normal `each` method would do.
See the section on working with vectors
for why this is the case.
There’s much more to vectors and vector types. See the vectors section for further details.
Now that we’ve added any missing pins to our dut and we’ve seen how to access
the vectors themselves, we can execute the pattern source. The #execute
method will iterate through each vector, apply the pin states, and
cycle the tester repeat number of times.
pat.execute