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 API
for working with decompiled patterns from any platform. - Allow platforms to implement the
universal API
in 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 beSTIL
orWGL
. - 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 Source
by 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 Source
and 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::Pattern
class.
- 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
dut
object that does not have the pinstclk
,tms
,tdo
, ortdi
already 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:47005605984740>, :tdi=><Origen::Pins::Pin:47005605981520>, :tdo=><Origen::Pins::Pin:47005605978120>, :tms=><Origen::Pins::Pin:47005605991360>}
#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:47005605984740>, :tdi=><Origen::Pins::Pin:47005605981520>, :tdo=><Origen::Pins::Pin:47005605978120>, :tms=><Origen::Pins::Pin:47005605991360>}
pat.add_pins
#=> []
dut.pins
#=> {:tclk=><Origen::Pins::Pin:47005605984740>, :tdi=><Origen::Pins::Pin:47005605981520>, :tdo=><Origen::Pins::Pin:47005605978120>, :tms=><Origen::Pins::Pin:47005605991360>}
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