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 fromDesignFormatobjects 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.Stateinputs in theinputsattribute.This will enforce checking the input states for these views.
Declare any potential state modifications in the
outputsattribute.This list is checked for completeness and validity- i.e. the
Stepsuperclass WILL throw aStepExceptionif a Step modifies any State variable it does not declare.
Declare any used configuration variables in the
config_varsattribute.
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
typingmodule, i.e., for a list of strings, trytyping.List[str]instead oflist[str]or justlist.list[str]is incompatible with Python 3.8.listdoes 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.