Digital inverter with OpenLane

Stay organized with collections Save and categorize content based on your preferences.

Open In Colab

Run a simple digital inverter design thru the OpenLane GDS to RTL flow targeting the open source SKY130 PDK.

Install dependencies

import os
import pathlib
import sys

!curl -Ls https://micro.mamba.pm/api/micromamba/linux-64/latest | tar -xvj bin/micromamba
conda_prefix_path = pathlib.Path('conda-env')
site_package_path = conda_prefix_path / 'lib/python3.7/site-packages'
sys.path.append(str(site_package_path.resolve()))
CONDA_PREFIX = str(conda_prefix_path.resolve())
PATH = os.environ['PATH']
LD_LIBRARY_PATH = os.environ.get('LD_LIBRARY_PATH', '')
%env CONDA_PREFIX={CONDA_PREFIX}
%env PATH={CONDA_PREFIX}/bin:{PATH}
%env LD_LIBRARY_PATH={CONDA_PREFIX}/lib:{LD_LIBRARY_PATH}
!bin/micromamba create --yes --prefix $CONDA_PREFIX
!echo 'python ==3.7*' >> {CONDA_PREFIX}/conda-meta/pinned
!bin/micromamba install --yes --prefix $CONDA_PREFIX \
                        --channel litex-hub \
                        --channel main \
                        open_pdks.sky130a \
                        magic \
                        openroad \
                        netgen \
                        yosys 
!bin/micromamba install --yes --prefix $CONDA_PREFIX \
                        --channel conda-forge \
                        tcllib gdstk pyyaml click

Get OpenLane

git clone --depth=1 https://github.com/The-OpenROAD-Project/OpenLane

Write verilog

%%writefile inverter.v
module inverter(input wire in, output wire out);
    assign out = !in;
endmodule

Write configuration

%%writefile config.tcl
set ::env(DESIGN_NAME) inverter

set script_dir [file dirname [file normalize [info script]]]
set ::env(VERILOG_FILES) "$script_dir/inverter.v"

set ::env(CLOCK_TREE_SYNTH) 0
set ::env(CLOCK_PORT) ""

set ::env(PL_RANDOM_GLB_PLACEMENT) 1

set ::env(FP_SIZING) absolute
set ::env(DIE_AREA) "0 0 50 50"
set ::env(PL_TARGET_DENSITY) 0.80


set ::env(FP_PDN_HORIZONTAL_HALO) 6
set ::env(FP_PDN_VERTICAL_HALO) 6

set ::env(DIODE_INSERTION_STRATEGY) 3

# disable version checks because we use conda packaged versions
set ::env(TEST_MISMATCHES) none
# disable klayout because of https://github.com/hdl/conda-eda/issues/175
set ::env(RUN_KLAYOUT) 0
# disable CVC because of https://github.com/hdl/conda-eda/issues/174
set ::env(RUN_CVC) 0

Run OpenLane Flow

import os
import pathlib
OPENLANE_ROOT=str(pathlib.Path('OpenLane').resolve())
PATH=os.environ['PATH']
%env PDK_ROOT={CONDA_PREFIX}/share/pdk
%env TCLLIBPATH={CONDA_PREFIX}/lib/tcllib1.20
%env OPENLANE_ROOT={OPENLANE_ROOT}
%env PATH={PATH}:{OPENLANE_ROOT}:{OPENLANE_ROOT}/scripts
%env OPENLANE_LOCAL_INSTALL=1
!flow.tcl -design .
env: PDK_ROOT=/content/conda-env/share/pdk
env: TCLLIBPATH=/content/conda-env/lib/tcllib1.20
env: OPENLANE_ROOT=/content/OpenLane
env: PATH=/content/conda-env/bin:/opt/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/tools/node/bin:/tools/google-cloud-sdk/bin:/content/OpenLane:/content/OpenLane/scripts
env: OPENLANE_LOCAL_INSTALL=1
OpenLane ad24025768f6e43058646dad0528af04cabf2aec
All rights reserved. (c) 2020-2022 Efabless Corporation and contributors.
Available under the Apache License, version 2.0. See the LICENSE file for more details.

[INFO]: Using design configuration at /content/config.tcl
[INFO]: Sourcing Configurations from /content/config.tcl
[INFO]: PDKs root directory: /content/conda-env/share/pdk
[INFO]: PDK: sky130A
[INFO]: Setting PDKPATH to /content/conda-env/share/pdk/sky130A
[INFO]: Standard Cell Library: sky130_fd_sc_hd
[INFO]: Optimization Standard Cell Library is set to: sky130_fd_sc_hd
[INFO]: Sourcing Configurations from /content/config.tcl
[INFO]: Current run directory is /content/runs/RUN_2022.06.10_07.51.15
[INFO]: Preparing LEF files for the nom corner...
[INFO]: Preparing LEF files for the min corner...
[INFO]: Preparing LEF files for the max corner...
[STEP 1]
[INFO]: Running Synthesis...
[STEP 2]
[INFO]: Running Single-Corner Static Timing Analysis...
[STEP 3]
[INFO]: Running Initial Floorplanning...
[WARNING]: Current core area is too small for a power grid. The power grid will be minimized.
[INFO]: Extracting core dimensions...
[INFO]: Set CORE_WIDTH to 38.64, CORE_HEIGHT to 27.2.
[STEP 4]
[INFO]: Running IO Placement...
[STEP 5]
[INFO]: Running Tap/Decap Insertion...
[INFO]: Power planning with power {VPWR} and ground {VGND}...
[STEP 6]
[INFO]: Generating PDN...
[STEP 7]
[INFO]: Performing Random Global Placement...
[STEP 8]
[INFO]: Running Placement Resizer Design Optimizations...
[STEP 9]
[INFO]: Writing Verilog...
[STEP 10]
[INFO]: Running Detailed Placement...
[STEP 11]
[INFO]: Running Placement Resizer Timing Optimizations...
[STEP 12]
[INFO]: Writing Verilog...
[INFO]: Routing...
[STEP 13]
[INFO]: Running Global Routing Resizer Timing Optimizations...
[STEP 14]
[INFO]: Writing Verilog...
[STEP 15]
[INFO]: Running Detailed Placement...
[STEP 16]
[INFO]: Running Global Routing...
[INFO]: Starting FastRoute Antenna Repair Iterations...
[STEP 17]
[INFO]: Running Fill Insertion...
[STEP 18]
[INFO]: Writing Verilog...
[STEP 19]
[INFO]: Running Detailed Routing...
[INFO]: No DRC violations after detailed routing.
[STEP 20]
[INFO]: Writing Verilog...
[INFO]: Running parasitics-based static timing analysis...
[STEP 21]
[INFO]: Running SPEF Extraction at the min process corner...
[STEP 22]
[INFO]: Running Multi-Corner Static Timing Analysis at the min process corner...
[STEP 23]
[INFO]: Running SPEF Extraction at the max process corner...
[STEP 24]
[INFO]: Running Multi-Corner Static Timing Analysis at the max process corner...
[STEP 25]
[INFO]: Running SPEF Extraction at the nom process corner...
[STEP 26]
[INFO]: Running Single-Corner Static Timing Analysis at the nom process corner...
[STEP 27]
[INFO]: Running Multi-Corner Static Timing Analysis at the nom process corner...
[STEP 28]
[INFO]: Running Magic to generate various views...
[INFO]: Streaming out GDS-II with Magic...
[INFO]: Generating MAGLEF views...
[STEP 29]
[INFO]: Running XOR on the layouts using Klayout...
[WARNING]: /content/runs/RUN_2022.06.10_07.51.15/results/signoff/inverter.klayout.gds wasn't found. Skipping GDS XOR.
[STEP 30]
[INFO]: Running Magic Spice Export from LEF...
[STEP 31]
[INFO]: Writing Powered Verilog...
[STEP 32]
[INFO]: Writing Verilog...
[STEP 33]
[INFO]: Running LEF LVS...
[STEP 34]
[INFO]: Running Magic DRC...
[INFO]: Converting Magic DRC Violations to Magic Readable Format...
[INFO]: Converting Magic DRC Violations to Klayout XML Database...
[INFO]: No DRC violations after GDS streaming out.
[INFO]: Running Antenna Checks...
[STEP 35]
[INFO]: Running OpenROAD Antenna Rule Checker...
[INFO]: Skipping CVC...
[INFO]: Saving final set of views in '/content/runs/RUN_2022.06.10_07.51.15/results/final'...
[INFO]: Saving runtime environment...
[INFO]: Generating final set of reports...
[INFO]: Created manufacturability report at 'runs/RUN_2022.06.10_07.51.15/reports/manufacturability.rpt'.
[INFO]: Created metrics report at 'runs/RUN_2022.06.10_07.51.15/reports/metrics.csv'.
[INFO]: There are no max slew violations in the design at the typical corner.
[INFO]: There are no hold violations in the design at the typical corner.
[INFO]: There are no setup violations in the design at the typical corner.
[SUCCESS]: Flow complete.
[INFO]: Note that the following warnings have been generated:
[WARNING]: Current core area is too small for a power grid. The power grid will be minimized.
[WARNING]: /content/runs/RUN_2022.06.10_07.51.15/results/signoff/inverter.klayout.gds wasn't found. Skipping GDS XOR.

Display layout

import pathlib
import gdstk
import IPython.display

gdss = sorted(pathlib.Path('runs').glob('*/results/final/gds/*.gds'))
library = gdstk.read_gds(gdss[-1])
top_cells = library.top_level()
top_cells[0].write_svg('inverter.svg')
IPython.display.SVG('inverter.svg')

svg

Dump flow report

import pandas as pd
import pathlib

pd.options.display.max_rows = None
final_summary_reports = sorted(pathlib.Path('runs').glob('*/reports/metrics.csv'))
df = pd.read_csv(final_summary_reports[-1])
df.transpose()