Diff two CMSIS-SVD register maps and classify changes as BREAKING/WARNING/SAFE.
Project description
regdrift
regdrift is a compatibility gate for CMSIS-SVD register maps. It compares
two silicon descriptions, classifies every detected change as BREAKING,
WARNING, or SAFE, and returns a CI-friendly verdict.
A moved register can leave a driver compiling cleanly while every write lands at the wrong address. regdrift catches that change in the pull request, before it becomes a logic-analyzer debugging session.
Status:
0.1.0a2is a public alpha, published on PyPI. The implementation is exercised against 15 pinned vendor SVDs, but the explicit limitations in RULES.md still apply.
Highlights
- Resolves
derivedFrom, register-property inheritance, nested clusters,dimarrays, enumerated values, interrupts, and read/write side effects. - Uses deterministic structural matching with conservative rename detection.
- Applies a published 22-rule contract: 15
BREAKING, 4WARNING, and 3SAFErules. - Produces ranked text, schema-versioned JSON, or GitHub workflow annotations.
- Supports exact-path allowlisting, project-wide severity overrides, stdin for the baseline file, and configurable failure thresholds.
- Ships as both a Python CLI and a composite GitHub Action.
- Has unit, CLI, mutation, fuzz, golden, real-vendor corpus, and performance coverage on Python 3.11 and 3.12.
Installation
Install the current alpha from PyPI:
python -m pip install regdrift==0.1.0a2
or, as an isolated CLI tool:
pipx install regdrift==0.1.0a2
To install from source instead:
git clone https://github.com/Pranav-s79/regdrift.git
cd regdrift
python -m venv .venv
# POSIX: source .venv/bin/activate
# Windows PowerShell: .venv\Scripts\Activate.ps1
python -m pip install .
For development, install the editable package and validation tools instead:
python -m pip install -e ".[dev]"
python scripts/fetch_corpus.py
Quick start with the synthetic data
The committed demo/ folder contains two revisions of an imaginary
accelerator. The candidate moves a register, renames a field, renumbers an
interrupt, changes write semantics and a reset value, and adds a register.
regdrift check demo/chip_v1.svd demo/chip_v2.svd
BREAKING (4)
RD015 interrupt ACCEL.ACCEL_DONE renumbered 17 -> 18
RD005 field ACCEL.CTRL.ENABLE renamed (was EN; exact structural match)
RD001 register ACCEL.STATUS address moved 0x8 -> 0xC
RD017 field ACCEL.STATUS.DONE write semantics changed oneToClear -> oneToSet (what writing a bit does is inverted or altered)
WARNING (1)
RD010 register ACCEL.STATUS reset value changed 0x1 -> 0x0
1 safe (1 added) - use --all to list
4 breaking, 1 warning, 1 safe, 0 allowed
The command exits 1 because the candidate contains unallowed breaking
changes. Run it with --all to list the safe addition too.
CLI
| Command | Purpose |
|---|---|
regdrift parse DEVICE.svd |
Validate and summarize a resolved SVD model. |
regdrift parse DEVICE.svd --json |
Emit the canonical model as JSON. |
regdrift diff OLD.svd NEW.svd |
List factual structural changes without policy. |
regdrift diff OLD.svd NEW.svd --format json |
Emit the raw change list as JSON. |
regdrift check OLD.svd NEW.svd |
Classify changes and enforce the compatibility gate. |
Useful gate options:
# Show SAFE findings instead of rolling them up.
regdrift check old.svd new.svd --all
# Fail on warnings as well as breaking changes.
regdrift check old.svd new.svd --fail-on warning
# Produce stable machine-readable output.
regdrift check old.svd new.svd --format json
# Emit GitHub workflow commands.
regdrift check old.svd new.svd --format github
# Read the baseline from stdin.
git show origin/main:device.svd | regdrift check - device.svd
check uses these exit codes:
| Code | Meaning |
|---|---|
0 |
No unallowed finding meets the failure threshold. |
1 |
At least one unallowed finding meets the failure threshold. |
2 |
The SVD, configuration, path, or command input is invalid. |
Rulebook and configuration
RULES.md is the normative compatibility contract. Every emitted change must map to exactly one documented rule or classification fails explicitly.
Create .regdrift.toml in the working directory to acknowledge intentional
breaks or adjust policy for a specific toolchain:
allow = [
"RD001:UART0.CTRL", # this rule at this exact path
"RD030", # this rule at every path
]
[severity]
RD013 = "WARNING" # enum removals do not break this project's generator
RD010 = "BREAKING" # reset-value drift must fail this project
Command-line entries add to the file allowlist:
regdrift check old.svd new.svd --allow RD001:UART0.CTRL --allow RD030
Configuration is strict: unknown keys, unpublished rule IDs, malformed allow
entries, and invalid severities are tool errors rather than silent no-ops.
Allowlisting wins over severity overrides and is reported separately as
ALLOWED.
GitHub Actions
The bundled action extracts the baseline SVD from the pull request's base ref, runs the gate, writes a step summary, adds workflow annotations, and can update a sticky pull-request comment.
name: Register-map compatibility
on:
pull_request:
permissions:
contents: read
pull-requests: write
jobs:
regdrift:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: Pranav-s79/regdrift@v0.1.0a2
with:
svd-path: hardware/device.svd
fail-on: breaking
The action installs the source at the selected action ref by default, so its
runtime and action definition stay in sync. Set the optional version input to
an exact published package version to install from PyPI instead. Disable the
sticky comment with comment: "false" if the workflow only has read access.
For a fully manual workflow, install the package and run:
regdrift check /tmp/base.svd hardware/device.svd --format github
Output contracts
- Text output is optimized for review: breaking findings first, then warnings, allowed findings, and a safe-change rollup.
- JSON output includes
schema_version: 1, device metadata, summary counts, the verdict, and every finding. See docs/json-schema.md. - GitHub output escapes untrusted paths and SVD-derived text and caps each annotation severity at nine entries to keep workflow output usable.
Architecture
SVD/XML -> canonical parser -> structural diff -> rule classification -> report -> exit code
Parsing, factual diffing, policy classification, rendering, and CLI orchestration are separate modules. See docs/architecture.md for ownership boundaries and testing strategy.
Data and verification
demo/is committed, deterministic synthetic data. Regenerate it withpython scripts/make_demo.py; CI verifies its generated content.tests/corpus/is a gitignored, pinned 15-file vendor corpus downloaded bypython scripts/fetch_corpus.py.tests/golden/locks canonical parser output for selected corpus files.- The mutation harness proves that every published rule fires against real vendor models.
Run the same checks enforced by CI:
ruff check .
mypy
pytest
Contributor setup and change requirements are documented in CONTRIBUTING.md.
Project documentation
- RULES.md — severities, rationales, calibration, and limitations
- docs/architecture.md — module boundaries and test strategy
- docs/json-schema.md — machine-readable output contract
- CHANGELOG.md — release history
- docs/release-checklist.md — maintainer release runbook
License
Apache-2.0. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file regdrift-0.1.0a2.tar.gz.
File metadata
- Download URL: regdrift-0.1.0a2.tar.gz
- Upload date:
- Size: 83.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
41f5997e45f1d3e364c7ab84e2ee8d449b4f97e952fdd801879eb772ff39fc25
|
|
| MD5 |
a9f3fe81afb02d0b5c4af69ccf36d598
|
|
| BLAKE2b-256 |
4ed91618e407367aeb1a87b1aa7b7330513c7f2c08f0874e12c92c98363da8db
|
Provenance
The following attestation bundles were made for regdrift-0.1.0a2.tar.gz:
Publisher:
release.yml on Pranav-s79/regdrift
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
regdrift-0.1.0a2.tar.gz -
Subject digest:
41f5997e45f1d3e364c7ab84e2ee8d449b4f97e952fdd801879eb772ff39fc25 - Sigstore transparency entry: 2146405907
- Sigstore integration time:
-
Permalink:
Pranav-s79/regdrift@f907684b93f82915b9ad4d0cfe4e3c412e68e42a -
Branch / Tag:
refs/tags/v0.1.0a2 - Owner: https://github.com/Pranav-s79
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f907684b93f82915b9ad4d0cfe4e3c412e68e42a -
Trigger Event:
push
-
Statement type:
File details
Details for the file regdrift-0.1.0a2-py3-none-any.whl.
File metadata
- Download URL: regdrift-0.1.0a2-py3-none-any.whl
- Upload date:
- Size: 29.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fcd7ee0417b7f8b5fd465fb9897417452a9c236604b683f4fe98aa5713e33a71
|
|
| MD5 |
59946a3693b8201a0d89bf67a2d605f1
|
|
| BLAKE2b-256 |
3eff5c638cb6e99b6c06accf7d8bb989fc058d8de7c274ab081f93780c2e0367
|
Provenance
The following attestation bundles were made for regdrift-0.1.0a2-py3-none-any.whl:
Publisher:
release.yml on Pranav-s79/regdrift
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
regdrift-0.1.0a2-py3-none-any.whl -
Subject digest:
fcd7ee0417b7f8b5fd465fb9897417452a9c236604b683f4fe98aa5713e33a71 - Sigstore transparency entry: 2146405920
- Sigstore integration time:
-
Permalink:
Pranav-s79/regdrift@f907684b93f82915b9ad4d0cfe4e3c412e68e42a -
Branch / Tag:
refs/tags/v0.1.0a2 - Owner: https://github.com/Pranav-s79
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f907684b93f82915b9ad4d0cfe4e3c412e68e42a -
Trigger Event:
push
-
Statement type: