origen_testers 0.19.0 → 0.19.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|