Getting Started with Origen
Creating New Files
This guide describes how to add new files to an application and how to leverage the tools and conventions that Origen provides to help with this.
Like all programming languages, Ruby requires that a source file is either executed directly or else loaded in some way in order for the language runtime to be aware of it.
Source files, such as test patterns, test program flow files and templates, can simply be added to the
app/templates directories respectively.
Whenever you invoke Origen to generate or compile, you will naturally provide a named
reference to the file in the command arguments and Origen will know in which directory to look based
on the command being run.
However, things have the potential to be more tricky when dealing with more abstract file references, for example when referencing a class or other object name that is not directly associated with an Origen command. For these cases, Origen provides an auto-loading system which means that as long as you follow a few simple conventions about what directories to use and how to name your objects and files, then Origen will automatically find and load them as required.
Note that using the auto-loading system is actually the preferred approach because it means that your application files will be lazily loaded - meaning that files will only be loaded just-in-time and on an as-needed basis. This helps to keep application boot times fast by not requiring the world at startup when in fact the target operation may only require a small subset of an application’s overall functionality.
The easiest way to align to the required naming convention is to use the
origen new command to generate your
new files rather than adding them manually…
Code generation refers to executing an Origen command to create new application files automatically. These files will come with all of the necessary internal structure already in place (the so-called boilerplate) and if any modifications have to be made to existing files in order to integrate the new file, then these modifications will be applied automatically too.
All code generators are accessible via the
origen new command, to see the available generators run:
origen new -h
To get more information about what each generator does, add the specific generator name, for example to find
out what the
block generator does, run:
origen new block -h
Your application’s revision control system should be used for that. i.e. If you are worried about the consequences of running a generator, make sure that you have everything checked in before running it, then you can simply checkout your application again to remove the effects of running the generator.
One of the first things you will want to do after creating a new application, is to create a new top-level DUT object to work with.
This can done very easily by running the following command (replacing
my_dut_name with your choice of name,
ensuring to follow the convention of keeping it lower-cased and underscored):
origen new dut my_dut_name
If you look inside the target file, you will see something like this:
There are a few points worth noting here:
- The name of the new dut class begins with
MyApp::which means that it exists within your application’s unique namespace. It is important that all of the Ruby classes and modules defined by your application do this so that naming collisions are avoided with any plugins that you may use. Using the code generators will ensure that this is always done.
- There is a second level to the name,
::DUT::. Experience has shown that it is common within applications to want to add functionality to all DUTs, even if they are otherwise unrelated. So the new DUT generator enforces that all DUTs in an application are all children of a master DUT block. This is an example of a generator enforcing good application architecture patterns, another reason to use the generators!
- Finally, the DUT’s name,
::MyDUTNameis the camel-cased version of the original name that you supplied. This is following standard Ruby conventions that class names are always camel-cased. Note that the name contains
Dutbecause this is a common acronym that Origen is aware of.
If your application deals with multiple DUTs that can be logically grouped into collections/families then you can add such identifiers when generating DUTs. For example, say some of your DUTs belonged to a network controller product family, you could add a new DUT to this family by running:
origen new dut network_controllers/my_dut_name
This time the target will look like this:
Meaning that the DUT is a descendent of
NetworkControllers which is itself a descendent of
The files generated within
app/blocks by this command will set all of this up for you, providing you with a logical
place to add features to all DUTs, all network controllers, or to an individual DUT only.
Once you have a DUT, you may then want to start adding sub-blocks to it. For example, if you wanted to start creating tests for a flash module, then you should create a dedicated block for it rather than adding everything into the top-level block.
Do this by running the following command:
origen new block flash/my_flash_name
This will create a complete set of block files for this IP and it will ask you which of your current
DUTs you want to instantiate it in. You can also choose to not instantiate it at this time, in that
case you will be able to manually instantiate it later within the given DUT’s
Note that when running this command, we had to supply the TYPE of the block (in this example
flash) as well as
its name (
The presence of the TYPE argument is mandatory and it exists for two reasons:
- Origen is assuming that as your application matures you will need variations of this IP block, for example a
1MB flash IP and a 2.5MB variant. Similar to having the master
DUTblock, this is setting you off down a scalable architecture path by creating a master block for each IP type. In this example, the master block from which all derivatives of this type will inherit will be called
MyApp::Flashand the specific derivative that we just created will be called
- The TYPE is also used as the name given to the instance of the block that is instantiated within the
DUTs that you selected when running the command (if you chose no DUTs then it will be up to you what you call
the instance when you do it manually).
Continuing with this flash example, this means that you can make derivative-agnostic references to
dut.flashin your pattern and test program source files and they will be compatible with whatever flash derivative is instantiated by the current target.
Otherwise, the created block files are very much like a DUT block. A DUT is a special block which cannot be instantiated as a sub-block of other blocks, but these regular blocks can be instantiated within DUTs or even within other blocks.
Sometimes, you may want to create blocks to represent/handle sub-components of an IP. It will often be the case that such blocks are:
- Tightly coupled to the parent IP, where the concept of them being instantiated within some other block does not make sense
- Simple in nature; there will be no need for derivative blocks to be created/managed in the future
If both of these are true, then an embedded (sub-) block is a good choice rather than a regular block, though if you are in any doubt, a regular block can always be used safely.
The advantage of using an embedded sub-block is that it keeps your
app/blocks directory clean, meaning that
it only contains primary blocks which would typically represent the main IPs within a SoC, rather than being
cluttered with lots of secondary/trivial blocks.
The restrictions of creating an embedded sub-block are that they can’t define pins, parameters, or timesets, and they don’t support derivative children.
Otherwise, they are a normal block with a model, controller, registers and attributes, and they can even have their own embedded child blocks.
Here is an example of a command to create an embedded sub-block, supplying the path to the directory of the parent block and then the name of the embedded sub-block to create:
origen new block app/blocks/parent my_sub_block_name
sub_blocks.rb files in the
app/blocks contain an example of the command to run to add
an embedded sub-block to the given block.
origen new module my_module and
origen new class my_class can be used to create plain
Ruby classes and modules in the
These should be used to build abstract logic and helpers that your application requires.
All class/modules created by these code generator commands will be named correctly for auto-loading and will be properly wrapped in the application’s namespace.
origen new module -h and
origen new class -h for more details.
It is expected that the available code generators will grow over time as the community add them and as new best practices and conventions about how to structure Origen applications emerges.
origen new -h for the latest list of code generators that are available within your application.
As your experience with Origen grows, you may find that you start to bypass the
origen new command and
begin to create new files directly.
In that case, it is worthwhile understanding how Origen’s auto-loading system works and exactly what the
naming convention is.
Within an Origen application, files residing in either
app/lib will be auto-loaded.
app/blocks directory is a special case which uses a custom directory
app/lib follows a very typical structure that you will see in many Ruby projects.
All Ruby class or module names used within your application should be camel-cased to enable the auto-loader to resolve them to a file that defines them. This naming convention is widely within the Ruby language and almost all non-Origen projects will also follow the same convention.
Examples of valid names are:
Note that in all cases the top-level name must be your application’s unique namespace - this tells Origen which application or plugin owns a given object and therefore in which app’s directories to look for a definition of it.
The remainder of the name is then broken down into the equivalent lower-cased and underscored versions of the name, like this:
['my_app', 'my_family', 'my_device'] ['my_app', 'helpers']
These transformed names are what the files and directories should be called and this is another widely used convention within the Ruby language/community - i.e. that files (and directories) are named after the lower-cased and underscored version of the class/module names that they define, and therefore that you have a dedicated file for each class/module.
When your application references something like
MyApp::MyFamily::MyDevice for the first time, it will trigger
Ruby’s constant missing procedure and this provides a hook (
const_missing) to allow applications like Origen
to handle the missing definition before an error is raised.
When this hook is triggered, Origen will first identify what app/plugin to look in from the first part of the name, if no matching app/plugin is found then the lookup will go no further and most likely the user will receive an uninitialized constant error.
If an app/plugin is found, it will first see if it has an
app/blocks directory and if so this will be
searched for a match.
MyApp::MyFamily::MyDevice example will be searched for within
app/blocks in this order:
# A reference to a model, note that `MyApp` is discarded and that `derivatives` directories are injected app/blocks/my_family/derivatives/my_device/model.rb # A reference to a sub-block model (all `derivatives` dirs in the path are systematically changed to `sub_blocks`) app/blocks/my_family/sub_blocks/my_device/model.rb # A reference to a module which has been added to a model app/blocks/my_family/model/my_device.rb
If the name is resolved to a block model, then Origen will load the complete block at this time - i.e. the model and all of its pins, registers, sub_blocks, etc.
If no match is found within
app/blocks it will then try
app/lib. In that case the lookup is a very simple
concatenation of the names and in these examples it will look for:
If a matching file is found, it will be loaded and if it defines the missing constant then the application execution will proceed as normal. If a matching file is found but it does not actually define the missing class/module name then an error will be raised to that effect.