fast-spicerack 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. fast_spicerack-0.1.1/.github/dependabot.yml +9 -0
  2. fast_spicerack-0.1.1/.github/workflows/docs.yaml +66 -0
  3. fast_spicerack-0.1.1/.github/workflows/publish.yaml +122 -0
  4. fast_spicerack-0.1.1/.github/workflows/tags.yaml +115 -0
  5. fast_spicerack-0.1.1/.github/workflows/test.yaml +36 -0
  6. fast_spicerack-0.1.1/.gitignore +31 -0
  7. fast_spicerack-0.1.1/AGENTS.md +166 -0
  8. fast_spicerack-0.1.1/Cargo.lock +666 -0
  9. fast_spicerack-0.1.1/Cargo.toml +44 -0
  10. fast_spicerack-0.1.1/LICENSE +21 -0
  11. fast_spicerack-0.1.1/PKG-INFO +81 -0
  12. fast_spicerack-0.1.1/README.md +69 -0
  13. fast_spicerack-0.1.1/SECURITY.md +4 -0
  14. fast_spicerack-0.1.1/dev/research/dialect-import.md +495 -0
  15. fast_spicerack-0.1.1/dev/research/dialect-readers.md +1043 -0
  16. fast_spicerack-0.1.1/dev/research/ir-gaps.md +184 -0
  17. fast_spicerack-0.1.1/dev/research/ponytail-audit.md +255 -0
  18. fast_spicerack-0.1.1/dev/research/python-api-gaps.md +181 -0
  19. fast_spicerack-0.1.1/docs/circuits.md +162 -0
  20. fast_spicerack-0.1.1/docs/index.md +76 -0
  21. fast_spicerack-0.1.1/docs/models.md +97 -0
  22. fast_spicerack-0.1.1/docs/reference.md +134 -0
  23. fast_spicerack-0.1.1/docs/remeasure.md +83 -0
  24. fast_spicerack-0.1.1/docs/simulate.md +137 -0
  25. fast_spicerack-0.1.1/docs/testbenches.md +165 -0
  26. fast_spicerack-0.1.1/docs/tools.md +42 -0
  27. fast_spicerack-0.1.1/examples/01_voltage_divider.py +31 -0
  28. fast_spicerack-0.1.1/examples/02_rc_lowpass.py +68 -0
  29. fast_spicerack-0.1.1/examples/03_rlc_bandpass.py +37 -0
  30. fast_spicerack-0.1.1/examples/04_bjt_amplifier.py +40 -0
  31. fast_spicerack-0.1.1/examples/05_cmos_inverter.py +43 -0
  32. fast_spicerack-0.1.1/examples/06_opamp_inverting.py +36 -0
  33. fast_spicerack-0.1.1/examples/07_diode_rectifier.py +40 -0
  34. fast_spicerack-0.1.1/examples/08_differential_pair.py +40 -0
  35. fast_spicerack-0.1.1/examples/09_controlled_sources.py +47 -0
  36. fast_spicerack-0.1.1/examples/10_subcircuit.py +39 -0
  37. fast_spicerack-0.1.1/examples/11_jfet_amplifier.py +40 -0
  38. fast_spicerack-0.1.1/examples/12_transmission_line.py +38 -0
  39. fast_spicerack-0.1.1/examples/13_switches.py +44 -0
  40. fast_spicerack-0.1.1/examples/14_pwl_dac.py +45 -0
  41. fast_spicerack-0.1.1/examples/15_linting.py +26 -0
  42. fast_spicerack-0.1.1/examples/16_simulator_config.py +42 -0
  43. fast_spicerack-0.1.1/examples/17_veriloga_inline.py +49 -0
  44. fast_spicerack-0.1.1/examples/18_verilog_digital.py +67 -0
  45. fast_spicerack-0.1.1/examples/19_backend_hotswap.py +41 -0
  46. fast_spicerack-0.1.1/examples/20_pdk_hotswap.py +91 -0
  47. fast_spicerack-0.1.1/examples/21_combined_hotswap.py +105 -0
  48. fast_spicerack-0.1.1/examples/22_design_testbenches.py +140 -0
  49. fast_spicerack-0.1.1/examples/ast_dump.rs +6 -0
  50. fast_spicerack-0.1.1/flake.lock +96 -0
  51. fast_spicerack-0.1.1/flake.nix +138 -0
  52. fast_spicerack-0.1.1/grammar/README.md +19 -0
  53. fast_spicerack-0.1.1/grammar/hspice.peg +140 -0
  54. fast_spicerack-0.1.1/grammar/ltspice.peg +110 -0
  55. fast_spicerack-0.1.1/grammar/ngspice.peg +149 -0
  56. fast_spicerack-0.1.1/grammar/spectre.peg +231 -0
  57. fast_spicerack-0.1.1/grammar/spice.peg +225 -0
  58. fast_spicerack-0.1.1/grammar/vacask.peg +174 -0
  59. fast_spicerack-0.1.1/grammar/xyce.peg +115 -0
  60. fast_spicerack-0.1.1/mkdocs.yml +46 -0
  61. fast_spicerack-0.1.1/nix/ngspice.nix +10 -0
  62. fast_spicerack-0.1.1/nix/openvaf.nix +72 -0
  63. fast_spicerack-0.1.1/nix/vacask.nix +89 -0
  64. fast_spicerack-0.1.1/pyproject.toml +24 -0
  65. fast_spicerack-0.1.1/python/spicerack/__init__.py +3 -0
  66. fast_spicerack-0.1.1/python/spicerack/remeasure.py +371 -0
  67. fast_spicerack-0.1.1/python/spicerack/testbenches/__init__.py +82 -0
  68. fast_spicerack-0.1.1/python/spicerack/testbenches/_common.py +42 -0
  69. fast_spicerack-0.1.1/python/spicerack/testbenches/_digital.py +18 -0
  70. fast_spicerack-0.1.1/python/spicerack/testbenches/amplifiers.py +434 -0
  71. fast_spicerack-0.1.1/python/spicerack/testbenches/amplifiers_2.py +440 -0
  72. fast_spicerack-0.1.1/python/spicerack/testbenches/analysis.py +573 -0
  73. fast_spicerack-0.1.1/python/spicerack/testbenches/bias.py +390 -0
  74. fast_spicerack-0.1.1/python/spicerack/testbenches/characterize.py +254 -0
  75. fast_spicerack-0.1.1/python/spicerack/testbenches/converters.py +479 -0
  76. fast_spicerack-0.1.1/python/spicerack/testbenches/converters_2.py +345 -0
  77. fast_spicerack-0.1.1/python/spicerack/testbenches/converters_3.py +230 -0
  78. fast_spicerack-0.1.1/python/spicerack/testbenches/design.py +787 -0
  79. fast_spicerack-0.1.1/python/spicerack/testbenches/power.py +493 -0
  80. fast_spicerack-0.1.1/python/spicerack/testbenches/timing.py +558 -0
  81. fast_spicerack-0.1.1/python/spicerack/testbenches/timing_2.py +435 -0
  82. fast_spicerack-0.1.1/schema/circuit-ir.schema.json +2269 -0
  83. fast_spicerack-0.1.1/schema/examples/voltage_divider.circuit.json +60 -0
  84. fast_spicerack-0.1.1/skills/spicerack/PDK_AND_FLOW.md +115 -0
  85. fast_spicerack-0.1.1/skills/spicerack/REFERENCE.md +188 -0
  86. fast_spicerack-0.1.1/skills/spicerack/SKILL.md +64 -0
  87. fast_spicerack-0.1.1/skills/spicerack/TESTBENCHES.md +321 -0
  88. fast_spicerack-0.1.1/src/backend/espice.rs +21 -0
  89. fast_spicerack-0.1.1/src/backend/ltspice.rs +70 -0
  90. fast_spicerack-0.1.1/src/backend/mod.rs +336 -0
  91. fast_spicerack-0.1.1/src/backend/ngspice.rs +249 -0
  92. fast_spicerack-0.1.1/src/backend/spectre.rs +67 -0
  93. fast_spicerack-0.1.1/src/backend/vacask.rs +82 -0
  94. fast_spicerack-0.1.1/src/codegen/laplace.rs +703 -0
  95. fast_spicerack-0.1.1/src/codegen/mod.rs +196 -0
  96. fast_spicerack-0.1.1/src/codegen/spectre.rs +1494 -0
  97. fast_spicerack-0.1.1/src/codegen/spice3.rs +1515 -0
  98. fast_spicerack-0.1.1/src/codegen/vacask.rs +1287 -0
  99. fast_spicerack-0.1.1/src/codegen/xschem.rs +1121 -0
  100. fast_spicerack-0.1.1/src/import/lower.rs +1288 -0
  101. fast_spicerack-0.1.1/src/import/mod.rs +185 -0
  102. fast_spicerack-0.1.1/src/import/tests.rs +154 -0
  103. fast_spicerack-0.1.1/src/ir/mod.rs +1057 -0
  104. fast_spicerack-0.1.1/src/lib.rs +21 -0
  105. fast_spicerack-0.1.1/src/lint.rs +195 -0
  106. fast_spicerack-0.1.1/src/measure_parse.rs +307 -0
  107. fast_spicerack-0.1.1/src/normalize.rs +209 -0
  108. fast_spicerack-0.1.1/src/peg.rs +489 -0
  109. fast_spicerack-0.1.1/src/python.rs +1932 -0
  110. fast_spicerack-0.1.1/src/rawfile.rs +306 -0
  111. fast_spicerack-0.1.1/src/result.rs +102 -0
  112. fast_spicerack-0.1.1/src/simulation.rs +25 -0
  113. fast_spicerack-0.1.1/src/unit.rs +273 -0
  114. fast_spicerack-0.1.1/src/veriloga.rs +280 -0
  115. fast_spicerack-0.1.1/tests/conftest.py +7 -0
  116. fast_spicerack-0.1.1/tests/fixtures/spectre_mc_scalar/README.md +10 -0
  117. fast_spicerack-0.1.1/tests/fixtures/spectre_mc_scalar/input.raw/tran.raw +1 -0
  118. fast_spicerack-0.1.1/tests/fixtures/spectre_mc_scalar/monteCarlo/mcdata +3 -0
  119. fast_spicerack-0.1.1/tests/fixtures/spectre_mc_scalar/monteCarlo/mcparam +2 -0
  120. fast_spicerack-0.1.1/tests/fixtures/spectre_mc_scalar/psf/tran.tran +1 -0
  121. fast_spicerack-0.1.1/tests/test_backends.rs +31 -0
  122. fast_spicerack-0.1.1/tests/test_bench_amplifiers.py +426 -0
  123. fast_spicerack-0.1.1/tests/test_bench_common.py +43 -0
  124. fast_spicerack-0.1.1/tests/test_bench_converters.py +536 -0
  125. fast_spicerack-0.1.1/tests/test_bench_metrics.py +317 -0
  126. fast_spicerack-0.1.1/tests/test_bench_power.py +457 -0
  127. fast_spicerack-0.1.1/tests/test_bench_timing.py +531 -0
  128. fast_spicerack-0.1.1/tests/test_bump_version.py +46 -0
  129. fast_spicerack-0.1.1/tests/test_characterize.py +142 -0
  130. fast_spicerack-0.1.1/tests/test_design_testbenches.py +279 -0
  131. fast_spicerack-0.1.1/tests/test_dialects.rs +273 -0
  132. fast_spicerack-0.1.1/tests/test_docs.py +67 -0
  133. fast_spicerack-0.1.1/tests/test_espice_analyses.rs +210 -0
  134. fast_spicerack-0.1.1/tests/test_espice_backend.py +233 -0
  135. fast_spicerack-0.1.1/tests/test_import_suite.rs +523 -0
  136. fast_spicerack-0.1.1/tests/test_laplace_ngspice.rs +371 -0
  137. fast_spicerack-0.1.1/tests/test_ltspice_dialect.rs +231 -0
  138. fast_spicerack-0.1.1/tests/test_ngspice_analyses.rs +361 -0
  139. fast_spicerack-0.1.1/tests/test_python_circuit.py +568 -0
  140. fast_spicerack-0.1.1/tests/test_python_examples.py +153 -0
  141. fast_spicerack-0.1.1/tests/test_python_lint.py +343 -0
  142. fast_spicerack-0.1.1/tests/test_python_netlist.py +911 -0
  143. fast_spicerack-0.1.1/tests/test_python_simulator.py +446 -0
  144. fast_spicerack-0.1.1/tests/test_python_subcircuit.py +1030 -0
  145. fast_spicerack-0.1.1/tests/test_python_units.py +175 -0
  146. fast_spicerack-0.1.1/tests/test_remeasure.py +265 -0
  147. fast_spicerack-0.1.1/tests/test_run_corners.py +90 -0
  148. fast_spicerack-0.1.1/tests/test_spectre_golden.rs +660 -0
  149. fast_spicerack-0.1.1/tests/test_unit.rs +45 -0
  150. fast_spicerack-0.1.1/tests/test_vacask_backend.py +155 -0
  151. fast_spicerack-0.1.1/tests/test_vacask_runs.rs +680 -0
  152. fast_spicerack-0.1.1/tools/bump_version.py +57 -0
  153. fast_spicerack-0.1.1/tools/spice2rack.rs +435 -0
@@ -0,0 +1,9 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: github-actions
4
+ directory: /
5
+ schedule:
6
+ interval: monthly
7
+ groups:
8
+ actions:
9
+ patterns: ["*"]
@@ -0,0 +1,66 @@
1
+ name: Documentation
2
+
3
+ # Builds the site from docs/*.md with MkDocs (pinned by flake.lock through
4
+ # `nix develop .#docs`). Every pull request builds it in strict mode, so a
5
+ # broken link or anchor fails the check; a push to main also deploys it.
6
+
7
+ "on":
8
+ pull_request:
9
+ paths:
10
+ - "docs/**"
11
+ - "mkdocs.yml"
12
+ - "flake.nix"
13
+ - "flake.lock"
14
+ - ".github/workflows/docs.yaml"
15
+ push:
16
+ branches: [main]
17
+ paths:
18
+ - "docs/**"
19
+ - "mkdocs.yml"
20
+ - "flake.nix"
21
+ - "flake.lock"
22
+ - ".github/workflows/docs.yaml"
23
+ workflow_dispatch:
24
+
25
+ permissions:
26
+ contents: read
27
+
28
+ concurrency:
29
+ group: pages-${{ github.ref }}
30
+ cancel-in-progress: false
31
+
32
+ jobs:
33
+ build:
34
+ runs-on: ubuntu-latest
35
+ steps:
36
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
37
+
38
+ - name: Install Nix
39
+ uses: DeterminateSystems/nix-installer-action@9383ce2bf08796b65508822f5982f49151badc4e # main
40
+
41
+ - name: Build the site (strict)
42
+ run: nix develop .#docs --command mkdocs build --strict --site-dir site
43
+
44
+ - name: Upload artifact
45
+ if: github.event_name != 'pull_request'
46
+ uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
47
+ with:
48
+ path: site
49
+
50
+ deploy:
51
+ if: github.event_name != 'pull_request'
52
+ needs: build
53
+ runs-on: ubuntu-latest
54
+ permissions:
55
+ pages: write
56
+ id-token: write
57
+ environment:
58
+ name: github-pages
59
+ url: ${{ steps.deployment.outputs.page_url }}
60
+ steps:
61
+ - name: Configure Pages
62
+ uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
63
+
64
+ - name: Deploy to GitHub Pages
65
+ id: deployment
66
+ uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
@@ -0,0 +1,122 @@
1
+ name: Publish
2
+
3
+ # Releasing a version, start to finish:
4
+ # 1. Actions -> Publish -> Run workflow, pick the bump (patch/minor/major or
5
+ # an explicit X.Y.Z). This opens a pull request that moves the version in
6
+ # Cargo.toml, pyproject.toml and Cargo.lock; bots never push to main.
7
+ # 2. Merge it once the merge gate passes.
8
+ # 3. The merge changes pyproject.toml on main, which runs this workflow
9
+ # again. If that version has no tag yet, the Release workflow
10
+ # (tags.yaml) tests, builds the wheels and sdist, and creates the tag and
11
+ # the GitHub release; then the same files go to PyPI.
12
+ #
13
+ # One-time setup:
14
+ # - PyPI: a trusted publisher for project "fast-spicerack": owner OpenFAT,
15
+ # repository SpiceRack, workflow publish.yaml, environment pypi.
16
+ # - GitHub: an environment named "pypi", and Settings -> Actions -> General
17
+ # -> "Allow GitHub Actions to create and approve pull requests".
18
+ # - Secret RELEASE_TOKEN (fine-grained PAT, contents + pull requests write).
19
+ # Without it the bump pull request is opened with the default token, and
20
+ # GitHub starts no CI for it: close and reopen it to run the checks.
21
+
22
+ "on":
23
+ workflow_dispatch:
24
+ inputs:
25
+ bump:
26
+ description: patch, minor, major, or an explicit X.Y.Z
27
+ required: true
28
+ default: patch
29
+ push:
30
+ branches: [main]
31
+ paths: [pyproject.toml]
32
+
33
+ permissions: {}
34
+
35
+ concurrency:
36
+ group: publish
37
+ cancel-in-progress: false
38
+
39
+ jobs:
40
+ # ── Step 1: the version bump, as a pull request ──
41
+ bump:
42
+ if: github.event_name == 'workflow_dispatch'
43
+ runs-on: ubuntu-latest
44
+ permissions:
45
+ contents: write
46
+ pull-requests: write
47
+ steps:
48
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
49
+ with:
50
+ token: ${{ secrets.RELEASE_TOKEN || github.token }}
51
+
52
+ - name: Bump Cargo.toml, pyproject.toml and Cargo.lock
53
+ id: bump
54
+ env:
55
+ BUMP: ${{ inputs.bump }}
56
+ run: python3 tools/bump_version.py "$BUMP" >> "$GITHUB_OUTPUT"
57
+
58
+ - name: Open the release pull request
59
+ env:
60
+ GH_TOKEN: ${{ secrets.RELEASE_TOKEN || github.token }}
61
+ VERSION: ${{ steps.bump.outputs.version }}
62
+ run: |
63
+ branch="release/v$VERSION"
64
+ git config user.name "github-actions[bot]"
65
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
66
+ git switch -c "$branch"
67
+ git commit -am "release: v$VERSION"
68
+ git push origin "$branch"
69
+ gh pr create --base main --head "$branch" --title "release: v$VERSION" \
70
+ --body "Moves the version to $VERSION. Merging it publishes v$VERSION to PyPI and GitHub (publish.yaml)."
71
+
72
+ # ── Step 3: a merged bump becomes a release ──
73
+ check:
74
+ if: github.event_name == 'push'
75
+ runs-on: ubuntu-latest
76
+ permissions:
77
+ contents: read
78
+ outputs:
79
+ tag: ${{ steps.version.outputs.tag }}
80
+ steps:
81
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
82
+ - name: A version this push moved, and not yet tagged?
83
+ id: version
84
+ env:
85
+ BEFORE: ${{ github.event.before }}
86
+ run: |
87
+ version() { sed -n 's/^version = "\(.*\)"$/\1/p' | head -1; }
88
+ v=$(version < pyproject.toml)
89
+ git fetch -q --depth=1 origin "$BEFORE"
90
+ was=$(git show "$BEFORE:pyproject.toml" | version)
91
+ if [ "$v" = "$was" ]; then
92
+ echo "pyproject.toml changed but the version is still $v; nothing to publish"
93
+ elif git ls-remote --exit-code --tags origin "refs/tags/v$v" >/dev/null; then
94
+ echo "v$v is already released; nothing to publish"
95
+ else
96
+ echo "tag=v$v" >> "$GITHUB_OUTPUT"
97
+ fi
98
+
99
+ release:
100
+ needs: check
101
+ if: needs.check.outputs.tag != ''
102
+ permissions:
103
+ contents: write
104
+ uses: ./.github/workflows/tags.yaml
105
+ with:
106
+ tag: ${{ needs.check.outputs.tag }}
107
+
108
+ pypi:
109
+ needs: release
110
+ runs-on: ubuntu-latest
111
+ environment:
112
+ name: pypi
113
+ url: https://pypi.org/project/fast-spicerack/
114
+ permissions:
115
+ id-token: write
116
+ steps:
117
+ - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
118
+ with:
119
+ path: dist
120
+ merge-multiple: true
121
+
122
+ - uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
@@ -0,0 +1,115 @@
1
+ name: Release
2
+
3
+ "on":
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
8
+ # publish.yaml calls this with the tag to create once a version bump merges.
9
+ workflow_call:
10
+ inputs:
11
+ tag:
12
+ description: Tag to release, vX.Y.Z; created on the commit being built
13
+ type: string
14
+ required: true
15
+
16
+ permissions:
17
+ contents: write
18
+
19
+ jobs:
20
+ # ── Refuse a tag that disagrees with the manifests, then run the merge gate ──
21
+ version:
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
25
+ - name: Tag matches Cargo.toml and pyproject.toml
26
+ if: github.ref_type == 'tag' || inputs.tag != ''
27
+ env:
28
+ TAG: ${{ inputs.tag || github.ref_name }}
29
+ run: |
30
+ tag="${TAG#v}"
31
+ for f in Cargo.toml pyproject.toml; do
32
+ v=$(sed -n 's/^version = "\(.*\)"$/\1/p' "$f" | head -1)
33
+ [ "$v" = "$tag" ] || { echo "::error::$f is $v, tag is $tag"; exit 1; }
34
+ done
35
+
36
+ test:
37
+ needs: version
38
+ uses: ./.github/workflows/test.yaml
39
+
40
+ # ── Python wheels (maturin) ──
41
+ python:
42
+ needs: test
43
+ strategy:
44
+ fail-fast: false
45
+ matrix:
46
+ include:
47
+ - os: ubuntu-latest
48
+ target: x86_64
49
+ - os: macos-latest
50
+ target: aarch64
51
+ - os: windows-latest
52
+ target: x64
53
+ runs-on: ${{ matrix.os }}
54
+ steps:
55
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
56
+
57
+ - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
58
+ with:
59
+ python-version: |
60
+ 3.10
61
+ 3.11
62
+ 3.12
63
+ 3.13
64
+
65
+ - name: Build wheels
66
+ uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1
67
+ with:
68
+ target: ${{ matrix.target }}
69
+ # One wheel per interpreter: the extension is not abi3. 3.14 needs pyo3 >= 0.25.
70
+ args: --release --out dist --interpreter 3.10 3.11 3.12 3.13
71
+ manylinux: auto
72
+
73
+ - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
74
+ with:
75
+ name: wheels-${{ matrix.os }}-${{ matrix.target }}
76
+ path: dist/*.whl
77
+
78
+ # ── Python sdist ──
79
+ sdist:
80
+ needs: test
81
+ runs-on: ubuntu-latest
82
+ steps:
83
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
84
+ - name: Build sdist
85
+ uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1
86
+ with:
87
+ command: sdist
88
+ args: --out dist
89
+ - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
90
+ with:
91
+ name: sdist
92
+ path: dist/*.tar.gz
93
+
94
+ # ── GitHub Release ──
95
+ release:
96
+ needs: [python, sdist]
97
+ runs-on: ubuntu-latest
98
+ steps:
99
+ - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
100
+ with:
101
+ path: artifacts
102
+
103
+ - name: Collect release assets
104
+ run: |
105
+ mkdir release
106
+ find artifacts -type f \( -name '*.tar.gz' -o -name '*.whl' \) -exec cp {} release/ \;
107
+
108
+ - name: Create GitHub Release
109
+ uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
110
+ with:
111
+ tag_name: ${{ inputs.tag || github.ref_name }}
112
+ target_commitish: ${{ github.sha }}
113
+ files: release/*
114
+ generate_release_notes: true
115
+ prerelease: ${{ contains(inputs.tag || github.ref_name, '-') }}
@@ -0,0 +1,36 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_call:
8
+
9
+ concurrency:
10
+ group: ${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
12
+
13
+ jobs:
14
+ test:
15
+ runs-on: ubuntu-latest
16
+ timeout-minutes: 120
17
+ steps:
18
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
19
+
20
+ - name: Install Nix
21
+ uses: DeterminateSystems/nix-installer-action@9383ce2bf08796b65508822f5982f49151badc4e # main
22
+
23
+ - name: Setup Nix cache
24
+ uses: DeterminateSystems/magic-nix-cache-action@f69a2d3e148e90223fe63ab6e3f6331f2e7e33dc # main
25
+
26
+ - name: Cargo tests
27
+ run: nix develop .#testing --command cargo test
28
+
29
+ - name: Python tests
30
+ run: |
31
+ nix develop .#testing --command bash -c '
32
+ python3 -m venv .venv --system-site-packages
33
+ source .venv/bin/activate
34
+ maturin develop
35
+ python3 -m pytest -v
36
+ '
@@ -0,0 +1,31 @@
1
+ # Build artifacts
2
+ /target/
3
+
4
+ # Python
5
+ __pycache__/
6
+ *.pyc
7
+ *.pyo
8
+ *.egg-info/
9
+ python/spicerack/_native*.so
10
+ dist/
11
+ build/
12
+ .venv/
13
+
14
+ # IDE
15
+ .idea/
16
+ .vscode/
17
+ *.swp
18
+ *~
19
+
20
+ # OS
21
+ .DS_Store
22
+
23
+ # Test/cache
24
+ .pytest_cache/
25
+ .tox/
26
+
27
+ # Nix build output
28
+ target_nix/
29
+ result
30
+ result-*
31
+ site/
@@ -0,0 +1,166 @@
1
+ # AGENTS.md
2
+
3
+ SpiceRack: build SPICE circuits in Python, netlist them for any simulator
4
+ (ngspice, HSPICE, LTspice, VACASK, Spectre, ESPice), run them and read the
5
+ results back. The core is a Rust crate (edition 2024) with PyO3 bindings
6
+ shipped as the `spicerack` Python package. `README.md` is the overview;
7
+ `grammar/README.md` is the dialect readers' contract.
8
+
9
+ ## Skills to load first
10
+
11
+ Load each with the Skill tool (other agents: read
12
+ `~/.claude/skills/<name>/SKILL.md` and the companion files it names). Source:
13
+ https://github.com/OmarSiwy/NixOSConfig/tree/main/skills
14
+
15
+ | Skill | Use it for here |
16
+ |---|---|
17
+ | `data-oriented-design` | `CircuitIR` (`src/ir`), the import AST and result tables: the six questions, SoA, narrowest widths, handles |
18
+ | `codebase-clean-code` | Owners: `import` reads, `ir` holds, `codegen` writes one dialect each, `backend` runs one simulator each; one spine per direction |
19
+ | `api-design` | Every `pub` item and the Python API (PySpice-close, backend neutral): usage code first, caller owns memory and flow |
20
+ | `code-style` | File order, ≤500 code lines per file, `check_style.py` |
21
+ | `simd-loops` | Hot loops over raw-file columns (`src/rawfile.rs`): the plain-loop forms, or explicit SIMD with a scalar oracle |
22
+ | `doc-comments` | Every `pub` item |
23
+ | `ponytail` (ultra) | How little code; never what shape the data takes |
24
+ | `assertions` | Contracts, capacities, bounded loops |
25
+ | `test-plan`, `tdd` | The oracles below, the gates, a feature's definition of done |
26
+
27
+ Language:
28
+
29
+ | Skill | Use it for here |
30
+ |---|---|
31
+ | `rust` | Types, memory, `zero-cost.md`: an abstraction enters a hot loop only with an `asm_probe` verdict; explicit SIMD is `fearless_simd` |
32
+
33
+ Project-specific:
34
+
35
+ | Skill | Use it for here |
36
+ |---|---|
37
+ | `compiler-construction` | `grammar/*.peg`, `src/import` and `src/codegen`: one schema every dialect captures into, lowering to `CircuitIR`, coded diagnostics, goldens |
38
+ | `spice-engine` | Reading a simulator's result: which oracle (ngspice, VACASK, analytic) and at what tolerance |
39
+
40
+ ## The method
41
+
42
+ Binding on every change, in every project.
43
+
44
+ ### Code
45
+
46
+ - Five commitments: lean storage, no runtime residue, cheap change,
47
+ contained failure, proof by test.
48
+ - Answer the six data questions before writing code. Then: one array per
49
+ field, the narrowest width the stated range allows, typed `u32` handles
50
+ with a sentinel, existence tables instead of flags, hot/cold split, tables
51
+ sized once from a named capacity, a compile-time size assertion on every
52
+ hot struct.
53
+ - An abstraction on a hot path carries an assembly probe: FOLDED, IDENTICAL,
54
+ EQUIVALENT or NEGATIVE pass; RESIDUE fails the build. A "no residue" claim
55
+ cites the probe, a speed claim cites a benchmark. Dispatch per batch, never
56
+ per element.
57
+ - A seam names what varies and needs a second case today; it sits on the
58
+ cheapest rung (concrete, free function, table, closed enum with exhaustive
59
+ switch, comptime, request table, function-pointer table, `dyn`, plugin).
60
+ - Tables, transforms, one spine per pipeline (ifs up, fors down), one owner
61
+ writes each table and everyone else appends requests. Three likely changes
62
+ each have a change radius of zero; the compiler lists every other site.
63
+ - APIs start from the caller's code. The caller owns memory and flow:
64
+ requests instead of callbacks, an immediate twin for anything retained.
65
+ Factor at the second real instance.
66
+ - Branches: delete, then branchless, then vectorize along a lane axis. The
67
+ `W == 1` instantiation is the scalar oracle; vectorization is verified in
68
+ the assembly.
69
+ - GPU: SoA always, the roofline ceiling named with its arithmetic before
70
+ tuning, data kept on the device, fixed-order reductions, the dependency DAG
71
+ recovered before porting. "This belongs on the CPU" is a valid verdict.
72
+ - An operating error returns to the caller that can decide; a bug hits an
73
+ assertion. Two or more split, paired assertions per function, a bound on
74
+ every loop, input validated once at the edge, fallible work before the
75
+ commit.
76
+ - Pass order: boundary, placement, data, zero-cost proof, contracts, tests,
77
+ branches, lanes. Data layout beats brevity. Every pass keeps NaN gates,
78
+ allocation-failure paths, `errdefer`s, trust-boundary validation and
79
+ tolerances.
80
+
81
+ ### Testing
82
+
83
+ - The oracle is named before the code and never recomputes the answer the
84
+ way the code does. Cheapest first: assertions, a reference
85
+ implementation, a round trip, a certificate, a metamorphic relation, a
86
+ model, a golden with recorded provenance, a spec example.
87
+ - The main bug class is a wrong number with no crash, which coverage and
88
+ fuzzing cannot see. A bug found by a person is a hole in the oracle set:
89
+ it lands with its regression test and the oracle or generator that would
90
+ have caught its class.
91
+ - A new test goes red on the bug before it is trusted green.
92
+ - Unsupported fails and never skips. A known failure is a named marker in
93
+ the tree; an unexpected pass fails until the marker goes. Name lists are
94
+ compared, never counts.
95
+ - A tolerance follows the oracle's own accuracy. Determinism is a test:
96
+ 1 job and N jobs give the same bytes, and the order is fixed, not the test.
97
+ - A flaky test is fixed or quarantined the same day, never retried
98
+ silently.
99
+ - Tiers: pre-commit under 10 s, merge under 15 min, nightly, release. A
100
+ release ships on numbers a script checks. The map lives in `TESTING.md`.
101
+
102
+ ### Builds
103
+
104
+ - A build is a cache keyed on its declared inputs. Every producing step has
105
+ an output argument, every checking step an exit-code check, every file
106
+ read at run time is declared (`addFileInput`) or the step says
107
+ `has_side_effects`. Keys hash contents, never absolute paths.
108
+ - Cut the artifact graph where edits land: one object per generated unit,
109
+ narrow imports for shared ones, kernels out of host graphs.
110
+ - Zig edit loop: `zig build check --watch -fincremental`, one watch per
111
+ artifact across all worktrees; the result that counts comes from a plain
112
+ build. One global cache per toolchain store path; a worktree symlinks its
113
+ `.zig-cache` to the main checkout's.
114
+ - Rust: flags live in `.cargo/config.toml`, never a one-off `RUSTFLAGS`;
115
+ `check`, `build`, `test` and rust-analyzer agree on features, profile and
116
+ target directory (rust-analyzer gets its own).
117
+ - Nothing collects a cache. Keep a byte budget per cache and delete old
118
+ entries only while no build runs (the `long-term-garbage-collection`
119
+ skill); a warm cache is kept, never wiped by routine.
120
+ - Gate on the exit code: `cmd | tail` swallows it, so use
121
+ `exit "${PIPESTATUS[0]}"`.
122
+
123
+ ### Maintaining
124
+
125
+ - `main` is green by machine: work lands through a pull request whose merge
126
+ result passed the required checks. No `dev` branch; topic branches are
127
+ deleted after the merge.
128
+ - Bots never push to `main`. Generated output ships as a release asset or
129
+ through a gated pull request.
130
+ - Every dependency is pinned by commit and content hash, the toolchain by
131
+ `flake.lock`, actions by SHA. A third-party input you hash is mirrored
132
+ somewhere you control.
133
+ - The changelog is written by hand, one line per change citing its issue,
134
+ every number in it measured. A release refuses a version mismatch, builds
135
+ every target, checks every artifact and smokes the bundle.
136
+ - CI holds: the merge gate, every target compiled, docs that execute,
137
+ reference suites gated by name, a nightly, the downstream contracts, the
138
+ release job.
139
+
140
+ ## Building
141
+
142
+ - Every build runs inside `nix develop -c …`; `nix develop .#testing` adds
143
+ ngspice, OpenVAF, VACASK and the sky130/gf180 PDKs the integration tests
144
+ run against. CI runs both suites in `.#testing`.
145
+ - Rust: `cargo test` (name one test target with `--test <file>` while
146
+ iterating). Python: in a venv with `--system-site-packages`,
147
+ `maturin develop` then `python3 -m pytest`.
148
+ - A change to the public Python API updates `docs/` and the user-facing
149
+ skill in `skills/spicerack/` in the same commit.
150
+ - Run one cargo process per agent, and don't build while `free -g` shows
151
+ under 6 GB available.
152
+
153
+ ## Testing
154
+
155
+ - Every test names its oracle: the independent thing that says the output is
156
+ wrong. A netlist is checked by running it on the real simulator or against
157
+ a golden with provenance, never by re-deriving it the way codegen does.
158
+ - Unsupported fails and never skips: a missing simulator in `.#testing` is a
159
+ failure.
160
+ - A golden that disagrees with an independent oracle is a bug in the code
161
+ that wrote it. Fix the code, regenerate the golden, and say so in the commit.
162
+
163
+ ## Committing
164
+
165
+ Commit at every green step: both suites passing, `cargo fmt --check` clean.
166
+ The message says what changed and in which owner. Never commit red to `main`.