Writing Custom Steps¶
Just like you may write custom flows, you may also write custom steps to run within those flows.
Again, please review OpenLane’s high-level architecture at this link. This defines many of the terms used and enumerates strictures mentioned in this document.
Generic Steps¶
Like flows, each Step subclass must:
Implement the
openlane.steps.Step.run()
method.This step is responsible for the core logic of the step, which is arbitrary.
This method must return two values:
A
ViewsUpdate
, a dictionary fromDesignFormat
objects to Paths for all views altered.A
MetricsUpdate
, a dictionary with valid JSON values.
Important
Do NOT call the run
method of any Step
from outside of Step
and its
subclasses- consider it a protected method. start
is class-independent and
does some incredibly important processing.
You should not be overriding start
either, which is marked final.
But also, each Step is required to:
Declare any required
openlane.state.State
inputs in theinputs
attribute.This will enforce checking the input states for these views.
Declare any potential state modifications in the
outputs
attribute.This list is checked for completeness and validity- i.e. the
Step
superclass WILL throw aStepException
if a Step modifies any State variable it does not declare.
Declare any used configuration variables in the
config_vars
attribute.
Important
Don’t forget the Step
strictures. Some of them are
programmatically enforced, but some are still not.
Writing Config Variables¶
Config variables are declared using the openlane.config.Variable
object.
There are some conventions to writing these variables.
Variable names are declared in
UPPER_SNAKE_CASE
, and must be valid identifiers in the Python programming language.Composite types should be declared using the
typing
module, i.e., for a list of strings, trytyping.List[str]
instead oflist[str]
or justlist
.list[str]
is incompatible with Python 3.8.list
does not give OpenLane adequate information to validate the child variables.
Variables that capture a physical quantity, such as time, distance or similar, must declare units using their
"units"
field.In case of micro-, the only SI prefix denoted with a non-Latin letter, use this exact Unicode codepoint:
µ
Variables may be declared as
pdk
, which determines the compatibility of a PDK with your step. If you use a PDK that does not declare one of your declared PDK variables, the configuration will not compile and the step will raise aopenlane.steps.StepException
.PDK variables should generally avoid having default values other than
None
. An exception is when a quantity may be defined by some PDKs, but needs a fallback value for others.
No complex defaults. Defaults must be scalar and quick to evaluate- if your default value depends on the default value of another variable, for example,
All filesystem paths must be declared as
openlane.common.Path
, objects which adds some very necessary validation and enables easier processing of the variables down the line.Avoid pointing to entire folders. If your step may require multiple files within a folder, try using the type
List[Path]
.
Implementing run
¶
The run header should look like this:
def run(self, state_in: State, *args, **kwargs):
The *args
and **kwargs
allow subclasses to pass arguments to subprocesses-
more on that later.
You can access configuration variables- which are validated by this point- using
self.config[KEY]
. If you need to save files, you can get the step directory
using self.step_dir
. For example:
design_name = self.config["DESIGN_NAME"]
output_path = os.path.join(self.step_dir, f"{design_name}.def")
Note
A step has access to:
Its declared
config_vars
Attempting to access any other variable is undefined behavior.
Warning
Ensure that, if your configuration variable is Optional, that you explicitly
check if the variable is not None
. If the variable is not Optional, validation
will handle this check for you.
Otherwise, you’re basically free to write any logic you desire, with one exception:
If you’re running a terminal subprocess you’d like to have OpenLane manage the logs for, please use
openlane.steps.Step.run_subprocess()
, passing *args and **kwargs. It will manage I/O for the process, and allow the creation of report files straight from the logs- more on that later.
In the end, add any views updated to the first dictionary in the returned tuple, and any metrics updated to the second dictionary in the returned tuple.
Creating Reports¶
You can create report files manually in Python, but if you’re running a subprocess,
you can also write %OL_CREATE_REPORT <name>.rpt
to stdout and everything until
%OL_END_REPORT
(or another %OL_CREATE_REPORT
) will be forwarded to a file called
<name>.rpt
in the step dir automatically.
Creating Metrics¶
Likewise, if you’re running a subprocess, you can have openlane.steps.Step.run_subprocess()
capture them for you automatically by using %OL_METRIC
. See the documentation
of openlane.steps.Step.run_subprocess()
for more info.
Note
Metrics generated using this method will not be automatically added to the
output state. The openlane.steps.Step.run()
method is expected to capture
the returned dictionary of any openlane.steps.Step.run_subprocess()
invocations and add any values to the returned MetricUpdate
dictionary as appropriate.
Tool-Specific Steps¶
The Step
object makes heavy use of object-oriented programming to encourage
as much code reuse as possible. To that extent, there exists some more specialized
Step
abstract base classes that deal with specific utilities:
openlane.steps.TclStep
¶
TclStep
implements a run
that works for most Tcl-based utilities.
This run calls a subprocess with the value of openlane.steps.TclStep.get_command()
,
and it emplaces all configuration variables as environment variables using this scheme:
List variables are joined with a space character.
Enumerations are replaced with the enumeration name.
Booleans are replaced with
"1"
if true or"0"
if false.Integers and Decimals are turned into Base-10 strings.
The state is also exposed to the TclStep as is:
Input files are pointed to in variables with the format
CURRENT_<view name>
.Output paths are pointed to in the variables with the format
SAVE_<view name>
.
If a TclStep-based step fails, a reproducible is created, which can be submitted to the respective repository of the tool.
Keep in mind that TclStep-based tools still have to define their config_vars
,
inputs
and outputs
.
Subclasses¶
TclStep
has various subclasses for a number of Tcl-based utilities:
These subclasses acts as an abstract base class for steps that use their
respective utility. They have one abstract method, get_script_path
.
Most steps subclassing them might not need to even override run
.
Additionally, they comes with a common set of config_vars
required by all invocations
of said tool; you can declare more for your step, however, as shown in this example.:
config_vars = OpenROADStep.config_vars + [
...
]
Be sure to read the subclasses’ run
docstrings as they may contain critical information.