Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 174 additions & 0 deletions .github/workflows/device-testing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# Device model tests (ihp-sg13g2/libs.tech/ngspice/testing/devices): measured vs simulated.
#
# Thin by design: every step calls a script or a make target that runs the same way locally.
# plan job matrices from toolchain.lock (tools/ci_matrix.py)
# ngspice build each pinned ngspice version once, cached (tools/toolchain.py build ngspice)
# openvaf build each pinned OpenVAF-Reloaded commit once and compile PSP103 with it, cached
# unit-tests framework unit tests and the HBT de-embedding check (no simulation)
# tests one job per toolchain and make target; a job fails on NEW failures (no exactly
# matching exception in waivers/), simulation errors, or exceptions whose curve is
# missing. The job summary has the counts per run (waived curves counted as failures),
# every new failure and the toolchain record; every failure is in the uploaded
# final_reports.
# Caches are keyed on toolchain.lock, tools/ci_setup.sh and the runner image name (ubuntu-24.04,
# the `runs-on` of every job), so a pin change
# (or `cache_version` in toolchain.lock) rebuilds them; an edit of tools/toolchain.py does not
# (hashFiles() is only allowed inside steps, so each cache key spells it out).

name: Device Testing

on:
push:
branches: [device_models_testing]
pull_request:
paths:
- "ihp-sg13g2/libs.tech/ngspice/testing/devices/**"
- "ihp-sg13g2/libs.tech/ngspice/models/**"
- "ihp-sg13g2/libs.tech/verilog-a/**"
- ".github/workflows/device-testing.yml"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.repository }}-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
# (not MV / DEV: libtool reads $MV as its move command when ngspice is built)
DEV_DIR: ihp-sg13g2/libs.tech/ngspice/testing/devices
TOOLCHAIN_ROOT: /home/runner/toolchains

# bash -eo pipefail for every step (a failing command inside a pipe fails the step)
defaults:
run:
shell: bash

jobs:
plan:
runs-on: ubuntu-24.04
outputs:
ngspice: ${{ steps.matrix.outputs.ngspice }}
openvaf: ${{ steps.matrix.outputs.openvaf }}
tests: ${{ steps.matrix.outputs.tests }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.14"
cache: pip
cache-dependency-path: ${{ env.DEV_DIR }}/requirements.lock
- run: pip install -r "$DEV_DIR/requirements.lock"
- id: matrix
run: python3 "$DEV_DIR/tools/ci_matrix.py" >> "$GITHUB_OUTPUT"

ngspice:
needs: plan
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.plan.outputs.ngspice) }}
steps:
- uses: actions/checkout@v4
- id: cache
uses: actions/cache@v4
with:
path: ${{ env.TOOLCHAIN_ROOT }}/ngspice-${{ matrix.version }}
key: ngspice-${{ matrix.version }}-${{ runner.os }}-ubuntu-24.04-${{ hashFiles('ihp-sg13g2/libs.tech/ngspice/testing/devices/toolchain.lock', 'ihp-sg13g2/libs.tech/ngspice/testing/devices/tools/ci_setup.sh') }}
- if: steps.cache.outputs.cache-hit != 'true'
uses: actions/setup-python@v5
with:
python-version: "3.14"
- if: steps.cache.outputs.cache-hit != 'true'
run: |
pip install -r "$DEV_DIR/requirements.lock"
$DEV_DIR/tools/ci_setup.sh ngspice
python3 "$DEV_DIR/tools/toolchain.py" build ngspice ${{ matrix.version }}

openvaf:
needs: plan
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
commit: ${{ fromJSON(needs.plan.outputs.openvaf) }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.14"
cache: pip
cache-dependency-path: ${{ env.DEV_DIR }}/requirements.lock
- run: pip install -r "$DEV_DIR/requirements.lock"
- id: openvaf
uses: actions/cache@v4
with:
path: ${{ env.TOOLCHAIN_ROOT }}/openvaf-r-${{ matrix.commit }}
key: openvaf-${{ matrix.commit }}-${{ runner.os }}-ubuntu-24.04-${{ hashFiles('ihp-sg13g2/libs.tech/ngspice/testing/devices/toolchain.lock', 'ihp-sg13g2/libs.tech/ngspice/testing/devices/tools/ci_setup.sh') }}
- id: osdi
uses: actions/cache@v4
with:
path: ${{ env.DEV_DIR }}/osdi_build/ovr-${{ matrix.commit }}
key: osdi-${{ matrix.commit }}-${{ runner.os }}-ubuntu-24.04-${{ hashFiles('ihp-sg13g2/libs.tech/ngspice/testing/devices/toolchain.lock', 'ihp-sg13g2/libs.tech/ngspice/testing/devices/tools/ci_setup.sh', 'ihp-sg13g2/libs.tech/verilog-a/psp103/**') }}
# OpenVAF is only needed to compile the models: nothing to do when their cache hit.
- if: steps.osdi.outputs.cache-hit != 'true'
run: $DEV_DIR/tools/ci_setup.sh llvm
- if: steps.osdi.outputs.cache-hit != 'true' && steps.openvaf.outputs.cache-hit != 'true'
run: python3 "$DEV_DIR/tools/toolchain.py" build openvaf ${{ matrix.commit }}
- if: steps.osdi.outputs.cache-hit != 'true'
run: python3 "$DEV_DIR/tools/toolchain.py" osdi ${{ matrix.commit }}

unit-tests:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.14"
cache: pip
cache-dependency-path: ${{ env.DEV_DIR }}/requirements.lock
- run: pip install -r "$DEV_DIR/requirements.lock"
- run: make -C "$DEV_DIR" unit-tests
- run: make -C "$DEV_DIR" check-deembedding RESULTS_ROOT=models_results/checks

tests:
needs: [plan, ngspice, openvaf]
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.plan.outputs.tests) }}
name: ${{ matrix.target }} (${{ matrix.toolchain }})
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.14"
cache: pip
cache-dependency-path: ${{ env.DEV_DIR }}/requirements.lock
- run: pip install -r "$DEV_DIR/requirements.lock"
- run: $DEV_DIR/tools/ci_setup.sh ngspice
- id: ids
run: python3 "$DEV_DIR/tools/toolchain.py" ids ${{ matrix.toolchain }} >> "$GITHUB_OUTPUT"
- uses: actions/cache/restore@v4
with:
path: ${{ env.TOOLCHAIN_ROOT }}/ngspice-${{ steps.ids.outputs.ngspice }}
key: ngspice-${{ steps.ids.outputs.ngspice }}-${{ runner.os }}-ubuntu-24.04-${{ hashFiles('ihp-sg13g2/libs.tech/ngspice/testing/devices/toolchain.lock', 'ihp-sg13g2/libs.tech/ngspice/testing/devices/tools/ci_setup.sh') }}
fail-on-cache-miss: true
- uses: actions/cache/restore@v4
with:
path: ${{ env.DEV_DIR }}/osdi_build/ovr-${{ steps.ids.outputs.openvaf }}
key: osdi-${{ steps.ids.outputs.openvaf }}-${{ runner.os }}-ubuntu-24.04-${{ hashFiles('ihp-sg13g2/libs.tech/ngspice/testing/devices/toolchain.lock', 'ihp-sg13g2/libs.tech/ngspice/testing/devices/tools/ci_setup.sh', 'ihp-sg13g2/libs.tech/verilog-a/psp103/**') }}
fail-on-cache-miss: true
- run: make -C "$DEV_DIR" ${{ matrix.target }} TOOLCHAIN=${{ matrix.toolchain }}
- if: always()
run: python3 "$DEV_DIR/tools/ci_summary.py" "$DEV_DIR/models_results/${{ matrix.toolchain }}" --title "${{ matrix.target }} on ${{ matrix.toolchain }}" | tee -a "$GITHUB_STEP_SUMMARY"
- if: always()
uses: actions/upload-artifact@v4
with:
name: reports-${{ matrix.target }}-${{ matrix.toolchain }}
path: |
${{ env.DEV_DIR }}/models_results/${{ matrix.toolchain }}/**/final_reports/
${{ env.DEV_DIR }}/models_results/${{ matrix.toolchain }}/**/toolchain.txt
if-no-files-found: warn
39 changes: 39 additions & 0 deletions ihp-sg13g2/libs.tech/ngspice/testing/devices/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# =========================================================================================
# Copyright 2025 IHP PDK Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# =========================================================================================

# Generated verification run output (logs, netlists, CSVs, reports) — never committed.
models_results/

# Results of an analysis of the runs kept outside this repository -- never committed.
models_results_analysis/

# Generated MOS error-EDA output (Milestone M3: report.md, figures, labels.json cache)
# — never committed, regenerated by `make eda-mos` / `make eda-<device>`.
eda_report/

# Generated measured-vs-simulated figures (`make plot-<device>` / `make plot-all`)
# — never committed.
figures/

# Python build/runtime artifacts local to this test suite (also covered by the repo
# root .gitignore, listed again here for clarity/self-containment).
__pycache__/
*.pyc
venv/
*.osdi

# Verilog-A models compiled per OpenVAF build (`make osdi`, tools/toolchain.py) — never committed.
osdi_build/
10 changes: 10 additions & 0 deletions ihp-sg13g2/libs.tech/ngspice/testing/devices/.spiceinit
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
* a custom spiceinit file for IHP-Open-PDK

set ngbehavior=hsa
set num_threads=1
set ng_nomodcheck

* add OSDI: PSP103 compiled with the OpenVAF build of the selected toolchain. The Makefile exports
* OSDI_DIR (tools/toolchain.py path osdi-dir <toolchain>, filled by `make osdi`).
osdi '$OSDI_DIR/psp103.osdi'
osdi '$OSDI_DIR/psp103_nqs.osdi'
Loading
Loading