(c) 2026 Simon Dorrer and Harald Pretl
Institute for Integrated Circuits and Quantum Computing, Johannes Kepler University (JKU), Linz, Austria
Warning
make add-logo-fill currently fails in the IIC-OSIC-TOOLS 2026.07 release. A PDK issue corrupts the
seal ring, which makes the KLayout filler abort with an internal error in Region::holes. The target is
therefore commented out in Makefile :: build-top. This will be fixed with the 2026.08 release of
IIC-OSIC-TOOLS.
Important
This repository requires the IIC-OSIC-TOOLS container with tag 2026.07 or later.
Chip render of the ihp-sg13g2 analog-mixed signal template chip (1.6 mm x 1.6 mm).
Render of the TopMetal2 AMS Chip logo, generated with the tool ArtistIC.
Developing high-performance open-source silicon requires both the availability of tapeout-ready open-PDKs and robust, user-friendly EDA flows. While digital RTL-to-GDS flows offer an easy entry with documentation and examples, analog mixed-signal (AMS) design still suffers from a steep learning curve and the lack of examples and instructions. This repository provides a comprehensive template and tutorial for AMS chip design using the ihp-sg13g2 Open-PDK, guiding the designer from initial system-level specifications to the tapeout-ready chip.
This Makefile-driven repository simulates, builds, and fully verifies (DRC, LVS, PEX) a complete analog mixed-signal chip for the ihp-sg13g2 Open-PDK, including padframe generation, top-level assembly and bondplan generation. The flow uses:
- LibreLane for digital macro hardening, padframe generation, top-level assembly, filler and logo insertion
- Xschem for schematic entry
- Ngspice, VACASK and CACE for analog simulation
- KLayout for viewing and routing of the layout
- Magic + Netgen and KLayout for DRC, LVS and PEX verification
- SystemVerilog, Verilator, iverilog, cocotb, GTKWave and Surfer for linting and simulation of digital macros
The repository is the starting point for your own custom silicon and provides a universal design flow solution: Just clone the repo, enter the IIC-OSIC-TOOLS container, and run make all to get a tapeout-ready analog-mixed signal chip. Focus on your design and do not care about the tools and the design flow!
Furthermore, it serves as a regression test for the above-mentioned open-source tools and their dependencies using the ihp-sg13g2 Open-PDK.
A step-by-step tutorial, including additional exercises, can be found here.
An overview of the open source IC design landscape is presented here.
Are you interested in an open-source RFIC flow? Check it out here.
Examples based on this template are:
- TinyWhisper: An Open-Source Fully-Integrated Multi-Mode Short-Wave Transmitter for Amateur Radio Applications in 130-nm CMOS
- SPARX: An Open-Source, Automated, Programmatically Generated, Frequency-Scalable Six-Port Receiver in 130-nm CMOS
- wafer.space gf180mcuD MPW Multi-Project Chip
A designer-oriented description of this chip can be found in doc/:
- doc/specifications.md: top-level specifications (technology, supplies, clock, macro inventory, functional behaviour).
- doc/pinout.md: full 32-pad bondpad table per side, with the
chip_topport and the role each pad carries insidechip_core. - doc/floorplan.md: die / core geometry, hard-macro placement coordinates, PDN strategy and the floorplan diagram.
Show Directory Structure
📁 ihp-sg13g2-ams-chip-template/
├─ 📁 .github/
│ └─ 📁 workflows/
│ ├─ license-check.yml
│ ├─ quarto-publish.yml
│ └─ regression.yml
├─ 📁 doc/
│ ├─ 📁 ihp-sg13g2-Open-PDK/
│ ├─ 📁 ihp-structure-proposals/
│ ├─ 📁 klayout/
│ ├─ 📁 librelane/
│ ├─ 📁 sizing/
│ ├─ floorplan.md
│ ├─ pinout.md
│ └─ specifications.md
├─ 📁 flow/
│ ├─ 📁 artistic/
│ ├─ 📁 librelane/
│ │ ├─ chip_top.sdc
│ │ ├─ config.yaml
│ │ └─ pdn_cfg.tcl
│ └─ 📁 logo/
│ └─ chip_logo_mono.png
├─ 📁 ip/
│ ├─ 📁 sg13g2_io_custom/
│ ├─ 📁 sg13g2_ip__bondpad_70x70/
│ │ ├─ 📁 final/
│ │ ├─ 📁 script/
│ │ ├─ 📁 verification/
│ │ ├─ Makefile
│ │ └─ README.md
│ ├─ 📁 sg13g2_ip__jku/
│ │ ├─ 📁 final/
│ │ ├─ 📁 logo/
│ │ ├─ 📁 script/
│ │ ├─ 📁 verification/
│ │ ├─ Makefile
│ │ └─ README.md
│ └─ 📁 sg13g2_ip__jku_names/
│ ├─ 📁 final/
│ ├─ 📁 logo/
│ ├─ 📁 script/
│ ├─ 📁 verification/
│ ├─ Makefile
│ └─ README.md
├─ 📁 layout/
│ ├─ chip_top.gds.gz
│ └─ chip_top_logo_fill.gds.gz
├─ 📁 LICENSES/
│ ├─ Apache-2.0.txt
│ ├─ LicenseRef-EUROPRACTICE.txt
│ └─ SHL-2.1.txt
├─ 📁 macros/
│ ├─ 📁 counter/
│ │ ├─ 📁 final/
│ │ ├─ 📁 flow/
│ │ ├─ 📁 fpga/
│ │ ├─ 📁 netlist/
│ │ ├─ 📁 render/
│ │ ├─ 📁 rtl/
│ │ ├─ 📁 schematic/
│ │ ├─ 📁 scripts/
│ │ ├─ 📁 testbenches/
│ │ ├─ 📁 verification/
│ │ ├─ Makefile
│ │ └─ README.md
│ └─ 📁 inverter/
│ ├─ 📁 final/
│ ├─ 📁 layout/
│ ├─ 📁 netlist/
│ ├─ 📁 render/
│ ├─ 📁 schematic/
│ ├─ 📁 scripts/
│ ├─ 📁 testbenches/
│ ├─ 📁 verification/
│ ├─ Makefile
│ └─ README.md
├─ 📁 netlist/
│ ├─ 📁 layout/
│ ├─ 📁 nl/
│ ├─ 📁 pex/
│ ├─ 📁 pnl/
│ ├─ 📁 schematic/
│ └─ 📁 spice/
├─ 📁 packaging/
│ ├─ 📁 layout/
│ │ ├─ chip_top_bondplan.gds
│ │ ├─ chip_top_logo_TM2.gds.gz
│ │ ├─ EP_PACKAGES_08022018.gds
│ │ └─ OP_QFN32_A4_FIT.gds
│ ├─ 📁 render/
│ │ └─ chip_top_bondplan_{white,black}.{png,svg}
│ ├─ 📁 scripts/
│ │ └─ run_bondplan.py
│ ├─ config.yaml
│ ├─ README.md
│ └─ result.md
├─ 📁 release/
│ └─ 📁 v.1.0.0/
│ ├─ 📁 gds/
│ ├─ 📁 img/
│ └─ 📁 netlist/
├─ 📁 render/
│ ├─ 📁 blender/
│ └─ 📁 img/
├─ 📁 rtl/
│ ├─ chip_core.sv
│ └─ chip_top.sv
├─ 📁 schematic/
│ └─ 📁 xschem/
│ ├─ chip_top.sch
│ ├─ chip_top.sym
│ ├─ chip_top_pex.sym
│ └─ xschemrc
├─ 📁 scripts/
│ ├─ add_logo_fill.sh
│ ├─ add_rectangle.py
│ ├─ check_pex_ports.py
│ └─ lay2img.py
├─ 📁 testbenches/
│ ├─ 📁 cocotb/
│ │ ├─ chip_top_tb.gtkw
│ │ ├─ chip_top_tb.py
│ │ └─ chip_top_tb.surf.ron
│ └─ 📁 xschem/
│ ├─ 📁 plot_simulations/
│ │ ├─ 📁 data/
│ │ ├─ 📁 figures/
│ │ ├─ ngspice2python.py
│ │ └─ plot_chip_top.py
│ ├─ chip_top_tb_tran.sch
│ └─ xschemrc
├─ 📁 tutorial/
│ ├─ 📁 fig/
│ ├─ _quarto.yml
│ ├─ index.qmd
│ ├─ Makefile
│ └─ requirements.txt
├─ 📁 verification/
│ ├─ 📁 drc/
│ ├─ 📁 lvs/
│ └─ 📁 reports/
│ ├─ antenna_summary.rpt
│ ├─ antenna_violations.rpt
│ ├─ irdrop.rpt
│ ├─ lvs.netgen.rpt
│ ├─ manufacturability.rpt
│ ├─ stapostpnr_*.rpt
│ ├─ stat.rpt
│ ├─ yosys_post_dff.rpt
│ ├─ yosys_pre_techmap.rpt
│ └─ yosys_synth_check.rpt
├─ CITATION.cff
├─ LICENSE
├─ Makefile
├─ README.md
├─ REUSE.toml
└─ ToDo.md
The whole flow is driven by Makefiles. The top-level Makefile builds the chip, and every component under macros/ and ip/ has its own Makefile and README.md following the same conventions (make help, make all, and so on). You can run each component from the top level or directly from inside its own folder. The figure below shows how the targets are connected when you run make all at the top level.
Overview of the Makefile targets.
Every coloured branch corresponds to one deliverable (top chip, bondpad, logos, digital macro, analog macro, packaging). The grey targets connect make all to those branches.
Solid arrows are direct $(MAKE) <target> calls within a single Makefile. Dashed arrows descend into a subdirectory, either as a recursive $(MAKE) -C <dir> all call into a sub-Makefile or as the Python bondplan flow in packaging/. The numbers on the second level give the execution order of make all, and the vertical order inside the coloured boxes gives the execution order of each sub-Makefile.
At the top level, make all runs four steps in this order:
build-allinitializes the submodules and builds every component by calling its ownalltarget: bondpad, logos, digital macro, analog macro, and finally the chip assembly withbuild-top(LibreLane, copy-back of all artifacts, logo and fill insertion, final GDS render).magic-drcandklayout-drcrun the DRC of the finalchip_topandchip_top_logo_fillGDS.sim-allruns the chip-level RTL and gate-level simulations on the netlists produced by this build.bondplangenerates the bonding diagram, the bondwires, and the pin table.
Every component follows the same principle. The simulations always run last, so they use the artifacts that the same invocation has just produced.
| Makefile | all flow |
|---|---|
macros/counter/ (digital) |
lint -> build (FPGA and LibreLane, including the XSPICE model) -> simulate. DRC and LVS run inside the LibreLane flow. |
macros/inverter/ (analog) |
verify (DRC, LVS, PEX) -> build (LEF, LIB, Verilog stub, GDS, render) -> simulate |
ip/* (bondpad, logos) |
build -> verify (DRC) |
| top level | build -> verify (DRC) -> simulate -> package |
The following sections describe the top-level targets in detail. The macro and IP targets are documented in the README.md of the respective subfolder.
The default Make target is help, so running make prints usage and all available targets with short descriptions.
make
make helpInitializes and updates the repository submodules (for example ArtistIC):
make init-submodulesRun this after cloning the repository, or whenever submodule pointers are updated.
We use cocotb, a Python-based testbench environment, for the verification of the chip. The underlying simulator is Icarus Verilog.
The simulation targets accept an optional CELL variable (default: chip_top).
The testbench is located in testbenches/cocotb/chip_top_tb.py. To run the RTL simulation, use:
make sim-rtl-cocotbTo run the gate-level (GL) simulation with cocotb, use:
make sim-gl-cocotbTo run the gate-level simulation with Xschem, use:
make sim-gl-xschem
make sim-gl-xschem TB=<testbenchname>The testbench is selected with the TB variable, given without the .sch extension (default: <CELL>_tb_tran). All testbench schematics are located in testbenches/xschem/, and the generated netlists are written to testbenches/xschem/simulations/.
The simulation runs in batch mode: the target netlists the testbench with xschem netlist and then invokes ngspice -b directly instead of using xschem simulate. xschem simulate would spawn an interactive ngspice in a terminal detached from make: the target would return immediately, the result would never be checked, and the process (with its X server) would leak. Running the simulator directly makes make block until the run finishes and see its exit status.
Because the run is headless, the plot commands in a testbench's .control block are a no-op and no plot windows appear. Every testbench instead exports its results with wrdata to testbenches/xschem/plot_simulations/data/, from where they are plotted with sim-view-xschem.
Note
sim-gl-xschem is part of sim-all, but it may take a long time depending on the hardware used.
To plot the Xschem simulation results, use sim-view-xschem. It runs a plotting script from testbenches/xschem/plot_simulations/ (SIM_PLOT_DIR), selected with the SCRIPT variable (given without the .py extension), and reproduces the plots of the testbench's .control block with matplotlib from the exported data in plot_simulations/data/:
make sim-view-xschem SCRIPT=plot_chip_topThe target runs SHOW_PLOTS=1 python3 testbenches/xschem/plot_simulations/$(SCRIPT).py. Every script writes its figures to testbenches/xschem/plot_simulations/figures/. Run through sim-view-xschem, the plot windows additionally open when a display is available (i.e. the container's X/VNC session). Headless, only the figures are written.
Note
sim-view-xschem is intentionally not called by sim-all.
It opens the generated Python figures, which blocks the shell until the window is closed.
It is designed for interactive use and must be called manually after the simulation has completed.
The cocotb simulations generate a waveform file under testbenches/cocotb/sim_build/chip_top.fst.
You can view it with a waveform viewer such as GTKWave or Surfer.
The waveform viewer can be changed with WAVEFORM_VIEWER=<gtkwave|surfer> (default: gtkwave).
make sim-view-cocotb # view chip_top waveform with GTKWave (default)
make sim-view-cocotb WAVEFORM_VIEWER=surfer # use Surfer insteadEach cocotb simulation folder contains a pre-configured waveform layout file (<CELL>_tb.gtkw for GTKWave, <CELL>_tb.surf.ron for Surfer).
The view target loads it automatically together with the current .fst, so signal formatting is preserved across runs.
To run all non-interactive simulation targets in sequence (RTL cocotb, GL cocotb and GL Xschem), use:
make sim-allNote
sim-view-cocotb is intentionally not called by sim-all.
It opens a waveform viewer GUI (GTKWave or Surfer), which blocks the shell until the window is closed.
It is designed for interactive use and must be called manually after the simulation has completed.
Note
sim-view-xschem is intentionally not called by sim-all either. Run it manually with
make sim-view-xschem SCRIPT=plot_chip_top after the simulation has completed.
Run the LibreLane flow with:
make librelaneAdditional targets are available for different DRC configurations:
make librelane-nodrc– run LibreLane without DRC checksmake librelane-magicdrc– run LibreLane with only Magic DRC checksmake librelane-klayoutdrc– run LibreLane with only KLayout DRC checks
These targets are also available for the digital macros. After the LibreLane flow completes successfully, the generated views are saved under flow/final/.
After completion, you can view the design using the OpenROAD GUI:
make librelane-openroadOr using KLayout:
make librelane-klayoutThese commands are also available for the digital macros.
To copy the Yosys synthesis checks, antenna reports, post-PnR timing summary, per-corner power reports, IR-drop report, LVS report, and manufacturability report from the latest LibreLane run into verification/reports/, run:
make copy-reportsThis only works if the latest run completed without errors. This command is also available for the digital macros.
Note
The Magic and KLayout DRC reports are temporarily not copied because IHP's
metal1_pin_offgrid rule trips on the pad ring (see IHP-Open-PDK#683).
Once it is fixed upstream, the corresponding cp lines in Makefile :: copy-reports will be re-enabled.
To copy and compress the latest GDS from flow/final/gds/ into layout/, run:
make copy-gdsTo copy the latest SPICE, PnL, and NL netlists from flow/final/spice/ into netlist/spice/, from flow/final/pnl/ into netlist/pnl/, and from flow/final/nl/ into netlist/nl/, run:
make copy-netlistThis only works if the latest run completed without errors.
To copy the latest LibreLane chip render from flow/final/render/ into render/img/, run:
make copy-renderThis creates render/img/chip_top_librelane.png. This only works if the latest run completed without errors.
Renders the top-level GDS from layout/ with scripts/lay2img.py and saves the two images chip_top_black.png and chip_top_white.png in the render/img/ folder:
make render-gdsThis only works if the latest run completed without errors. This command is also available for the digital macros.
To build the bondpad in the ip folder, run the following command:
make build-bondpadTo build the logos in the ip folder, run the following command:
make build-logosTo build a specific macro, run the corresponding target from the Makefile. To build all currently enabled macros, run:
make build-macrosThe following command builds the counter digital macro:
make build-counterFor each digital macro this dispatches to its in-tree make all, which runs the macro's full flow: lint, build (FPGA and LibreLane, including netlists and the XSPICE model), verify (DRC and LVS within the LibreLane flow) and simulate. The simulations run after the build, so the gate-level simulations run on the netlists produced by this build.
Tip
Each macro has its own Makefile and README.md with additional targets, such as linting, simulation, and verification.
For example, to lint the counter or run its simulation, refer to macros/counter/README.md.
Each analog macro has its own klayout-verify and magic-verify targets that run DRC, LVS, and PEX for the top-level cell.
To build the inverter macro:
make build-inverterFor each analog macro this dispatches to its in-tree make all, which runs the macro's full flow: verify (DRC, LVS, PEX), build, and simulate. The simulations run after the verification, so the top-level testbench includes the PEX netlist produced by this run.
All analog macros are included in build-macros alongside the digital macros.
To run LibreLane for the top-level chip and copy the resulting reports, GDS, netlist, and chip render back into the source tree, then add the logo + fill structures and render the final GDS, run:
make build-topInternally this executes (in order): librelane-nodrc → copy-reports → copy-gds → copy-netlist → copy-render → add-logo-fill → render-gds.
Note
build-top runs librelane-nodrc instead of librelane for the same reason the DRC reports are not copied: IHP's metal1_pin_offgrid rule trips on the pad ring (see IHP-Open-PDK#683).
Once it is fixed upstream, Makefile :: build-top switches back to librelane.
To initialise submodules, build the bondpad, build the logos, build the macros, and run the full build-top flow, run:
make build-allThis is useful if you want to rebuild the chip from scratch. Clone the repository, enter the IIC-OSIC-TOOLS environment, and run make build-all.
To add the chip logo (PNG → GDS) and the fill structures on top of the LibreLane output (so the final GDS in layout/ includes the artwork), run:
make add-logo-fillThis calls scripts/add_logo_fill.sh and writes layout/chip_top_logo_fill.gds.gz. The step is also called from make build-top.
Note
In the future, it is planned to replace this script and Makefile target with a custom librelane step.
Runs DRC on the GDS layout in layout/. Both flows use sak-drc.sh and write their reports into per-cell run folders: verification/drc/<CELL>.magic.drc/ (Magic) and verification/drc/<CELL>.klayout.drc/ (KLayout, .lyrdb). The run folders are wiped at the start of each run, so they always reflect the latest run only.
The DRC_LEVEL parameter selects the KLayout DRC level (sak-drc.sh -l). It is ignored by magic-drc, since Magic has no selectable rule decks and always runs the full rule set compiled into the PDK's Magic tech file:
precheck= core FEOL + BEOL manufacturing rules only (fast iteration)macro= block-in-isolation sign-off:precheckplus off-grid, zero-area, and pin/label checks (default)regular= full-chip sign-off: all checks, including density and antenna
| Check | precheck |
macro (default) |
regular |
|---|---|---|---|
| FEOL + BEOL core rules | ✓ | ✓ | ✓ |
| Off-grid / angle | – | ✓ | ✓ |
| Zero-area / geometry | – | ✓ | ✓ |
| Pin / label | – | ✓ | ✓ |
| Recommended / extra rules | – | – | ✓ |
| Density (chip-level fill) | – | – | ✓ |
| Antenna | – | – | ✓ |
KLayout DRC (minimum) runs a pre-check (precheck) KLayout DRC on the final top-level layout with logo and fill structures:
make klayout-drc-minimumKLayout DRC (regular) runs a full (regular) KLayout DRC on the final top-level layout with logo and fill structures:
make klayout-drc-regularKLayout DRC runs a KLayout DRC at the selected DRC_LEVEL:
make klayout-drc
make klayout-drc CELL=chip_top
make klayout-drc CELL=chip_top DRC_LEVEL=regularMagic DRC runs a Magic DRC with all subcells flattened (sak-drc.sh -f "*"):
make magic-drc
make magic-drc CELL=chip_topExports the schematic netlist for LVS from Xschem and places it in netlist/schematic/.
The EV_PRECISION parameter sets the number of significant digits used by Xschem's ev function when calculating device properties (default: 5). Increase this to avoid LVS mismatches caused by floating-point rounding differences between Xschem and KLayout (see xschem#465).
The ntap and ptap substrate contacts are ignored during LVS in both flows. sak-lvs.sh runs KLayout LVS with the --disable_tap_extraction option so it does not extract ntap and ptap devices from the layout (matching Magic + Netgen LVS).
KLayout uses CDL netlists, while Magic uses SPICE netlists. Accordingly, klayout-lvs-netlist uses the Xschem commands set spiceprefix 1, set lvs_netlist 1, set top_is_subckt 1, and set lvs_ignore 1, while magic-lvs-netlist uses set spiceprefix 1, set lvs_netlist 0, set top_is_subckt 1, and set lvs_ignore 1. Hence, switching between CDL and SPICE netlists can be done with lvs_netlist.
To extract a CDL schematic netlist for KLayout LVS, use:
make klayout-lvs-netlist
make klayout-lvs-netlist CELL=chip_top
make klayout-lvs-netlist EV_PRECISION=5To extract a SPICE schematic netlist for Magic + Netgen LVS, use:
make magic-lvs-netlist
make magic-lvs-netlist CELL=chip_top
make magic-lvs-netlist EV_PRECISION=5Exports the schematic netlist from Xschem, then runs LVS. Compares the GDS layout in layout/ against the schematic netlist in netlist/schematic/. Both flows use sak-lvs.sh and write their reports into per-cell run folders: verification/lvs/<CELL>.magic.lvs/ (Magic + Netgen) and verification/lvs/<CELL>.klayout.lvs/ (KLayout, .lvsdb). The run folders are wiped at the start of each run, so they always reflect the latest run only. The extracted layout netlist is moved to netlist/layout/.
KLayout LVS uses sak-lvs.sh (KLayout mode -k), which wraps run_lvs.py from the IHP Open-PDK:
make klayout-lvs
make klayout-lvs CELL=chip_topMagic + Netgen LVS uses sak-lvs.sh (Magic + Netgen mode -m, the default), which extracts the layout netlist with Magic and compares it against the schematic netlist with Netgen, using the Netgen setup from the IHP Open-PDK:
make magic-lvs
make magic-lvs CELL=chip_topRuns parasitic extraction on the GDS layout in layout/. The extracted SPICE netlist is written to netlist/pex/.
The extracted SPICE filenames include the selected extraction mode:
klayout-pexwritesnetlist/pex/<CELL>_klayout_pex_<EXT_MODE>.spicemagic-pexwritesnetlist/pex/<CELL>_magic_pex_<EXT_MODE>.spice
The EXT_MODE parameter selects the extraction mode:
1= C-decoupled (default)2= C-coupled3= full-RC
Note
For klayout-pex, EXT_MODE=1 (C-decoupled) is not yet supported by kpex and automatically falls back to EXT_MODE=2 (CC) with a warning.
The .subckt name in the extracted SPICE file is <CELL>_pex: magic-pex sets it directly via the sak-pex.sh option -n <CELL>_pex, while for klayout-pex it is automatically renamed from <CELL> (kpex).
If a matching Xschem symbol (schematic/xschem/<CELL>_pex.sym) exists, the .subckt pin order in the extracted SPICE file is automatically reordered with sak-pin-reorder.py (installed in the IIC-OSIC-TOOLS container) to match the symbol's pin positions. This ensures the PEX netlist can be used directly with the corresponding Xschem symbol for simulation regardless of the selected EXT_MODE.
Both targets finish by running scripts/check_pex_ports.py on the netlist they just wrote. It verifies that every pin of the .subckt really reaches the circuit, and fails the target otherwise. Two cases are caught:
- A port that is declared in the
.subcktline but referenced by no element at all. Whatever is wired to that pin from outside is then left floating. - A port whose net was split into
<port>.t<n>and<port>.n<n>fragments byextresist(EXT_MODE=3), where none of the fragments is connected back to the port. The pin is then dangling even though the fragments themselves are wired up.
Both produce a netlist that ngspice reads without a single warning while the cell behaves completely differently in simulation, so the check is worth the two seconds it costs. It can also be run by hand on any SPICE netlist:
python3 scripts/check_pex_ports.py netlist/pex/chip_top_magic_pex_1.spice
python3 scripts/check_pex_ports.py -v netlist/pex/*.spice # -v also prints the size of each subcircuitKLayout PEX uses kpex with the Magic extraction engine currently (2.5D engine is work in progress):
make klayout-pex
make klayout-pex CELL=chip_top
make klayout-pex CELL=chip_top EXT_MODE=3Magic PEX uses sak-pex.sh, which extracts the parasitics with Magic (C-decoupled, C-coupled, or full-RC):
make magic-pex
make magic-pex CELL=chip_top
make magic-pex CELL=chip_top EXT_MODE=3For full-RC extraction (EXT_MODE=3), magic-pex additionally exposes the three extresist tuning parameters of sak-pex.sh. They are ignored in EXT_MODE=1/2.
A full-RC extraction of a whole chip would produce a resistor network far too large to simulate, and most of it would be wires so short that their resistance does not matter. The three parameters are the filters Magic applies to keep only the part of the network that is worth having. They run in this order:
THRESHOLD(-t, in mOhm, default10000= 10 Ohm) decides which nets are extracted at all. Before doing any real work, Magic makes a quick end-to-end resistance guess for every net. The guess is deliberately pessimistic, it is an absolute worst case. Nets that stay belowTHRESHOLDeven in that worst case cannot matter, so they are treated as ideal wires and skipped. This is the cheap first pass that removes the many short, low-resistance nets.MINDELAY(-y, in ps, default1) decides which of the extracted nets are kept. Because the guess above overestimates, Magic re-checks each net once it has been properly extracted and discards its resistor network again if the RC delay it adds stays belowMINDELAY. SettingMINDELAY=0switches the delay criterion off and appliesTHRESHOLDa second time instead, now against the accurately extracted resistance rather than the initial guess.MINRES(-r, in mOhm, default1000= 1 Ohm) decides how detailed the kept networks are. Inside a net, neighbouring resistors belowMINRESare merged as far as possible, which shrinks the network without changing its overall resistance much.
In short: THRESHOLD and MINDELAY control how many nets carry parasitic resistance, MINRES controls how finely each of them is modelled. Raising all three gives a smaller netlist that simulates faster with less detail, lowering them gives a more accurate but considerably larger one.
make magic-pex CELL=chip_top EXT_MODE=3 THRESHOLD=5000 MINRES=500 MINDELAY=2Runs DRC, LVS, and PEX for a specific cell (e.g. chip_top):
make klayout-verify CELL=chip_top
make magic-verify CELL=chip_topRuns DRC, LVS, and PEX for the top cell:
make klayout-verify
make magic-verifyGenerates the bondplan fully automatically: the die placed in the package cavity, all bondwires, a pin table, and the filled EUROPRACTICE title block. Inputs are the final chip GDS (layout/chip_top_logo_fill.gds.gz) and the EUROPRACTICE package library, from which the QFN32 drawing sheet is extracted:
make bondplan # uses the default VERSION (1.0.0)
make bondplan VERSION=2.1.0 # stamp another version on the sheetThe VERSION variable is passed to the flow and printed in the title block (DIE: CHIP_TOP - V.1.0.0), so the version number is maintained in the Makefile only.
The flow (packaging/scripts/run_bondplan.py) is driven by packaging/config.yaml, which holds the full package-pin-to-die-pad PINOUT in a LibreLane-style config format. It detects the die bondpads (Passiv openings and TopMetal2.text labels), places the die in the package cavity, draws the bondwires, and checks wire lengths, crossings, spacing, lead skew and analog guard clearances. Outputs:
packaging/layout/chip_top_bondplan.gds: the bondplan GDS- packaging/result.md: bond report with summary and bond table
packaging/render/chip_top_bondplan_{white,black}.{png,svg}: bonding diagram images
See packaging/README.md for the full flow documentation and configuration reference.
Bonding diagram of the ihp-sg13g2 AMS template chip in a QFN32 package.
Runs build-all first, followed by Magic DRC for both chip_top and chip_top_logo_fill, then the chip simulations (sim-all) and finally generates the bondplan (bondplan) once all checks have passed:
make allCopies the final top-level GDS with logo and fill structures from layout/ to release/v.<VERSION>/gds/, copies the generated netlists into release/v.<VERSION>/netlist/, and copies the chip renders and the bonding diagram into release/v.<VERSION>/img/.
The following netlist folders are exported:
netlist/schematic->release/v.<VERSION>/netlist/schematicnetlist/layout->release/v.<VERSION>/netlist/layoutnetlist/pnl->release/v.<VERSION>/netlist/pnlnetlist/spice->release/v.<VERSION>/netlist/spice
Note
netlist/pex is not copied by the release target. It holds the Magic-extracted top-level netlist (chip_top_magic_pex_1.spice, ~73 MB and ~566k lines even in the C-decoupled EXT_MODE=1). Since release/ is committed to the repository, copying it would add those ~73 MB to every released version. The netlist stays available in netlist/pex/.
Note
netlist/schematic and netlist/layout are still empty. The schematic netlist is written by klayout-lvs-netlist / magic-lvs-netlist and the extracted layout netlist by klayout-lvs / magic-lvs, and the top-level LVS is not finished yet. Both folders fill up once it runs through.
The following chip renders are exported:
render/img/chip_top_black.png->release/v.<VERSION>/img/chip_top_black.pngrender/img/chip_top_white.png->release/v.<VERSION>/img/chip_top_white.pngrender/img/chip_top_librelane.png->release/v.<VERSION>/img/chip_top_librelane.png
The bonding diagram is exported as well (see make bondplan):
packaging/render/chip_top_bondplan_black.png->release/v.<VERSION>/img/chip_top_bondplan_black.pngpackaging/render/chip_top_bondplan_white.png->release/v.<VERSION>/img/chip_top_bondplan_white.png
Run with default version (1.0.0):
make releaseRun with a custom version:
make release VERSION=2.1.0The regression target is the project's end-to-end smoke test for the IIC-OSIC-TOOLS environment. Its goal is to exercise every tool and flow in the template at least once with the shortest possible runtime. It is a tool/flow regression, not a design sign-off.
make regressionThis target also runs automatically in continuous integration: the regression GitHub Actions workflow runs make regression inside the IIC-OSIC-TOOLS container nightly (and on manual dispatch), and its status is shown by the Regression badge at the top of this README. The scheduled run is gated so it only executes when there have been changes since the previous night.
To keep the runtime low while still covering the full toolchain, the regression makes the following trade-offs:
- The counter macro is hardened with
librelane-magicdrc(only Magic DRC enabled, the slower KLayout DRC is skipped). Netgen LVS still runs as part of the flow. - The chip top-level runs
librelane-nodrc. All DRC checks are skipped to save runtime on the large top-level assembly. The macros and IP blocks are DRC-checked individually beforehand, so this only leaves the top-level routing/fill unchecked. - KLayout DRC (
sak-drc.sh) is skipped inside the LibreLane runs, but is still exercised in the bondpad and logo IP builds, and in the inverterklayout-verify. - Only one logo (
sg13g2_ip__jku) is regenerated. It is the only step that exercises the PNG to GDS flow. The second logo (sg13g2_ip__jku_names) uses an identical toolchain and reuses its committed views. - Exactly one CACE parameter set is run (the AC VDD sweep
ac_params, no Monte-Carlo). Swapac_paramsforac_mc_params/ac_mm_paramsin the target to also exercise the Monte-Carlo flow.
The regression runs bottom-up: first the inverter and counter macros, then the top-level assembly (submodules, bondpad, logo) and finally the chip top-level LibreLane run that integrates the freshly built macros and IP. After the counter is hardened, copy-final copies its fresh flow/final/ views into macros/counter/final/, so that the gate-level simulation (sim-gl-cocotb) and the chip top-level integration use the freshly built outputs rather than the committed ones.
The following tools and flows are checked:
| Tool / flow | Where it is exercised |
|---|---|
| git submodules | init-submodules |
| KLayout scripting (bondpad generator), KLayout DRC, Magic DRC | build-bondpad |
| PNG to GDS logo generation, KLayout DRC, Magic DRC | sg13g2_ip__jku all (single logo) |
| Xschem + ngspice (analog simulation) | inverter sim-xschem (inverter_tb_dc_vout) |
| CACE (+ ngspice) | inverter CACE, single parameter set (ac_params) |
KLayout DRC (sak-drc.sh) + KLayout LVS (sak-lvs.sh) + KLayout PEX (kpex) |
inverter klayout-verify CELL=inverter_top |
Magic DRC (sak-drc.sh) + Magic extract + Netgen LVS (sak-lvs.sh) + Magic PEX (sak-pex.sh) |
inverter magic-verify CELL=inverter_top |
Magic LEF export + LIB + Verilog stub + lay2img render |
inverter build-top |
| Verilator lint | counter lint-verilog-all |
Icarus Verilog (iverilog/vvp) |
counter sim-rtl-verilog |
| cocotb (RTL + gate-level) | counter sim-rtl-cocotb, sim-gl-cocotb |
| yosys + nextpnr-ice40 + icepack (FPGA) | counter build-fpga |
| LibreLane (OpenROAD / yosys / KLayout streamout / Netgen LVS) | counter librelane-magicdrc, chip librelane-nodrc |
| Magic DRC (sign-off, run inside LibreLane) | counter librelane-magicdrc |
spi2xspice.py + sak-pin-reorder.py (XSPICE model) |
counter generate-xspice |
| Xschem gate-level | counter sim-gl-xschem |
@software{2026_ams_chip_template,
author = {Dorrer, Simon and Pretl, Harald},
month = apr,
year = {2026},
title = {{GitHub Repository of an Open-Source Analog-Mixed Signal Chip Design Template for the ihp-sg13g2 Open-PDK}},
url = {https://github.com/iic-jku/ihp-sg13g2-ams-chip-template},
doi = {10.5281/zenodo.20129233}
}
First, we would like to thank the open-source chip design community for its valuable input and constructive feedback. We especially thank
- Leo Moser, who initially started template repositories based on the LibreLane flow.
- Tim Edwards for helping with Magic + Netgen LVS and PEX issues.
- Krzysztof Herman for discussions about the directory structure.
This project is funded by the JKU/SAL IWS Lab, a collaboration of Johannes Kepler University and Silicon Austria Labs.
|
|
|
Licensed under the Solderpad Hardware License v2.1, see LICENSE.