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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/config/application.rb +34 -1
  3. data/config/version.rb +1 -1
  4. data/lib/origen_testers/flow.rb +1 -0
  5. data/lib/origen_testers/interface.rb +28 -0
  6. data/lib/origen_testers/pattern_compilers/v93k.rb +3 -1
  7. data/lib/origen_testers/smartest_based_tester/base.rb +14 -1
  8. data/lib/origen_testers/smartest_based_tester/base/test_methods/ac_tml.rb +10 -10
  9. data/lib/origen_testers/test/interface.rb +3 -0
  10. data/pattern/tester_overlay.rb +12 -1
  11. data/program/_erase.rb +1 -1
  12. data/program/components/_prb1_main.rb +3 -3
  13. data/program/test.rb +2 -2
  14. data/templates/origen_guides/pattern/common.md.erb +376 -0
  15. data/templates/origen_guides/pattern/creating.md.erb +133 -0
  16. data/templates/origen_guides/pattern/custom.md.erb +5 -0
  17. data/templates/origen_guides/pattern/documenting.md.erb +431 -0
  18. data/templates/origen_guides/pattern/introduction.md.erb +38 -0
  19. data/templates/origen_guides/pattern/j750.md.erb +10 -0
  20. data/templates/origen_guides/pattern/name.md.erb +511 -0
  21. data/templates/origen_guides/pattern/pins.md.erb +125 -0
  22. data/templates/origen_guides/pattern/registers.md.erb +300 -0
  23. data/templates/origen_guides/pattern/running.md.erb +105 -0
  24. data/templates/origen_guides/pattern/timing.md.erb +281 -0
  25. data/templates/origen_guides/pattern/ultraflex.md.erb +10 -0
  26. data/templates/origen_guides/pattern/v93k.md.erb +41 -0
  27. data/templates/origen_guides/program/code.md.erb +78 -0
  28. data/templates/origen_guides/program/custom.md.erb +5 -0
  29. data/templates/origen_guides/program/doc.md.erb +402 -0
  30. data/templates/origen_guides/program/flowapi.md.erb +249 -0
  31. data/templates/origen_guides/program/flows.md.erb +429 -0
  32. data/templates/origen_guides/program/generating.md.erb +97 -0
  33. data/templates/origen_guides/program/interface.md.erb +248 -0
  34. data/templates/origen_guides/program/introduction.md.erb +56 -0
  35. data/templates/origen_guides/program/j750.md.erb +514 -0
  36. data/templates/origen_guides/program/philosophy.md.erb +99 -0
  37. data/templates/origen_guides/program/resources.md.erb +141 -0
  38. data/templates/origen_guides/program/ultraflex.md.erb +5 -0
  39. data/templates/origen_guides/program/v93k.md.erb +456 -0
  40. data/templates/web/layouts/_guides.html.erb +10 -0
  41. data/templates/web/partials/_placeholder.md.erb +10 -0
  42. 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