Metadata-Version: 2.4
Name: soc-consistency
Version: 1.3.0
Summary: Static analysis tool that catches hardware-level bugs in Linux Device Tree Source (DTS) files
Author-email: gahingwoo <huhuvmb88@outlook.com>
License: MIT
Project-URL: Homepage, https://github.com/gahingwoo/SoC-Consistency
Project-URL: Repository, https://github.com/gahingwoo/SoC-Consistency
Project-URL: Bug Tracker, https://github.com/gahingwoo/SoC-Consistency/issues
Project-URL: Changelog, https://github.com/gahingwoo/SoC-Consistency/releases
Keywords: device-tree,dts,dtb,soc,linux,embedded,hardware,static-analysis,linter,rockchip,allwinner,arm
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: System :: Hardware
Classifier: Topic :: Utilities
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pyyaml>=6.0
Requires-Dist: click>=8.0
Requires-Dist: dataclasses-json>=0.5.7
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov>=3.0; extra == "dev"
Requires-Dist: black>=22.0; extra == "dev"
Requires-Dist: isort>=5.0; extra == "dev"
Requires-Dist: mypy>=0.990; extra == "dev"
Requires-Dist: flake8>=4.0; extra == "dev"
Provides-Extra: viz
Requires-Dist: pyvis>=0.3.2; extra == "viz"
Provides-Extra: xlsx
Requires-Dist: openpyxl>=3.0; extra == "xlsx"
Provides-Extra: shell
Requires-Dist: ipython>=8.0; extra == "shell"
Provides-Extra: all
Requires-Dist: pyvis>=0.3.2; extra == "all"
Requires-Dist: openpyxl>=3.0; extra == "all"
Requires-Dist: ipython>=8.0; extra == "all"
Dynamic: license-file

# socc — SoC Device-Tree Consistency Checker

[![PyPI](https://img.shields.io/pypi/v/soc-consistency)](https://pypi.org/project/soc-consistency/)
[![Python](https://img.shields.io/pypi/pyversions/soc-consistency)](https://pypi.org/project/soc-consistency/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

**socc** is a static-analysis and behavioural-simulation tool that catches
hardware-level bugs in Linux Device Tree Source (DTS) files — the kind that
pass `dtc` and `dt-schema` validation but still destroy your board at runtime.

If you have ever spent a week chasing a suspend-resume panic caused by a
wrong power-supply phandle, or a silent DMA hang caused by a copy-pasted
channel index that exceeded the controller's physical limit, socc is for you.

```text
$ socc check board.dts --soc rk3588
[FATAL]  PD-001  Power domain crossing — /soc/i2c@fe2b0000 uses vcc_3v3 (EE domain)
                  but is connected to vcc_1v8 (AO domain). System will panic on suspend.
[ERROR]  CK-003  Clock rate mismatch — spi0 requests 50 MHz from pll_cpll (max 24 MHz).
[WARN]   GP-002  GPIO conflict — gpio1_b3 assigned to both spi0 and uart2.

$ socc sim scenario board.dts --soc rk3588 --scenario suspend
Behavioral Simulation: rk3588  [board.dts]

  Scenario: suspend
  error[PS-002]  'vcc_io' disabled at t=4.5ms but uart0 not yet suspended
    Detail:  Active consumers: uart0
    Fix:     Ensure uart0 completes suspend callback before vcc_io is powered down.
  [UNSAFE] 1 error(s), 0 warning(s)  duration=6.5ms
```

---

## Table of Contents

- [Why socc?](#why-socc)
- [Installation](#installation)
- [Quick start](#quick-start)
- [Commands](#commands)
  - [Top-level](#top-level)
  - [socc audit — compatibility & BOM](#socc-audit--compatibility--bom)
  - [socc analyze — static analysis](#socc-analyze--static-analysis)
  - [socc generate — artifacts](#socc-generate--artifacts)
  - [socc viz — visualization](#socc-viz--visualization)
  - [socc sim — simulation & live-board](#socc-sim--simulation--live-board)
  - [socc socdef — constraint files](#socc-socdef--constraint-files)
- [Supported SoCs](#supported-socs)
- [CI / CD integration](#ci--cd-integration)
- [What's new in v1.3.0](#whats-new-in-v130)
- [What's new in v1.2.3](#whats-new-in-v123)
- [What's new in v1.2.2](#whats-new-in-v122)
- [What's new in v1.2](#whats-new-in-v12)
- [What's new in v1.2 (continued)](#whats-new-in-v12-continued--developer-experience-features)
- [Upgrading from pre-1.1](#upgrading-from-pre-11)
- [Rules reference](#rules-reference)
- [Architecture](#architecture)
- [Contributing](#contributing)

---

## Why socc?

| Tool | What it checks |
|------|---------------|
| `dtc` | DTS syntax |
| `dt-schema` / `dtbs_check` | Property types and required fields per binding |
| **socc** | Whether the *system* is physically and electrically correct |

socc operates on the semantic level: it builds an in-memory model of your
power tree, clock tree, pin-mux table, and interrupt routing, then runs
cross-domain constraint rules that no schema can express.

**Real bugs socc catches:**

| Bug class | Example | Runtime effect |
|-----------|---------|---------------|
| Power domain crossing | AO peripheral on EE supply | Suspend-resume panic |
| Clock rate mismatch | SPI clock > PLL maximum | Bus hangs, data corruption |
| GPIO pin conflict | Two nodes mapped to same pad | Silent last-write-wins |
| MMIO region overlap | Two drivers ioremap same address | Kernel memory corruption |
| GPIO index out of bounds | `gpio1 pin 35` on a 32-pin bank | Kernel panic at driver probe |
| IRQ collision | Two devices share GIC SPI 45 | -EBUSY or interrupt storm |
| DMA channel out of bounds | Channel 48 on 32-channel DMA | Silent DMA failure |
| Power/clock cycle | Regulator A requires B requires A | Kernel deadlock at boot |
| Zombie DTS nodes | 14 disabled camera nodes in BSP | Bloated DTB, slow boot |
| Allwinner 3.3V on 1.8V IO | Wrong PMIC rail to PC bank | Permanent IO pad damage |
| Power rail off too early | vcc_io cut before uart0 suspend callback | Kernel panic on suspend |
| Clock gated with active consumer | pclk_uart gated while UART TX in flight | Data corruption / hang |
| Missing reset property | spi@ node has no `resets` | Driver cannot recover from warm reset |

---

## Installation

```bash
pip install soc-consistency
```

Or install from source with development extras:

```bash
git clone https://github.com/gahingwoo/SoC-Consistency.git
cd SoC-Consistency
pip install -e ".[dev]"
```

**Requirements:** Python 3.8+, PyYAML, Click 8.0+

---

## Quick start

```bash
# Run all rules against a DTS file
socc check board.dts --soc rk3588

# Auto-fix safe violations and write a patch
socc fix board.dts --soc rk3588 -o board.patch

# Semantic diff between two DTS / DTB files
socc smart-diff vendor.dts mainline.dts

# ── analyze group ──────────────────────────────────────────────────────────
socc analyze gc board.dts --soc rk3588          # zombie-node garbage collector
socc analyze memory board.dts                   # MMIO overlap scan
socc analyze bounds board.dts --soc rk3588      # GPIO/DMA/PWM out-of-bounds
socc analyze irq board.dts                      # IRQ collision check
socc analyze deps board.dts                     # power/clock cycle detection

# ── audit group ────────────────────────────────────────────────────────────
socc audit bindings board.dts                   # DTS binding audit
socc audit bom board.dts hardware.csv           # BOM cross-check
socc audit kernel board.dts --kernel /path/to/kernel  # kernel config audit

# ── viz group ─────────────────────────────────────────────────────────────
socc viz topology board.dts --soc rk3588        # HTML topology graph
socc viz pinmap rk3588                          # BGA pin heatmap
socc viz power-seq board.dts                    # power-rail sequencing chart

# ── sim group ─────────────────────────────────────────────────────────────
socc sim failure vcc_3v3 board.dts --soc rk3588 # FMEA blast radius
socc sim shell board.dts --soc rk3588           # interactive simulator
socc sim live-check board.dts --host 192.168.1.1 # live-board SSH audit
socc sim scenario board.dts --soc rk3588        # behavioural power/clock/reset sim
socc sim scenario --demo --scenario all         # try without hardware
```

---

## Commands

### Top-level

| Command | Description |
|---------|-------------|
| `socc check` | Run all rules — output violations by severity |
| `socc fix` | Auto-generate a DTS patch for safe-to-fix violations |
| `socc autofix` | Apply fixes in-place |
| `socc diff` | Show violations introduced between two DTS versions |
| `socc smart-diff` | Semantic DTS/DTB diff (ignores labels/phandles/ordering) |
| `socc explain` | Explain a rule code in plain English with fix examples |
| `socc rules` | List all enabled rules with IDs and descriptions |
| `socc init` | Create a `.socc.yaml` config scaffold |
| `socc version` | Print version and environment information |
| `socc self-update` | Upgrade to the latest release from PyPI |

#### `socc check` options

```bash
socc check board.dts --soc rk3588 \
     --min-severity warning \
     --format json \
     -o report.json
```

| Option | Description |
|--------|-------------|
| `--soc` | Target SoC (`rk3588`, `sun50i-h616`, `imx8mp`, …) |
| `--min-severity` | Filter: `info` \| `warning` \| `error` \| `fatal` |
| `--strict` | Exit non-zero for warnings too (default: only errors block CI) |
| `--format` | Output: `text` (default) \| `json` \| `html` \| `sarif` |
| `--netlist` | Cross-check against a KiCad or CSV netlist |
| `--enable` / `--disable` | Toggle specific rule codes |
| `-o` | Write output to file |

---

### socc audit — compatibility & BOM

```
socc audit COMMAND [OPTIONS] ...
```

| Subcommand | Old flat name | Description |
|------------|--------------|-------------|
| `socc audit bindings` | `socc audit` | DTS binding audit against mainline kernel |
| `socc audit bom` | `socc audit-bom` | Cross-check BOM CSV against DTS peripherals |
| `socc audit kernel` | `socc audit-kernel` | Validate DTS-enabled devices against kernel config |
| `socc audit amp` | `socc amp-audit` | AMP (Linux + RTOS) resource conflict detection |
| `socc audit matrix` | `socc matrix-audit` | Multi-SKU supply-chain variant matrix audit |
| `socc audit cross-check` | `socc cross-check` | Bootloader vs. kernel DTS skew detection |
| `socc audit overlay` | `socc overlay-check` | Validate a DT overlay against its base DTS |
| `socc audit netlist` | `socc crosscheck` | Cross-validate DTS pinctrl against PCB netlist |

---

### socc analyze — static analysis

```
socc analyze COMMAND [OPTIONS] DTS_FILE
```

| Subcommand | Old flat name | Description |
|------------|--------------|-------------|
| `socc analyze memory` | `socc check-memory` | Sweep-line MMIO overlap scanner |
| `socc analyze deps` | `socc check-deps` | Power/clock dependency cycle detector |
| `socc analyze bounds` | `socc check-bounds` | GPIO/DMA/PWM physical-bounds auditor |
| `socc analyze irq` | `socc check-irq` | IRQ collision and reserved-PPI checker |
| `socc analyze gc` | `socc gc` | Zombie-node garbage collector |

#### socc analyze gc

Vendor BSPs ship Device Trees with dozens of disabled nodes for unsupported
board variants.  `gc` identifies unreferenced dead-code nodes and estimates
DTB savings.

```bash
socc analyze gc rockchip-rk3588-evb.dts
```

```text
SOCC DTS ZOMBIE-NODE GARBAGE COLLECTOR
  Alive nodes   : 47
  Zombie nodes  : 14
  Est. DTB savings: 8732 bytes (~8.5 KiB)
```

#### socc analyze bounds

Catches copy-paste GPIO/DMA/PWM index errors that compile fine but panic at
driver probe:

```bash
socc analyze bounds board.dts --soc rk3588
```

```text
[FATAL] BND-001  /leds/user-led1
    gpios = ['&gpio4', 35, 0]  — pin 35 is out of range for gpio4 (max: 31)
```

#### socc analyze irq

Detects two active devices sharing the same non-shared GIC SPI line:

```bash
socc analyze irq board.dts
```

```text
[CRITICAL] IRQ-C01  GIC SPI IRQ 45 claimed by spi0 and uart0 simultaneously.
```

#### socc analyze memory

O(n log n) sweep-line detects every class of `reg` address-space collision:

| Rule | Description |
|------|-------------|
| `MM-001` | Identical window — duplicate node |
| `MM-002` | Full containment — one region inside another |
| `MM-003` | Partial overlap — silent memory corruption |
| `MM-004` | Zero-size region |
| `MM-005` | Suspiciously large region (> 512 MiB) |

#### socc analyze deps

Builds directed power/clock graphs and runs DFS cycle detection:

| Rule | Description |
|------|-------------|
| `DG-CP01` | Cycle in power dependency graph — kernel deadlock at boot |
| `DG-CK01` | Cycle in clock dependency graph |
| `DG-OP01` | Regulator references non-existent parent rail |
| `DG-OK01` | Clock references non-existent parent |

---

### socc generate — artifacts

```
socc generate COMMAND [OPTIONS] DTS_FILE
```

| Subcommand | Old flat name | Description |
|------------|--------------|-------------|
| `socc generate qemu` | `socc generate-qemu` | QEMU launch script or C machine skeleton |
| `socc generate tests` | `socc generate-tests` | Bash bring-up test script |
| `socc generate saleae` | `socc generate-saleae` | Saleae Logic 2 workspace JSON |
| `socc generate headers` | `socc export-headers` | Bare-metal C peripheral address header |
| `socc generate diagram` | `socc generate-diagram` | Mermaid / PlantUML / ASCII topology diagram |
| `socc generate compliance` | `socc generate-compliance` | ISO 26262 / IEC 61508 functional-safety report |
| `socc generate report` | `socc generate-report` | Self-contained HTML architecture report |

---

### socc viz — visualization

```
socc viz COMMAND [OPTIONS]
```

| Subcommand | Old flat name | Description |
|------------|--------------|-------------|
| `socc viz topology` | `socc topology` | Interactive HTML hardware topology graph |
| `socc viz pinmap` | `socc pinmap` | HTML BGA pin heatmap for a SoC |
| `socc viz power-seq` | `socc power-seq` | ASCII power-rail startup sequence chart |

---

### socc sim — simulation & live-board

```
socc sim COMMAND [OPTIONS]
```

| Subcommand | Old flat name | Description |
|------------|--------------|-------------|
| `socc sim failure` | `socc simulate failure` | FMEA blast-radius simulation |
| `socc sim smoke` | `socc simulate-smoke` | Physical-damage risk from DTS config errors |
| `socc sim shell` | `socc shell` | Interactive power/clock state-machine shell |
| `socc sim scenario` | *(new in v1.3.0)* | Behavioural simulation of power/clock/reset sequencing |
| `socc sim live-check` | `socc live-check` | SSH into a board and run consistency checks |
| `socc sim live-probe` | `socc live-probe` | Compare DTS expectations vs. physical registers |
| `socc sim trace` | `socc trace` | Trace how a node's properties change across overlays |
| `socc sim migrate` | `socc migrate` | Assist in porting a DTS to a new target SoC |

---

### socc socdef — constraint files

```
socc socdef COMMAND [OPTIONS]
```

| Subcommand | Old flat name | Description |
|------------|--------------|-------------|
| `socc socdef validate` | `socc validate-socdef` | Validate a `.socdef` file |
| `socc socdef check` | `socc check-socdef` | Check a DTS against a `.socdef` constraint file |
| `socc socdef init` | `socc init-socdef` | Generate a `.socdef` template for a new SoC |

---

## Supported SoCs

socc ships vendor-specific rule packs that know the hardware limits, domain
topology, and common pitfalls of each family.

| Vendor | SoC families | Notes |
|--------|-------------|-------|
| Rockchip | RK3399, RK3568, RK3576, **RK3588**, RK3588S | GPIO banks, power domains, CRU |
| Allwinner | H616, H618, T507, A527 | AXP PMIC sequences, 1.8V IO banks |
| NXP | i.MX8M Plus, i.MX8M Mini | CCM, IOMUXC, power gating |
| Qualcomm | SDM845, SM8550 | GCC node dependency |
| Generic | any ARM/ARM64 | GIC, GPIO, DMA, PWM, IRQ rules |

Adding a new SoC requires only a YAML hardware-constraint file:

```yaml
# data/soc/rockchip/rk3588.yaml
name: rk3588
hardware_limits:
  gpio0: {pins: 32}
  gpio4: {pins: 32}
  dmac0: {channels: 32}
  pwm:   {channels: 16}
power_domains:
  - name: vcc_5v0
    children: [vcc_3v3, vcc_1v8]
```

---

## CI / CD integration

Drop socc into any pipeline:

```yaml
# GitHub Actions
- name: Check DTS consistency
  run: |
    pip install soc-consistency
    socc check board.dts --soc rk3588 --min-severity error --format sarif -o socc.sarif
```

socc exits **0** on success, **3** when errors are present. By default, warnings do **not**
produce a non-zero exit — your pipeline won't fail just because a vendor BSP has
pre-existing style warnings.

Use `--strict` when you want warnings to block CI too:

```yaml
# GitHub Actions — strict mode
- name: Check DTS consistency
  run: |
    pip install soc-consistency
    socc check board.dts --soc rk3588 --strict --format sarif -o socc.sarif
```

| Exit code | Meaning (default) | Meaning (`--strict`) |
|-----------|-------------------|---------------------|
| `0` | Clean or warnings/info only | Clean |
| `2` | — | Warnings present |
| `3` | Errors present | Errors present |

A ready-made GitHub Actions workflow with [OIDC Trusted Publishing](https://docs.pypi.org/trusted-publishers/)
is included at [`.github/workflows/publish.yml`](.github/workflows/publish.yml).

---

## Upgrading from pre-1.1

All flat command names continue to work unchanged (they are registered as
hidden aliases).  No scripts need to be updated.

| Pre-1.1 command | 1.1+ equivalent |
|-----------------|----------------|
| `socc gc` | `socc analyze gc` |
| `socc check-memory` | `socc analyze memory` |
| `socc check-bounds` | `socc analyze bounds` |
| `socc check-irq` | `socc analyze irq` |
| `socc check-deps` | `socc analyze deps` |
| `socc audit` | `socc audit bindings` |
| `socc audit-bom` | `socc audit bom` |
| `socc amp-audit` | `socc audit amp` |
| `socc cross-check` | `socc audit cross-check` |
| `socc generate-qemu` | `socc generate qemu` |
| `socc generate-diagram` | `socc generate diagram` |
| `socc export-headers` | `socc generate headers` |
| `socc topology` | `socc viz topology` |
| `socc pinmap` | `socc viz pinmap` |
| `socc power-seq` | `socc viz power-seq` |
| `socc shell` | `socc sim shell` |
| `socc live-check` | `socc sim live-check` |
| `socc simulate-smoke` | `socc sim smoke` |
| `socc simulate failure NODE DTS` | `socc sim failure NODE DTS` |
| `socc migrate` | `socc sim migrate` |
| `socc validate-socdef` | `socc socdef validate` |
| `socc check-socdef` | `socc socdef check` |

---

## What's new in v1.2

### Rust-style diagnostics

Violation output now looks like a Rust compiler message, with a source-code
snippet and caret underline pointing to the exact DTS line:

```
error[GP-001]: GPIO pin conflict at gpio3/pin8
 --> arch/arm64/boot/dts/rockchip/rk3588-foo.dts:142:5
141 |     pinctrl-0 = <&uart2m1_xfer>;
142 |     pinctrl-0 = <&spi0_cs0>;
    |     ^^^^^^^^^^ Pin already claimed by uart2
    = hint: Remove the duplicate pinctrl-0 assignment.
```

No extra dependencies — uses only `click.style` for ANSI color.

### Fuzzy SoC name matching

Typos in `--soc` now produce helpful suggestions instead of a wall of choices:

```
$ socc check foo.dts --soc rk3589
Error: Unknown SoC 'rk3589'. Did you mean: rk3588, rk3588s, rk3576?
```

### Granular exit codes

`socc check` and `socc diff` now return precise exit codes for use in CI:

| Code | Meaning |
|------|---------|
| `0`  | No violations |
| `1`  | Info-level findings only |
| `2`  | At least one warning |
| `3`  | At least one error |

### Subsystem breakdown

The summary line now includes a per-domain count:

```
Subsystems: [GPIO:23  Power:12  Clock:8  IRQ:3]
Summary: 1 error(s), 12 warning(s), 23 info
```

### Watch mode

```bash
socc check rk3588-board.dts --soc rk3588 --watch
```

Re-runs automatically whenever the file changes.  Press Ctrl-C to stop.

### GitHub Actions annotations

```bash
socc check rk3588-board.dts --soc rk3588 --format annotations
# → ::error file=...,line=...,title=[GP-001]::GPIO pin conflict
```

### `socc diff --ci`

```bash
socc diff baseline.dts pr.dts --soc rk3588 --ci
```

In `--ci` mode the command exits non-zero on *any* regression (not just errors),
ideal for pull-request gates.

### Parse cache

DTS files are cached in `~/.cache/socc/` after the first parse.  Subsequent
runs with the same file are significantly faster.  Pass `--no-cache` to bypass.

```bash
socc check rk3588-board.dts --soc rk3588 --no-cache
```

### IPython shell

`socc sim shell` now launches IPython when it is installed, giving you a rich
interactive environment with tab-completion, history, and a pre-populated
namespace (`model`, `power`, `clock`, `devices`, `check()`, `pins`).

```bash
pip install ipython    # one-time
socc sim shell --demo
```

Falls back to the built-in REPL when IPython is not available.

---

## What's new in v1.3.0

### Behavioural simulation — `socc sim scenario`

v1.3.0 introduces a full behavioural (behaviour-level) simulation engine that
models the three state machines a Linux kernel runs at every boot, suspend, and
resume cycle: **power rail sequencing**, **clock gate/ungate cascades**, and
**reset deassertion ordering**.

Static rules (like those in `socc check`) can only see what the DTS _says_.
The simulation engine asks what actually _happens_ at runtime — and catches
bugs that are invisible to any static analyser.

```bash
# Simulate all 4 scenarios for a board DTS
socc sim scenario board.dts --soc rk3588

# Target one scenario with full event timeline
socc sim scenario board.dts --soc rk3588 --scenario suspend --timeline

# Machine-readable JSON output for CI
socc sim scenario board.dts --soc rk3588 --format json

# No hardware? Try the built-in demo model
socc sim scenario --demo --scenario all
```

#### Scenarios

| Scenario | Description |
|----------|-------------|
| `boot` | Simulate power-on and full device probe sequence |
| `suspend` | Simulate Linux PM suspend (s2idle / deep) |
| `resume` | Simulate resume from suspend back to active |
| `runtime_pm` | Simulate a runtime PM autosuspend + wake cycle |
| `all` | Run all four in sequence (default) |

#### Violation codes

| Code | Severity | Scenario | Description |
|------|----------|----------|-------------|
| `PS-001` | warning | boot | Supply does not meet required stability window before consumer probes |
| `PS-002` | error | suspend | Supply disabled before consumer device finishes its suspend callback |
| `PS-003` | error | boot / resume | Child regulator enabled before parent is fully stable |
| `CG-001` | error | suspend | Clock gated (power domain off) while consumer device still active |
| `CG-002` | error | suspend | Parent clock disabled while child clock has active consumers |
| `RS-001` | error | boot | Device reset deasserted before required clock provider (CRU) is ready |
| `RS-002` | warning | boot | Device missing required `resets` property (prevents safe warm reset) |

#### Example output

```
Behavioral Simulation: rk3588  [board.dts]

  Scenario: suspend
  error[PS-002]  'vcc_io' disabled at t=4.5ms but 1 consumer(s) not yet suspended
    Detail:  Active consumers: uart0
    Fix:     Ensure uart0 completes suspend callback before vcc_io is powered down.
             Check the regulator-off-in-suspend property ordering.
  warning[RS-002]  Device 'spi1' missing required 'resets' property
    Detail:  SoC database requires a resets property for spi@ devices.
    Fix:     Add 'resets = <&cru SRST_SPI1>;' to spi1 in the DTS.
  [UNSAFE] 1 error(s), 1 warning(s)  duration=6.5ms
```

#### Constraint-driven tuning

Timing requirements and ordering rules are read from the SoC YAML file
(`data/soc/rockchip/rk3588.yaml`, `simulation_constraints` section).  The
shipped rk3588 constraints cover:

- **power_sequencing**: `stable_before_consumers_ms` per rail (PS-001 window)
- **clock_gating**: per-clock-pattern `consumers_must_idle_before_gate` flag
- **reset_dependencies**: which providers (CRU, PHY) must be ready per device
- **required_resets_patterns**: which peripheral types must declare `resets`

You can add a `simulation_constraints` section to any SoC YAML file to
get the same level of analysis for custom hardware.

---

## What's new in v1.2.3

### New rule — MM-006: Register Address / Node-Name Mismatch

A DTS node encodes its hardware address in two places: the `@hex` suffix in the
node name (`i2c@fe2b0000`) and the first value of the `reg` property.  When
these two disagree — typically a copy-paste error — the kernel maps the driver
to the **wrong MMIO window**.  The peripheral either fails to probe or silently
corrupts adjacent memory regions.  `dtc` compiles such files without warnings.

```dts
/* BAD — node name says 0xfe2b0000, reg says 0xfe2c0000 */
i2c@fe2b0000 {
    reg = <0xfe2c0000 0x1000>;   /* MM-006 */
};

/* GOOD */
i2c@fe2b0000 {
    reg = <0xfe2b0000 0x1000>;
};
```

```
error[MM-006]: Node is named 'i2c@fe2b0000' (address 0xfe2b0000) but its
               reg property declares base address 0xfe2c0000.
       Fix   : Rename to i2c@fe2c0000 or correct reg to <… 0xfe2b0000 …>.
```

Both 32-bit (`<addr size>`) and 64-bit cell pairs (`<0x0 addr 0x0 size>`) are
handled automatically.

---

### Deliberate-violation annotations — `socc-expect`

The existing `/* socc-ignore: CODE */` comment silences a violation permanently
(useful for known hardware errata).  The new `/* socc-expect: CODE */` comment
serves the opposite purpose: it documents that a violation is **intentional and
load-bearing** (a fly-wire, a hardware workaround, a deliberate override) and
should alert you if it ever disappears.

```dts
/* socc-expect: MM-006 -- voltage-divider fly-wire on board rev B */
i2c@fe2b0000 {
    reg = <0xfe2c0000 0x1000>;
};
```

| State | Behaviour |
|-------|-----------|
| Expected violation fires | Silenced — same as `socc-ignore` |
| Expected violation does NOT fire | `info[SE-001]` injected — stale comment detected |

The `SE-001` message explains which code was expected and on which line, so you
can quickly find and remove the obsolete annotation:

```
info[SE-001]: Expected violation 'MM-006' did not occur near line 5.
              The fly-wire or workaround may have been removed.
       Fix  : Remove or update the '/* socc-expect: MM-006 */' comment.
```

Free-text notes after `--` are ignored (`/* socc-expect: PIN-202 -- confirmed with EE */`).
Multiple codes are comma-separated (`/* socc-expect: MM-006, PD-001 */`).

---

### Binary DTB decompiler — `socc decompile`

Annotates the `dtc` decompile output with human-readable peripheral names from
the SoC hardware database, so you can navigate unfamiliar binary blobs without
memorising address maps.

```bash
socc decompile board.dtb --soc rk3588
socc decompile board.dtb --soc rk3588 -o board_annotated.dts
socc decompile board.dtb --no-annotate     # raw dtc output only
```

Example output (RK3588):

```dts
/*
 * Decompiled by socc v1.2.3 for rk3588
 * Peripheral addresses annotated from hardware constraint database.
 * This file is auto-generated — review before use.
 */

        gpio0@fd8a0000  /* GPIO0 (32-pin, 3.3V) */ {
                ...
        };

        cru@fd7c0000  /* CRU — Clock and Reset Unit */ {
                ...
        };
```

Works on both `.dtb` binary blobs and `.dts` text files.  Falls back to plain
`dtc` output if `dtc` is not installed or if no SoC database entry is found for
the target.

---

## What's new in v1.2.2

### CI-friendly exit codes — `socc check --strict`

By default, `socc check` exits **0** for warnings and info (only errors produce exit 3).
This means CI pipelines don't fail because of pre-existing BSP style warnings.

`--strict` restores the full granular behaviour for teams that want zero warnings:

```bash
# Default — warnings are printed, not fatal:
socc check board.dts --soc rk3588
echo $?   # 0 even if there are warnings

# Strict — warnings fail the build:
socc check board.dts --soc rk3588 --strict
echo $?   # 2 if warnings, 3 if errors
```

### Offline rule lookup — `socc explain CODE`

Look up any rule code instantly, without a DTS file:

```bash
socc explain BW-101
```

```
╭────────────────── BW-101 ──────────────────╮
│ Code:      BW-101                          │
│ Severity:  WARNING                         │
│ Rule name: DDR Bandwidth Saturation Risk   │
│                                            │
│ What this rule checks                      │
│   The sum of enabled high-bandwidth …      │
╰────────────────────────────────────────────╯
```

Renders with `rich` if installed, falls back to plain text automatically.
Unknown codes print the list of valid codes and exit 1.

### Noise-free review diffs — `socc smart-diff --semantic`

The existing `smart-diff` already ignores labels, comments, and phandle
renumbering. `--semantic` goes one step further: it filters the output to show
only **hardware-relevant property changes** — clock frequencies, register
addresses, supply rails, interrupt lines, pin-control settings, etc.

```bash
socc smart-diff vendor.dts mainline.dts --semantic
```

Changes to `linux,phandle`, node ordering, and non-critical DTS metadata are
silently dropped. The remaining diff is exactly what a hardware review needs.

Hardware-critical properties kept by `--semantic`:
`compatible`, `reg`, `status`, `clocks`, `clock-frequency`, `assigned-clock-rates`,
`interrupts`, `*-supply`, `*-microvolt`, `bus-width`, `pinctrl-*`, `resets`,
`power-domains`, `max-link-speed`, `num-lanes`, `*-gpio`, `*-gpios`.

---

## What's new in v1.2 (continued) — developer-experience features

### `socc bootstrap` — zero-cost SoC onboarding

Don't have a YAML constraint file for your SoC?  Point `socc bootstrap` at any
directory of Linux mainline `.dtsi` files and it will generate a working stub in
under two seconds:

```bash
socc bootstrap --from-mainline ./linux/arch/arm64/boot/dts/rockchip/ --soc rk3588
# → data/soc/rockchip/rk3588.yaml  (GPIO banks, clocks, IRQ controllers)
```

The generated file is fully editable.  Add datasheet-level constraints
(max GPIO index, clock ceiling, memory size) to get deeper checks.

### `socc viz pinmap --format xlsx` — Excel pin-assignment matrix

Hardware engineers live in Excel.  Export a fully formatted, colour-coded
pin-assignment spreadsheet that you can drop straight into a design document:

```bash
socc viz pinmap board.dts --soc rk3588 --format xlsx -o rk3588_pins.xlsx
socc viz pinmap board.dts --soc rk3588 --format csv  -o rk3588_pins.csv
```

Requires `openpyxl` (`pip install socc[xlsx]`).

### Inline `socc-ignore` suppression comments

Suppress a specific violation on the offending line without touching the
command line.  The comment is visible in code review and carries an optional
reason:

```dts
/* socc-ignore: BND-001 -- hardware errata, confirmed by vendor */
gpios = <&gpio4 35 GPIO_ACTIVE_HIGH>;
```

Multiple codes can be listed comma-separated: `/* socc-ignore: BND-001, GP-002 */`.

### `.socc_ignore` project-level exclusion file

Like `.gitignore` but for violations.  Commit it to your repo so the whole
team benefits:

```
# .socc_ignore
# Legacy layout — scheduled for Q3 hardware respin
BND-001  /soc/spi@fe610000
PD-006   *                   # suppress all orphaned-regulator warnings globally
GP-*     legacy/             # all GPIO rules in legacy/ subdirectory
```

Format: `CODE [PATH_GLOB]  [# optional comment]`

### Result cache — skip the rule engine when nothing changed

When the DTS file content is identical to the previous run, `socc check`
now skips parsing **and** rule execution entirely, reading cached violations
instead:

```
[cache] 2 violation(s) (content unchanged, skipped rule engine)
```

Invalidated automatically when any rule is added or the file changes.
Bypass with `--no-cache`.

### Custom rule plugin directory (`--rules-dir`)

Load company-internal rules without forking:

```bash
socc check board.dts --soc rk3588 --rules-dir ./acme_rules/
```

Every `*.py` file in the directory is imported.  If it exposes a
`register(registry)` function that function is called with the live registry.

```python
# acme_rules/power_budget.py
from socc.rules.base import Rule, Violation

class AcmePowerBudgetRule(Rule):
    code     = "ACME-001"
    name     = "Power budget"
    severity = "error"
    description = "Total power draw must not exceed 5 W"
    soc_targets = ["*"]

    def check(self, model, ctx):
        # … your logic …
        return []

def register(registry):
    registry.register(AcmePowerBudgetRule())
```

### `socc check --since REF` — git-aware incremental check

In CI, check only files changed since a git reference:

```bash
socc check board.dts --soc rk3588 --since origin/main
# → skipped if board.dts has no changes since origin/main
```

### `socc install-hook` — one-command git pre-commit integration

```bash
socc install-hook               # .git/hooks/pre-commit
socc install-hook --hook pre-push
socc install-hook --uninstall   # remove it
```

The hook automatically checks only **staged** DTS files, so it adds
milliseconds of latency for non-DTS commits.

---

## Rules reference

Run `socc rules` to list all active rules.  The full reference is in
[docs/rules.md](docs/rules.md).

Quick overview by domain:

| Prefix | Domain |
|--------|--------|
| `PD-` | Power domain integrity |
| `CK-` | Clock tree consistency |
| `GP-` | GPIO pin-mux conflicts |
| `MM-` | MMIO address-map overlaps |
| `BND-` | Physical resource bounds |
| `IRQ-` | Interrupt routing |
| `DG-` | Dependency graph cycles |
| `TH-` | Thermal zone configuration |
| `BW-` | Bus bandwidth budget |
| `SEC-` | Security / TrustZone constraints |

---

## Architecture

```
socc/
├── commands/          CLI command packages (new in 1.1)
│   ├── core.py        Top-level commands: check, fix, rules, diff, …
│   ├── audit_cmds.py  socc audit  — bindings, bom, kernel, amp, …
│   ├── analyze_cmds.py socc analyze — memory, bounds, irq, deps, gc
│   ├── generate_cmds.py socc generate — qemu, headers, diagram, …
│   ├── viz_cmds.py    socc viz    — topology, pinmap, power-seq
│   ├── sim_cmds.py    socc sim    — failure, smoke, shell, live-check, …
│   ├── socdef_cmds.py socc socdef — validate, check, init
│   └── _shared.py     Shared helpers: SoC lists, registry, helpers
├── parser/            DTS → IR model (tokenizer + parser + mapper)
├── model/             Dataclasses: SoC, PowerTree, ClockTree, IRNode
├── rules/             Rule registry + vendor rule packs
│   ├── common/        GIC, GPIO, DMA, MMIO rules
│   └── rockchip/      Rockchip-specific power/clock/bus rules
├── engine/            Rule executor + violation aggregator
├── memmap.py          MMIO sweep-line overlap scanner
├── depgraph.py        Power/clock cycle detector (DFS)
├── smartdiff.py       Semantic DTS/DTB differ
├── gc.py              Zombie-node garbage collector
├── bounds.py          Physical resource bounds auditor
├── irqcheck.py        IRQ collision & routing checker
├── autofix.py         DTS patch generator
├── report.py          HTML report renderer
└── cli.py             Click group assembler (152 lines) + backward aliases
```

The IR model is intentionally decoupled from the parser: you can load a
SoC model from a DTS file, a YAML hardware description, or build one
programmatically for testing.

---

## Contributing

```bash
git clone https://github.com/gahingwoo/SoC-Consistency.git
cd SoC-Consistency
pip install -e ".[dev]"
pytest tests/ -q
```

Rule contributions are welcome.  Each rule is a single Python class
inheriting `BaseRule`; see [docs/development.md](docs/development.md)
for the five-minute guide.

---

## License

MIT — see [LICENSE](LICENSE).
