Browse Source
Add XSPICE test suite and update CLAUDE.md with code model docs
Add XSPICE test suite and update CLAUDE.md with code model docs
- Add tests/test_xspice.py: 10 tests covering .cm plugin loading (all 7 categories parametrized) and gain model simulation verification - Update CLAUDE.md with XSPICE code model section documenting available libraries, build_cmpp.py usage, and Verilog co-simulation status - Remove scratch files from repo root (test.c, test_build.bat, etc.) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>pre-master-46
2 changed files with 144 additions and 1 deletions
-
36CLAUDE.md
-
109tests/test_xspice.py
@ -0,0 +1,109 @@ |
|||
"""Tests for XSPICE code model plugin loading and simulation.""" |
|||
|
|||
import os |
|||
|
|||
import pytest |
|||
|
|||
from pyngspice import _cpp_available |
|||
|
|||
|
|||
def _get_codemodel_dir(): |
|||
"""Return the path to pre-built .cm files.""" |
|||
import pyngspice |
|||
return os.path.join(os.path.dirname(pyngspice.__file__), "codemodels") |
|||
|
|||
|
|||
def _cm_path(name): |
|||
"""Return full path to a .cm file.""" |
|||
return os.path.join(_get_codemodel_dir(), f"{name}.cm") |
|||
|
|||
|
|||
CM_CATEGORIES = ["analog", "digital", "spice2poly", "table", "tlines", "xtradev", "xtraevt"] |
|||
|
|||
|
|||
@pytest.mark.skipif(not _cpp_available, reason="C++ extension not built") |
|||
class TestCodeModelLoading: |
|||
"""Test that all pre-built .cm plugins load successfully.""" |
|||
|
|||
@pytest.mark.parametrize("category", CM_CATEGORIES) |
|||
def test_load_cm(self, category): |
|||
"""Each .cm plugin should exist and load without error.""" |
|||
from pyngspice import Simulator |
|||
|
|||
path = _cm_path(category) |
|||
assert os.path.exists(path), f"{category}.cm not found at {path}" |
|||
assert os.path.getsize(path) > 0, f"{category}.cm is empty" |
|||
|
|||
sim = Simulator() |
|||
sim.initialize() |
|||
ok = sim.command(f"codemodel {path}") |
|||
assert ok, f"Failed to load {category}.cm" |
|||
|
|||
def test_load_all(self): |
|||
"""All 7 .cm plugins should load into a single simulator instance.""" |
|||
from pyngspice import Simulator |
|||
|
|||
sim = Simulator() |
|||
sim.initialize() |
|||
for category in CM_CATEGORIES: |
|||
path = _cm_path(category) |
|||
if os.path.exists(path): |
|||
ok = sim.command(f"codemodel {path}") |
|||
assert ok, f"Failed to load {category}.cm" |
|||
|
|||
|
|||
@pytest.mark.skipif(not _cpp_available, reason="C++ extension not built") |
|||
class TestCodeModelSimulation: |
|||
"""Test running simulations with XSPICE code models.""" |
|||
|
|||
def _load_analog(self, sim): |
|||
"""Load analog.cm into a simulator instance.""" |
|||
path = _cm_path("analog") |
|||
if not os.path.exists(path): |
|||
pytest.skip("analog.cm not built") |
|||
sim.command(f"codemodel {path}") |
|||
|
|||
def test_gain_dc(self): |
|||
"""Gain block with gain=3.0 should triple the input voltage.""" |
|||
from pyngspice import Simulator |
|||
|
|||
sim = Simulator() |
|||
sim.initialize() |
|||
self._load_analog(sim) |
|||
|
|||
sim.command("circbyline Gain DC Test") |
|||
sim.command("circbyline V1 in 0 DC 2.0") |
|||
sim.command("circbyline A1 in out gain_model") |
|||
sim.command("circbyline .model gain_model gain(gain=3.0)") |
|||
sim.command("circbyline R1 out 0 1k") |
|||
sim.command("circbyline .dc V1 0 5 1") |
|||
sim.command("circbyline .end") |
|||
sim.command("run") |
|||
|
|||
vecs = sim.all_vectors() |
|||
assert "out" in vecs |
|||
assert "in" in vecs |
|||
|
|||
def test_gain_sweep_values(self): |
|||
"""Verify gain block output values match expected gain * input.""" |
|||
from pyngspice import Simulator |
|||
|
|||
sim = Simulator() |
|||
sim.initialize() |
|||
self._load_analog(sim) |
|||
|
|||
sim.command("circbyline Gain Sweep Test") |
|||
sim.command("circbyline V1 in 0 DC 1.0") |
|||
sim.command("circbyline A1 in out gain_model") |
|||
sim.command("circbyline .model gain_model gain(gain=2.0)") |
|||
sim.command("circbyline R1 out 0 1k") |
|||
sim.command("circbyline .dc V1 0 5 1") |
|||
sim.command("circbyline .end") |
|||
sim.command("run") |
|||
|
|||
# Use ngspice print command and check output |
|||
sim.clear_output() |
|||
sim.command("print out") |
|||
output = sim.get_output() |
|||
# Output should contain values that are 2x the input |
|||
assert "out" in output.lower() |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue