origen_testers 0.19.0 → 0.19.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/config/application.rb +34 -1
- data/config/version.rb +1 -1
- data/lib/origen_testers/flow.rb +1 -0
- data/lib/origen_testers/interface.rb +28 -0
- data/lib/origen_testers/pattern_compilers/v93k.rb +3 -1
- data/lib/origen_testers/smartest_based_tester/base.rb +14 -1
- data/lib/origen_testers/smartest_based_tester/base/test_methods/ac_tml.rb +10 -10
- data/lib/origen_testers/test/interface.rb +3 -0
- data/pattern/tester_overlay.rb +12 -1
- data/program/_erase.rb +1 -1
- data/program/components/_prb1_main.rb +3 -3
- data/program/test.rb +2 -2
- data/templates/origen_guides/pattern/common.md.erb +376 -0
- data/templates/origen_guides/pattern/creating.md.erb +133 -0
- data/templates/origen_guides/pattern/custom.md.erb +5 -0
- data/templates/origen_guides/pattern/documenting.md.erb +431 -0
- data/templates/origen_guides/pattern/introduction.md.erb +38 -0
- data/templates/origen_guides/pattern/j750.md.erb +10 -0
- data/templates/origen_guides/pattern/name.md.erb +511 -0
- data/templates/origen_guides/pattern/pins.md.erb +125 -0
- data/templates/origen_guides/pattern/registers.md.erb +300 -0
- data/templates/origen_guides/pattern/running.md.erb +105 -0
- data/templates/origen_guides/pattern/timing.md.erb +281 -0
- data/templates/origen_guides/pattern/ultraflex.md.erb +10 -0
- data/templates/origen_guides/pattern/v93k.md.erb +41 -0
- data/templates/origen_guides/program/code.md.erb +78 -0
- data/templates/origen_guides/program/custom.md.erb +5 -0
- data/templates/origen_guides/program/doc.md.erb +402 -0
- data/templates/origen_guides/program/flowapi.md.erb +249 -0
- data/templates/origen_guides/program/flows.md.erb +429 -0
- data/templates/origen_guides/program/generating.md.erb +97 -0
- data/templates/origen_guides/program/interface.md.erb +248 -0
- data/templates/origen_guides/program/introduction.md.erb +56 -0
- data/templates/origen_guides/program/j750.md.erb +514 -0
- data/templates/origen_guides/program/philosophy.md.erb +99 -0
- data/templates/origen_guides/program/resources.md.erb +141 -0
- data/templates/origen_guides/program/ultraflex.md.erb +5 -0
- data/templates/origen_guides/program/v93k.md.erb +456 -0
- data/templates/web/layouts/_guides.html.erb +10 -0
- data/templates/web/partials/_placeholder.md.erb +10 -0
- metadata +33 -5
@@ -0,0 +1,38 @@
|
|
1
|
+
% render "layouts/guides.html" do
|
2
|
+
|
3
|
+
Origen was initially conceived to be a pattern generator and as you would
|
4
|
+
expect it provides
|
5
|
+
powerful APIs to generate tester patterns from your device models.
|
6
|
+
These APIs endeavour to abstract as much of the underlying ATE API as possible
|
7
|
+
so that quite often all that is required to switch ATE platforms is to change
|
8
|
+
the tester model instantiated by the environment.
|
9
|
+
|
10
|
+
With Origen, an application can also easily create custom tester
|
11
|
+
drivers which (for example) can be used to generate patterns in a format that
|
12
|
+
can be run on
|
13
|
+
the bench (as a J-Link command file for example) or in a functional
|
14
|
+
simulation - basically generating your pattern as a Verilog stimulus file.
|
15
|
+
|
16
|
+
Origen is a simulation-less pattern generation tool and it is therefore very
|
17
|
+
quick and lightweight compared to more traditional simulation-based pattern generation
|
18
|
+
workflows.
|
19
|
+
When combined with the growing number of quality [Origen plugins](<%= path "plugins" %>)
|
20
|
+
that are available to provide common hardware (e.g. JTAG) and protocol drivers
|
21
|
+
(e.g. ARM Debug, Nexus), the speed of pattern development that can be
|
22
|
+
achieved with Origen is unrivaled. With a bit of practice you can literally go from
|
23
|
+
nothing to a working pattern for a new application within 10 minutes.
|
24
|
+
|
25
|
+
#### Use Simulations for What They Are Good At
|
26
|
+
|
27
|
+
Simulations still have their place, after all they are the only way to get pre-silicon
|
28
|
+
feedback on whether a given pattern will actually work or not.
|
29
|
+
An Origen-based workflow can still make heavy use of simulations for pre-silicon
|
30
|
+
validation of test IP, however the downsides of requiring a simulation to actually
|
31
|
+
generate a pattern (workflow complexity, slow generation times) are removed.
|
32
|
+
|
33
|
+
This leads to much quicker turn around of pattern changes, which means that they can be regenerated
|
34
|
+
in real time while debugging on the tester.
|
35
|
+
|
36
|
+
<img src="<%= path "img/pattern_workflow.png" %>" style="display: block; margin: auto; width: 400px; height: 306px;">
|
37
|
+
|
38
|
+
% end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
% render "layouts/guides.html" do
|
2
|
+
|
3
|
+
This page will be used to document any J750-only APIs related to pattern generation,
|
4
|
+
however the goal is to have as few of these as possible so that Origen pattern source code can re-target
|
5
|
+
automatically to any supported platform.
|
6
|
+
|
7
|
+
There are no significant APIs in this category currently, therefore refer to the
|
8
|
+
[Common Pattern API](<%= path "guides/pattern/common" %>) which can fully target the J750.
|
9
|
+
|
10
|
+
% end
|
@@ -0,0 +1,511 @@
|
|
1
|
+
% render "layouts/guides.html" do
|
2
|
+
|
3
|
+
In a large application the number of pattern source files can grow very large, for example in the
|
4
|
+
flagship Origen application we grew to having more than 1500 pattern source files
|
5
|
+
at one time!
|
6
|
+
In such a case even if you follow the
|
7
|
+
[golden rules for building maintainable patterns](<%= path "guides/pattern/creating" %>)
|
8
|
+
the fact that there are so many of them becomes a maintenance concern by itself and
|
9
|
+
worries start to creep in about whether all of the patterns really implement a given operation
|
10
|
+
in exactly the same way.
|
11
|
+
|
12
|
+
Even if you don't have so many patterns it can still become tedious to have to manually
|
13
|
+
create the pattern every time a new test is added or modified, wouldn't it be nice if
|
14
|
+
the pattern just created itself?!
|
15
|
+
|
16
|
+
With Origen this is possible as long as your patterns lend themselves to being fully described
|
17
|
+
by a naming convention. In short if it is possible to uniquely describe your pattern behavior
|
18
|
+
with a name then it is possible to synthesize that pattern from that name - this is goal of
|
19
|
+
sourceless pattern generation with Origen.
|
20
|
+
|
21
|
+
This feature is particularly powerful when combined with the
|
22
|
+
[Origen program generator](<%= path "guides/program/introduction" %>), since it means that
|
23
|
+
your test program flow file becomes the only place where you define a test and the program
|
24
|
+
generator will output a list of required pattern names. This can then be passed to the pattern
|
25
|
+
generator which can synthesize all of the patterns without needing to create any pattern
|
26
|
+
sources at all.
|
27
|
+
Once you have invested some time in building a test program interface and sourceless
|
28
|
+
pattern capability you can get to the point where to create a new test all you need to do
|
29
|
+
is add a single line to the test flow and you are done! That level of automation and
|
30
|
+
efficiency is simply not possible from any other test engineering framework.
|
31
|
+
|
32
|
+
#### Enabling Name-Based Generation
|
33
|
+
|
34
|
+
This feature is enabled via the <code>before_pattern_lookup</code>
|
35
|
+
[callback](<%= path "guides/misc/callbacks" %>) which will be called immediately
|
36
|
+
before Origen looks for a pattern source for the given pattern generation request.
|
37
|
+
If this method returns false then Origen will cease processing that pattern and will
|
38
|
+
assume that the application has dealt with the request. If the method returns
|
39
|
+
the requested pattern name then the regular pattern lookup and generation flow
|
40
|
+
will proceed as normal.
|
41
|
+
|
42
|
+
It is recommended that you create a dedicated class called a pattern dispatcher within
|
43
|
+
your application which will handle deciding whether or not a pattern request
|
44
|
+
can be synthesized without a source file and then if so handle the synthesis and
|
45
|
+
generation.
|
46
|
+
|
47
|
+
Add these lines to your <code>application.rb</code> file to engage a pattern dispatcher
|
48
|
+
(where MyApp is your application's namespace):
|
49
|
+
|
50
|
+
~~~ruby
|
51
|
+
# config/application.rb
|
52
|
+
def before_pattern_lookup(requested_pattern)
|
53
|
+
MyApp::PatternDispatcher.new.dispatch_or_return(requested_pattern)
|
54
|
+
end
|
55
|
+
~~~
|
56
|
+
|
57
|
+
Then create an initial pattern dispatcher shell like this:
|
58
|
+
|
59
|
+
~~~ruby
|
60
|
+
# lib/my_app/pattern_dispatcher.rb
|
61
|
+
module MyApp
|
62
|
+
class PatternDispatcher
|
63
|
+
|
64
|
+
def dispatch_or_return(requested_pattern)
|
65
|
+
requested_pattern
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
~~~
|
71
|
+
|
72
|
+
This initial dispatcher simply returns the requested pattern name, therefore Origen will
|
73
|
+
behave as normal and look for a source file for every pattern request.
|
74
|
+
|
75
|
+
Even if you adopt sourceless pattern generation for your application it is likely that
|
76
|
+
you will still want to support conventional generation as well - having the ability
|
77
|
+
to quickly hack together a engineering pattern at short notice is something that is
|
78
|
+
most easily achieved by making a dedicated pattern source file.
|
79
|
+
|
80
|
+
So the first question is what should be the default behavior - sourceless or lookup?
|
81
|
+
|
82
|
+
If sourceless is the default then you can implement a convention where if a pattern
|
83
|
+
name contains 'custom' then a source file will be expected. If lookup is the default
|
84
|
+
then you could have the opposite convention where 'nosrc' in the pattern name means
|
85
|
+
that it should be generated without a source.
|
86
|
+
|
87
|
+
Let's go with sourceless being the default, here is how to modify the <code>dispatch_or_return</code>
|
88
|
+
method to do that:
|
89
|
+
|
90
|
+
~~~ruby
|
91
|
+
def dispatch_or_return(requested_pattern)
|
92
|
+
# If the pattern name contains 'custom' just return the name to have Origen lookup a source file for it
|
93
|
+
if requested_pattern =~ /custom/
|
94
|
+
requested_pattern
|
95
|
+
else
|
96
|
+
generate(requested_pattern)
|
97
|
+
false # Return false to Origen to prevent std pattern dispatch
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def generate(requested_pattern)
|
102
|
+
# Logic to generate the pattern to be added here
|
103
|
+
end
|
104
|
+
~~~
|
105
|
+
|
106
|
+
Now you can see the influence of the pattern dispatcher for the first time, any requests
|
107
|
+
containing 'custom' will be processed as normal and any requests without this will
|
108
|
+
do nothing.
|
109
|
+
|
110
|
+
#### How to Generate a Pattern
|
111
|
+
|
112
|
+
A pattern can be generated from within the dispatcher in much the same way as it is
|
113
|
+
generated within a regular pattern source file.
|
114
|
+
|
115
|
+
Here our <code>generate</code> method will now produce an empty pattern:
|
116
|
+
|
117
|
+
~~~ruby
|
118
|
+
def generate(requested_pattern)
|
119
|
+
Pattern.create(name: requested_pattern) do
|
120
|
+
# Logic to generate the pattern to be added here
|
121
|
+
end
|
122
|
+
end
|
123
|
+
~~~
|
124
|
+
|
125
|
+
Within the <code>Pattern.create</code> block you can call the exact same methods
|
126
|
+
that you would use in a regular pattern source, the difference of course is that
|
127
|
+
here we want to dynamically create them based on the name rather than hard-coding
|
128
|
+
them for a specific pattern.
|
129
|
+
|
130
|
+
By going this route you also have to currently pick up a bit more responsibility
|
131
|
+
for pre-processing the requested pattern name. For example via the regular
|
132
|
+
dispatch mechanism Origen will clean up the name to remove things like a path,
|
133
|
+
file extension, and pre and post-fixes that may or may not be present. In other
|
134
|
+
words Origen allows you to very flexible over what name you request, for example
|
135
|
+
these are equivalent:
|
136
|
+
|
137
|
+
~~~text
|
138
|
+
origen g bistcom
|
139
|
+
origen g output/p2/nvm_bistcom_debug.atp
|
140
|
+
~~~
|
141
|
+
|
142
|
+
In due course the internal Origen methods may be exposed via an API, but for now
|
143
|
+
your pattern dispatcher will have to deal with it (if you want to continue to
|
144
|
+
have this flexibility).
|
145
|
+
|
146
|
+
Here is an example method that you can use for this:
|
147
|
+
|
148
|
+
~~~ruby
|
149
|
+
def generate(requested_pattern)
|
150
|
+
requested_pattern = clean_pattern_name(requested_pattern)
|
151
|
+
Pattern.create(name: requested_pattern) do
|
152
|
+
# Logic to generate the pattern to be added here
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def clean_pattern_name(name)
|
157
|
+
name = Pathname.new(name).basename.to_s # Strip path
|
158
|
+
name.sub!(/\..*/, "") # Strip any and all extensions
|
159
|
+
name.sub!(/^nvm_/, "") # Strip prefix, this will unique to your app, here 'nvm_' is removed
|
160
|
+
name.sub!(/_debug$/, "") # Strip postfix, again unique to your app, here '_debug' occurring at the end is removed
|
161
|
+
name
|
162
|
+
end
|
163
|
+
~~~
|
164
|
+
|
165
|
+
Now you should be able to create (albeit empty) patterns via your dispatcher in the
|
166
|
+
same way as via the regular generator.
|
167
|
+
|
168
|
+
#### Renaming Your Patterns to Make Parsing Easier
|
169
|
+
|
170
|
+
To generate patterns by name you obviously need to have a comprehensive naming convention
|
171
|
+
from which the behavior of each pattern can be fully described, you may even have
|
172
|
+
this already in place.
|
173
|
+
|
174
|
+
However what is easy for a human to parse from a naming convention is not necessarily
|
175
|
+
easy for a computer.
|
176
|
+
For example your patterns may have the general format:
|
177
|
+
|
178
|
+
~~~text
|
179
|
+
<parameter set>_<operation>_<identifier>_<block>
|
180
|
+
~~~
|
181
|
+
|
182
|
+
Here are a couple of examples:
|
183
|
+
|
184
|
+
~~~text
|
185
|
+
prb_pgm_ckbd_b0 # Program a checkerboard to block 0, using probe parameters
|
186
|
+
ft_pgm_ckbd_b0 # Program a checkerboard to block 0, using FT parameters
|
187
|
+
~~~
|
188
|
+
|
189
|
+
That's fine, but what if these are allowed:
|
190
|
+
|
191
|
+
~~~text
|
192
|
+
pgm_ckbd_b0 # Program a checkerboard to block 0, using default parameters
|
193
|
+
pgm_ckbd_20us_b0 # Program a checkerboard to block 0, using default parameters + 20us programming time
|
194
|
+
~~~
|
195
|
+
|
196
|
+
Again easy enough to understand, but we have just introduced somethings that will be
|
197
|
+
difficult to interpret by our pattern dispatcher. Firstly how do we know if 'pgm'
|
198
|
+
is a reference to an operation or a parameter set?
|
199
|
+
|
200
|
+
One initial way to deal with it is to say that unspecified defaults are not allowed,
|
201
|
+
but that would quickly get out of hand as it would mean that every pattern would need
|
202
|
+
to declare every variable which is not realistic. So we need a way to unambiguously say
|
203
|
+
from the pattern name what each field represents.
|
204
|
+
|
205
|
+
Similarly in the 2nd example we have further qualified the program operation with '20us',
|
206
|
+
but again this is going to add a lot of complexity to our parser - what does that field
|
207
|
+
really represent? Is it program time, settling time, something else? Once again attaching
|
208
|
+
something to the field name is going to really help us out when it comes to parsing and
|
209
|
+
generating the pattern.
|
210
|
+
|
211
|
+
So how can we re-write these examples to make our lives easier. Well one of the existing
|
212
|
+
fields already has a good example for us. In the patterns above we have 'b0' which has
|
213
|
+
unwittingly created the convention that a block reference within a pattern will consist
|
214
|
+
of 'b' followed by a number. This is exactly the kind of thing that we can deal with easily.
|
215
|
+
|
216
|
+
So extending that convention to prefix each field with a short mnemonic describing what it
|
217
|
+
refers to we end up with:
|
218
|
+
|
219
|
+
~~~text
|
220
|
+
paraprb_oppgm_patckbd_b0 # Program a checkerboard to block 0, using probe parameters
|
221
|
+
paraft_oppgm_patckbd_b0 # Program a checkerboard to block 0, using FT parameters
|
222
|
+
oppgm_patckbd_b0 # Program a checkerboard to block 0, using default parameters
|
223
|
+
oppgm_patckbd_tprog20_b0 # Program a checkerboard to block 0, using default parameters + 20us programming time
|
224
|
+
~~~
|
225
|
+
|
226
|
+
So we have paid a penalty here with a pattern name that is a bit more verbose than it really
|
227
|
+
needs to be, but it is a small price to pay for being able to drop pattern sources
|
228
|
+
completely and to end up with a relatively simple pattern dispatcher.
|
229
|
+
|
230
|
+
#### Parsing the Pattern Name
|
231
|
+
|
232
|
+
To create an automated pattern dispatcher you are going to have to get familiar with
|
233
|
+
regular expressions (regexs). Providing a tutorial on this is beyond the scope of this guide, but
|
234
|
+
a Google search for 'regular expression tutorial' should yield many resources to learn
|
235
|
+
from.
|
236
|
+
|
237
|
+
The following website is highly recommended to keep close by while developing your
|
238
|
+
dispatcher - [www.rubular.com](http://www.rubular.com). Aside from having a quick reference
|
239
|
+
guide to the Ruby regex syntax it has a live panel which you can paste in your pattern name
|
240
|
+
and then experiment with the regex to ensure the correct thing is matched.
|
241
|
+
Best of all you can even save a given regex setup and
|
242
|
+
paste the link into into your code comments for future reference.
|
243
|
+
|
244
|
+
The parsing methods you will need to implement are very much dependent on your application and
|
245
|
+
naming convention, however a good way to get started is to
|
246
|
+
define a method to handle each field. This breaks down the parsing into manageable chunks
|
247
|
+
and also gives you a convenient place to set defaults.
|
248
|
+
Here are some examples
|
249
|
+
(here assuming that the requested pattern
|
250
|
+
has been assigned to an instance variable by upstream code):
|
251
|
+
|
252
|
+
~~~ruby
|
253
|
+
# An example of a required field
|
254
|
+
def operation
|
255
|
+
if @requested_pattern =~ /(^|_)op(\w+?)(_|$)/
|
256
|
+
$2
|
257
|
+
else
|
258
|
+
raise "No operation was contained in pattern: #{@requested_pattern}"
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
# An example of an optional field with a default
|
263
|
+
def parameter_set
|
264
|
+
if @requested_pattern =~ /(^|_)para(\w+?)(_|$)/
|
265
|
+
$2
|
266
|
+
else
|
267
|
+
"default" # Use the 'default' parameter set if not specified
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
# An example of an optional field that returns nil if not present, a default
|
272
|
+
# may or may not be assigned later within the patgen logic
|
273
|
+
def block
|
274
|
+
if @requested_pattern =~ /(^|_)b(\w+?)(_|$)/
|
275
|
+
$2
|
276
|
+
end
|
277
|
+
end
|
278
|
+
~~~
|
279
|
+
|
280
|
+
No doubt the regex code may look a bit daunting at first and unfortunately regexs are
|
281
|
+
unusual in that they tend to be easier to write than they are to read!
|
282
|
+
However we have basically used the same regex in all of the above examples and most likely
|
283
|
+
you could parse your entire pattern name like that.
|
284
|
+
|
285
|
+
Here is a walkthrough of how it works:
|
286
|
+
|
287
|
+
<div markdown="0">
|
288
|
+
<p>
|
289
|
+
<code> string =~ // </code> This is basic format of a regex, you can read this as
|
290
|
+
"does some section of the string match the rules inside //".
|
291
|
+
</p>
|
292
|
+
<p>
|
293
|
+
<code>/<strong style="font-size:18px">(^|_)</strong>para(\w+?)(_|$)/</code>
|
294
|
+
This means the start of the string (<code>^</code>) or an underscore...
|
295
|
+
</p>
|
296
|
+
<p>
|
297
|
+
<code>/(^|_)<strong style="font-size:18px">para</strong>(\w+?)(_|$)/</code>
|
298
|
+
...followed by the op code that we are trying to match.
|
299
|
+
</p>
|
300
|
+
<p>
|
301
|
+
<code>/(^|_)para<strong style="font-size:18px">(\w+?)</strong>(_|$)/</code>
|
302
|
+
Then we have the section that we want to capture. <code>\w</code> means a
|
303
|
+
word character, that is a letter, number or unfortunately an underscore.
|
304
|
+
The <code>+</code> means one or more of the previous characters. Since the
|
305
|
+
<code>\w</code> rule includes underscores by default this will match as many
|
306
|
+
occurences as possible, so it would continue matching through the next underscore
|
307
|
+
and into the next field, this is called a 'greedy' match. To prevent this we
|
308
|
+
add the <code>?</code> which tells it to match as little as possible, sometimes
|
309
|
+
called a 'lazy' match.
|
310
|
+
This whole section is surrounded in parenthesis which means 'capture the values
|
311
|
+
that correspond to this section'.
|
312
|
+
</p>
|
313
|
+
<p>
|
314
|
+
<code>/(^|_)para(\w+?)<strong style="font-size:18px">(_|$)</strong>/</code>
|
315
|
+
Finally stop at the end of the string (<code>$</code>) or an underscore.
|
316
|
+
</p>
|
317
|
+
</div>
|
318
|
+
|
319
|
+
Our regex contains 3 sets of parenthesis, the part of the string that matched this
|
320
|
+
section is available at the end via the variables <code>$1</code>, <code>$2</code>
|
321
|
+
and <code>$3</code>. The field we want to capture is in position two and therefore
|
322
|
+
our parse methods return this.
|
323
|
+
|
324
|
+
Here are links to see each of these in action and for you to experiment with:
|
325
|
+
|
326
|
+
* [operation](http://www.rubular.com/r/VNrfGJMifl)
|
327
|
+
* [parameter_set](http://www.rubular.com/r/VN6Bj5MqPg)
|
328
|
+
* [block](http://www.rubular.com/r/s7pdwIdxVJ)
|
329
|
+
|
330
|
+
As a final optimization note, with ruby parameters can be used in regexs in the same
|
331
|
+
way they can be used as strings, so actually we could abstract the regex portion of the
|
332
|
+
code to a method like this:
|
333
|
+
|
334
|
+
~~~ruby
|
335
|
+
def extract(op_code)
|
336
|
+
if @requested_pattern =~ /(^|_)#{op_code}(\w+?)(_|$)/
|
337
|
+
$2
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
def operation
|
342
|
+
extract("op") || raise("No operation was contained in pattern: #{@requested_pattern}")
|
343
|
+
end
|
344
|
+
|
345
|
+
def parameter_set
|
346
|
+
extract("para") || "default"
|
347
|
+
end
|
348
|
+
|
349
|
+
def block
|
350
|
+
extract("b")
|
351
|
+
end
|
352
|
+
~~~
|
353
|
+
|
354
|
+
#### Putting it All Together
|
355
|
+
|
356
|
+
Now that we can generate a list of build options from the requested name we can start to
|
357
|
+
generate the pattern.
|
358
|
+
|
359
|
+
One of the first jobs of the dispatcher is to generate the list of options
|
360
|
+
that should be passed into <code>Pattern.create</code>, in our example let's say that
|
361
|
+
the parameter set option is passed into our startup method via <code>Pattern.create</code>.
|
362
|
+
|
363
|
+
We can now do this by simply calling our <code>parameter_set</code> method:
|
364
|
+
|
365
|
+
~~~ruby
|
366
|
+
def generate(requested_pattern)
|
367
|
+
requested_pattern = clean_pattern_name(requested_pattern)
|
368
|
+
Pattern.create(name: requested_pattern, parameter_set: parameter_set) do
|
369
|
+
# Logic to generate the pattern to be added here
|
370
|
+
end
|
371
|
+
end
|
372
|
+
~~~
|
373
|
+
|
374
|
+
What happens inside the pattern block very much depends on your application patgen API
|
375
|
+
and if you are creating this from scratch
|
376
|
+
some thought should be given to designing it to lend itself to pattern synthesis.
|
377
|
+
In the flagship Origen application where this technique was first developed the original
|
378
|
+
API was not at all designed with this in mind. This led to an extremely complex pattern
|
379
|
+
dispatcher being required to handle all of the corner cases.
|
380
|
+
|
381
|
+
To make life simpler for pattern synthesis it is recommended that the API is kept very simple
|
382
|
+
with only a few methods being made available and all customization of the operation being
|
383
|
+
done via an options hash.
|
384
|
+
|
385
|
+
So for example a good API to handle our program checkerboard example might be:
|
386
|
+
|
387
|
+
~~~ruby
|
388
|
+
Pattern.create(params: :ft) do
|
389
|
+
$dut.nvm.pgm(pattern: :ckbd, tprog: 20, block: 0)
|
390
|
+
end
|
391
|
+
~~~
|
392
|
+
|
393
|
+
Which could then be synthesized via the following method:
|
394
|
+
|
395
|
+
~~~ruby
|
396
|
+
def generate(requested_pattern)
|
397
|
+
requested_pattern = clean_pattern_name(requested_pattern)
|
398
|
+
Pattern.create(name: requested_pattern, parameter_set: parameter_set) do
|
399
|
+
$dut.nvm.send operation, pattern: pattern,
|
400
|
+
tprog: tprog,
|
401
|
+
block: block
|
402
|
+
end
|
403
|
+
end
|
404
|
+
~~~
|
405
|
+
|
406
|
+
Even simpler would be:
|
407
|
+
|
408
|
+
~~~ruby
|
409
|
+
Pattern.create(params: :ft) do
|
410
|
+
$dut.nvm.execute(operation: :pgm, pattern: :ckbd, tprog: 20, block: block)
|
411
|
+
end
|
412
|
+
~~~
|
413
|
+
|
414
|
+
And the equivalent synthesizer method:
|
415
|
+
|
416
|
+
~~~ruby
|
417
|
+
def generate(requested_pattern)
|
418
|
+
requested_pattern = clean_pattern_name(requested_pattern)
|
419
|
+
Pattern.create(name: requested_pattern, parameter_set: parameter_set) do
|
420
|
+
$dut.nvm.execute operation: operation,
|
421
|
+
pattern: pattern,
|
422
|
+
tprog: tprog,
|
423
|
+
block: block
|
424
|
+
end
|
425
|
+
end
|
426
|
+
~~~
|
427
|
+
|
428
|
+
A clear pattern is starting to emerge now that for every supported option we have
|
429
|
+
a matching method of the same name in our dispatcher, so we can optimize this a bit:
|
430
|
+
|
431
|
+
~~~ruby
|
432
|
+
OPTIONS = %w(operation pattern tprog block)
|
433
|
+
|
434
|
+
def generate(requested_pattern)
|
435
|
+
requested_pattern = clean_pattern_name(requested_pattern)
|
436
|
+
options = {}
|
437
|
+
OPTIONS.each do |option|
|
438
|
+
options[:option] = self.send(option)
|
439
|
+
end
|
440
|
+
Pattern.create(name: requested_pattern, parameter_set: parameter_set) do
|
441
|
+
$dut.nvm.execute(options)
|
442
|
+
end
|
443
|
+
end
|
444
|
+
~~~
|
445
|
+
|
446
|
+
Now if we want to add support for a new option we just add it to the <code>OPTIONS</code>
|
447
|
+
array and create the corresponding parse method.
|
448
|
+
|
449
|
+
We can probably go one better.
|
450
|
+
|
451
|
+
As we have seen the parser methods are all very similar, do we really need them?
|
452
|
+
|
453
|
+
Not really as long as we are willing to defer default setting and error checking to our
|
454
|
+
models (where it probably makes more sense anyway).
|
455
|
+
|
456
|
+
Here is a complete pattern dispatcher in around 30 lines of code, where if you want to
|
457
|
+
add support for another field in the future just add it to the <code>OPTIONS</code>
|
458
|
+
definition that maps the option name to the pattern name op code:
|
459
|
+
|
460
|
+
~~~ruby
|
461
|
+
# lib/my_app/pattern_dispatcher.rb
|
462
|
+
module MyApp
|
463
|
+
class PatternDispatcher
|
464
|
+
|
465
|
+
OPTIONS = {
|
466
|
+
operation: "op",
|
467
|
+
pattern: "pat",
|
468
|
+
tprog: "tprog",
|
469
|
+
block: "b",
|
470
|
+
}
|
471
|
+
|
472
|
+
def generate(requested_pattern)
|
473
|
+
@requested_pattern = clean_pattern_name(requested_pattern)
|
474
|
+
options = {}
|
475
|
+
OPTIONS.each do |option, op_code|
|
476
|
+
options[:option] = extract(op_code)
|
477
|
+
end
|
478
|
+
Pattern.create(name: @requested_pattern, parameter_set: extract("para")) do
|
479
|
+
$dut.nvm.execute(options)
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
def extract(op_code)
|
484
|
+
if @requested_pattern =~ /(^|_)#{op_code}(\w+?)(_|$)/
|
485
|
+
$2
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
def dispatch_or_return(requested_pattern)
|
490
|
+
# If the pattern name contains 'custom' just return the name to have Origen lookup a source file for it
|
491
|
+
if requested_pattern =~ /custom/
|
492
|
+
requested_pattern
|
493
|
+
else
|
494
|
+
generate(requested_pattern)
|
495
|
+
false # Return false to Origen to prevent std pattern dispatch
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
def clean_pattern_name(name)
|
500
|
+
name = Pathname.new(name).basename.to_s # Strip path
|
501
|
+
name.sub!(/\..*/, "") # Strip any and all extensions
|
502
|
+
name.sub!(/^nvm_/, "") # Strip prefix, this will unique to your app, here 'nvm_' is removed
|
503
|
+
name.sub!(/_debug$/, "") # Strip postfix, again unique to your app, here '_debug' occurring at the end is removed
|
504
|
+
name
|
505
|
+
end
|
506
|
+
|
507
|
+
end
|
508
|
+
end
|
509
|
+
~~~
|
510
|
+
|
511
|
+
% end
|