Skip to content

Commit e5f87dd

Browse files
feat: add explicit PSpice and LTspice expression dialects
- preserve SPICE3f5 caret exponentiation by default - add PSpice mode with caret Boolean XOR semantics - add LTspice unary ~ and xor(a,b) support - propagate dialect settings through expression and Laplace parsing - add unit, integration, and LTspice-backed golden coverage - fix LTspice ASCII raw parsing and equivalent reference circuits - document operator behavior and nonlinear passive scaling
1 parent ce5b9bb commit e5f87dd

38 files changed

Lines changed: 773 additions & 211 deletions

‎README.md‎

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,20 +109,41 @@ Using SpiceSharpParser involves three steps:
109109
| Behavioral | B (arbitrary behavioral source with V= or I= expressions) |
110110
| Switches | S (voltage-controlled), W (current-controlled) |
111111

112-
### LTspice Compatibility
112+
### Dialect Compatibility
113113

114-
LTspice-specific behavior is opt-in so the default parser and reader behavior stays dialect-neutral:
114+
Dialect-specific behavior is opt-in. Without it, expressions retain the
115+
SPICE3f5-compatible default operator rules:
115116

116117
```csharp
118+
var compatibility = CompatibilityOptions.None; // SPICE3f5-compatible default
119+
// var compatibility = CompatibilityOptions.PSpice;
120+
// var compatibility = CompatibilityOptions.LTspice;
121+
117122
var parser = new SpiceNetlistParser();
118-
parser.Settings.Compatibility = CompatibilityOptions.LTspice;
123+
parser.Settings.Compatibility = compatibility;
119124
var parseResult = parser.ParseNetlist(netlist);
120125

121126
var reader = new SpiceSharpReader();
122-
reader.Settings.Compatibility = CompatibilityOptions.LTspice;
127+
reader.Settings.Compatibility = compatibility;
123128
var model = reader.Read(parseResult.FinalModel);
124129
```
125130

131+
Use the same preset for the parser and reader. Select
132+
`CompatibilityOptions.PSpice` when caret means boolean XOR, or
133+
`CompatibilityOptions.LTspice` for the supported LTspice-specific syntax.
134+
135+
Expression operators are dialect-aware:
136+
137+
| Mode | Boolean NOT | Boolean XOR | Exponentiation |
138+
|------|-------------|-------------|----------------|
139+
| Default / SPICE3f5 | `!` | — | `**` or `^` |
140+
| PSpice compatibility | `!` | `^` | `**` |
141+
| LTspice compatibility | `!` or `~` | `xor(a,b)` | `**` or `^` |
142+
143+
For PSpice expressions, boolean operators bind in the order `&`, then `^`, then
144+
`|`. In default and LTspice modes, caret remains an exponent operator. LTspice
145+
function-style `xor(a,b)` requires exactly two arguments.
146+
126147
LTspice mode covers syntax such as:
127148

128149
- `.backanno` and selected output/viewer options as warning no-ops
@@ -163,7 +184,9 @@ For nonlinear passives, `Q=` describes stored charge as a function of capacitor
163184
terminal voltage, and `Flux=` describes stored flux linkage as a function of inductor
164185
branch current. The local slopes `dQ/dV` and `dFlux/dI` are used for AC small-signal
165186
behavior and transient companion models. `IC=`, `M=`, and `N=` are supported for these
166-
custom passive forms.
187+
custom passive forms. LTspice natively supports `M` on capacitors and inductors but
188+
not `N`; nonlinear-passive `N` is a parser extension that models explicit series
189+
cells. The LTspice-backed goldens compare it with equivalent native LTspice circuits.
167190

168191
See [LTspice-Style Ideal Diode](src/docs/articles/ideal-diode.md) for syntax, scaling rules, current-law details, and the optional LTspice-backed golden tests for DC, AC, and transient parity.
169192

‎roadmap/laplace-pspice-feasibility.md‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ Coefficient order is ascending powers of `s`:
125125
```text
126126
1 + tau*s -> [1, tau]
127127
s + wc -> [wc, 1]
128-
s^2 + a*s + b -> [b, a, 1]
128+
s**2 + a*s + b -> [b, a, 1]
129129
```
130130

131131
For:
@@ -332,7 +332,7 @@ A + B -> (An*Bd + Bn*Ad) / (Ad*Bd)
332332
A - B -> (An*Bd - Bn*Ad) / (Ad*Bd)
333333
A * B -> (An*Bn) / (Ad*Bd)
334334
A / B -> (An*Bd) / (Ad*Bn)
335-
A ^ n -> (An^n) / (Ad^n), where n is a non-negative integer
335+
A ** n -> (An**n) / (Ad**n), where n is a non-negative integer
336336
-A -> (-An) / Ad
337337
```
338338

@@ -358,7 +358,7 @@ Do not perform polynomial GCD simplification in v1. It adds complexity and is no
358358
- Reject hidden symbolic parameter expansion such as `.PARAM pole={s+1000}`.
359359
- Reject improper transfers (`deg N > deg D`) in the MVP.
360360
- Reject singular DC gain (`D(0) == 0`) unless a focused spike proves the runtime handles the target scenario safely.
361-
- Preserve interior zeros: `s^2 + 1` is `[1, 0, 1]`, not `[1, 1]`.
361+
- Preserve interior zeros: `s**2 + 1` is `[1, 0, 1]`, not `[1, 1]`.
362362
- Trim only leading near-zero high-order coefficients.
363363

364364
Suggested tolerances:
@@ -766,7 +766,7 @@ Place near [src/SpiceSharpParser.Tests/Parsers](../src/SpiceSharpParser.Tests/Pa
766766
- Rational add, subtract, multiply, divide, power.
767767
- Zero denominator rejection.
768768
- Coefficients for all worked examples.
769-
- Rejection of `s^0.5`, `s^-1`, `sin(s)`, `exp(s)`, `V(x)*s`, stochastic functions, and hidden symbolic parameters.
769+
- Rejection of `s**0.5`, `s**-1`, `sin(s)`, `exp(s)`, `V(x)*s`, stochastic functions, and hidden symbolic parameters.
770770

771771
### Source Parser Tests
772772

@@ -1053,7 +1053,7 @@ E1 out 0 LAPLACE
10531053
E2 out 0 LAPLACE {V(in)}
10541054
E3 out 0 LAPLACE {V(in)} = {}
10551055
E4 out 0 LAPLACE {V(in)} = {sin(s)}
1056-
E5 out 0 LAPLACE {V(in)} = {s^0.5}
1056+
E5 out 0 LAPLACE {V(in)} = {s**0.5}
10571057
E6 out 0 LAPLACE {V(in)} = {1 / 0}
10581058
E7 out 0 LAPLACE {V(a)-V(b)} = {1/(1+s)}
10591059
```

‎roadmap/ltspice-compatibility-matrix.md‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
---
22
title: LTspice Compatibility Matrix
3-
status: P3 Baseline + .FOUR Support Refresh + Custom Passives + Ideal Diodes + Golden Evidence + Include/Lib Path Evidence + Waveform Docs Refresh + PWL Text Variants + PWL Repeat Variants + Finite SINE + Source/R-C/L Parasitics
3+
status: P3 Baseline + .FOUR Support Refresh + Custom Passives + Ideal Diodes + Golden Evidence + Include/Lib Path Evidence + Waveform Docs Refresh + PWL Text Variants + PWL Repeat Variants + Finite SINE + Boolean Aliases + Source/R-C/L Parasitics
44
scope: SpiceSharpParser + SpiceSharp
5-
last_reviewed: 2026-07-07
5+
last_reviewed: 2026-07-10
66
---
77

88
# LTspice Compatibility Matrix
@@ -52,9 +52,10 @@ Compatibility classes:
5252
| `.options cshunt=<value>` and LTspice solver-behavior options | Accepted | Rejected in LTspice mode | Not runnable | None | Targeted LTspice option error names option | Current parser/runtime | P1 behavior-changing list: `cshunt`, `gshunt`, `srcsteps`, `gminsteps`, `trtol`, `chgtol`, `pivrel`, `pivtol`, `ptrantau`. |
5353
| Scalar aliases `arccos`, `arcsin`, `arctan`, `fabs`, `sgn`, `round`, `pwr`, `pwrs`, `hypot` | Accepted | Resolved through SpiceSharpBehavioral/defaults or parser shims | OP supported | Analytic fixture | None expected | Current parser/runtime | P2 adds `fabs` and one-argument `round` shims; other listed functions are fixture-backed existing runtime support. |
5454
| Scalar `table(...)` / `tbl(...)` in expressions | Accepted | Runnable in expression and LTspice fixtures | OP supported | Analytic fixture | None expected | Current parser/runtime | Runtime support comes from SpiceSharpBehavioral defaults; `MathFunctions.CreateTable()` now returns a parser-owned interpolation helper for direct factory callers. |
55-
| Expression `**`, single/double `&` and `|`, unary `!` | Accepted | Parsed as power, boolean AND/OR, and NOT | OP/unit supported | Analytic fixture | None expected | Current parser/runtime | `^` remains existing exponent syntax; LTspice boolean XOR is deferred. |
55+
| Expression `**`, single/double `&` and `|`, unary `!` | Accepted | Parsed as power, boolean AND/OR, and NOT | OP/unit supported | Analytic fixture | None expected | Current parser/runtime | `**` is the dialect-neutral exponent syntax. Default/SPICE3f5 and LTspice modes also accept `^` for exponentiation. |
56+
| PSpice-mode boolean `^` | Accepted with `CompatibilityOptions.PSpice` | Lowered to a boolean XOR AST node | OP/unit supported | Four-row truth-table integration fixture plus parser precedence fixtures | None expected | Current parser/runtime | PSpice precedence is `&`, then `^`, then `|`; default/SPICE3f5 and LTspice modes interpret `^` as exponentiation. |
57+
| Unary `~` and `xor(a,b)` | Accepted in LTspice mode | Lowered to boolean NOT and two-argument boolean XOR AST nodes | OP supported | Analytic integration fixture plus optional LTspice-backed OP golden | Wrong `xor` arity produces a targeted parser error | Current parser/runtime | Function-style XOR avoids ambiguity with the LTspice-mode `^` exponent interpretation. |
5658
| `uplim(...)` / `dnlim(...)` | Accepted | Resolved as LTspice-style smooth one-sided limit functions | OP supported | Analytic fixture plus optional LTspice-backed OP golden | None expected | Current parser/runtime | Smooth upper/lower limiting uses the third argument as the transition zone. |
57-
| Unary `~` | Accepted in expression text | Rejected in LTspice mode | Not runnable | None | Targeted LTspice expression diagnostic names `~` | Current parser/runtime | Unary inversion semantics are not mapped yet. |
5859
| `EXP(...)` source waveform | Accepted | Produces internal exponential waveform | TRAN supported | Analytic fixture plus optional LTspice-backed transient golden | Invalid count/tau diagnostics name `EXP` | Current parser/runtime | P2 supports the six-argument form `EXP(v1 v2 td1 tau1 td2 tau2)`. |
5960
| `PULSE(... Ncycles)` | Accepted in LTspice mode | Produces finite-cycle pulse waveform | TRAN supported | Analytic transient fixture plus optional LTspice-backed transient golden | Invalid period or cycle count produces targeted `PULSE` diagnostic | Current parser/runtime | The eighth LTspice argument limits the waveform to `Ncycles` periods, then returns to the initial value. |
6061
| `SINE(... Ncycles)` | Accepted in LTspice mode | Produces finite-cycle sine waveform | TRAN supported | Analytic transient fixture plus optional LTspice-backed transient golden | Invalid frequency or cycle count produces targeted `SINE` diagnostic | Current parser/runtime | The seventh LTspice argument limits the waveform to `Ncycles` periods after the delay, then returns to the offset value. |
@@ -65,10 +66,10 @@ Compatibility classes:
6566
| Source `Rser`, `Cpar`, `load`, `R=<value>` | Accepted | Synthesizes helper R/C entities in LTspice mode | OP supported for resistance helpers; Cpar read fixture | Analytic/parser fixture plus optional LTspice-backed OP golden | Malformed value forms produce targeted LTspice source-option diagnostics | Current parser/runtime | Parser-only topology synthesis: `Rser` adds a series resistor, `Cpar` adds a shunt capacitor, `load` adds a shunt resistor, and `R=<value>` maps to series resistance on voltage sources and load resistance on current sources. Core source models are unchanged. |
6667
| R/C model `tc=a[,b]` | Accepted | Lowered to `tc1` / `tc2` | Existing R/C model behavior | Read fixture | None expected in LTspice mode | Current parser/runtime | Parser shim only; coefficients beyond two are rejected. |
6768
| LTspice metadata/rating parameters `mfg`, `manufacturer`, `pn`, `part`, `desc`, `description`, `V`, `Irms`, `Ipk` | Accepted | Warning no-op in LTspice mode | No runtime effect | Diagnostic fixture | Default: existing parameter error. LTspice: warning names parameter. | Current parser/runtime | BOM/layout metadata is not used by SpiceSharpParser. |
68-
| Resistor instance parasitics `Rser`, `Rpar`, `Cpar` | Accepted in LTspice mode | Synthesizes helper R/C entities | OP/TRAN supported | Analytic fixture plus optional LTspice-backed OP golden | None expected for supported forms | Current parser/runtime | Parser-only topology synthesis: `Rser` adds a series resistor through an internal node; `Rpar` and `Cpar` add shunts across the resistor terminals. Core resistor model is unchanged. |
69+
| Resistor instance parasitics `Rser`, `Rpar`, `Cpar` | Accepted in LTspice mode | Synthesizes helper R/C entities | OP/TRAN supported | Analytic fixture plus optional LTspice-backed OP golden against an explicit equivalent topology | None expected for supported forms | Current parser/runtime | Parser-only topology synthesis: `Rser` adds a series resistor through an internal node; `Rpar` and `Cpar` add shunts across the resistor terminals. LTspice rejects these options directly on a resistor line, so the external golden uses the equivalent explicit helper network. Core resistor model is unchanged. |
6970
| Capacitor instance parasitics `Rser`, `Lser`, `Rpar`, `Cpar` | Accepted in LTspice mode | Synthesizes helper R/L/C entities | OP/TRAN supported for R helpers and `Cpar`; `Lser` read fixture | Analytic/parser fixture plus optional LTspice-backed OP golden for `Rpar` | None expected for supported forms | Current parser/runtime | Parser-only topology synthesis: `Rser` and `Lser` add a series chain through internal nodes; `Rpar` and `Cpar` add shunts across the capacitor terminals. Core capacitor model is unchanged. |
7071
| Inductor instance parasitics `Rser`, `Lser`, `Rpar`, `RLshunt`, `Cpar` | Accepted in LTspice mode | Synthesizes helper R/L/C entities | OP/TRAN supported for resistance helpers; `Lser` / `Cpar` read fixtures | Analytic/parser fixture | None expected for supported forms | Current parser/runtime | Parser-only topology synthesis: `Rser` and `Lser` add a series helper chain through internal nodes; `Rpar`, `RLshunt`, and `Cpar` add shunts across the inductor terminals. Core inductor model is unchanged. |
71-
| Capacitor `Q=<expr>` and inductor `Flux=<expr>` | Accepted | Core LTspice mode: targeted diagnostic. With `UseCustomComponents()`: produces `NonlinearCapacitor` / `NonlinearInductor`. | Custom components: TRAN and AC supported with operating-point incremental capacitance/inductance. | Focused parser/TRAN/AC fixtures plus optional LTspice-backed AC/TRAN golden comparisons | Core LTspice mode still emits targeted charge/flux diagnostic when custom mappings are not enabled | `SpiceSharpParser.CustomComponents` | `Q` uses `x` as terminal voltage and supports `IC`, `M`, and `N`; `Flux` uses `x` as branch current. Optional goldens compare AC small-signal voltage and transient waveform samples against LTspice when `LTSPICE_EXE` is configured. |
72+
| Capacitor `Q=<expr>` and inductor `Flux=<expr>` | Accepted | Core LTspice mode: targeted diagnostic. With `UseCustomComponents()`: produces `NonlinearCapacitor` / `NonlinearInductor`. | Custom components: TRAN and AC supported with operating-point incremental capacitance/inductance. | Focused parser/TRAN/AC fixtures plus optional LTspice-backed AC/TRAN golden comparisons | Core LTspice mode still emits targeted charge/flux diagnostic when custom mappings are not enabled | `SpiceSharpParser.CustomComponents` | `Q` uses `x` as terminal voltage and supports `IC`, `M`, and `N`; `Flux` uses `x` as branch current. LTspice natively supports `M` but not `N` on these devices, so `N` is a parser series-cell extension and its optional goldens use equivalent native LTspice reference circuits. |
7273
| LTspice ideal diode parameters `Ron`, `Roff`, `Vfwd`, `Vrev`, `Rrev`, `Ilimit`, `RevIlimit`, `Epsilon`, `RevEpsilon` | Accepted | Core LTspice mode: targeted diagnostic. With `UseCustomComponents()`: produces `IdealDiodeModel` / `IdealDiode`. | Custom component: OP/DC/AC/TRAN supported as a memoryless nonlinear conductance. | Focused parser/integration/unit fixtures plus optional LTspice-backed DC sweep, AC, and rectifier-transient golden comparisons | Core LTspice mode still emits targeted ideal-diode diagnostics when custom mappings are not enabled | `SpiceSharpParser.CustomComponents` | These select LTspice's idealized diode behavior, not Berkeley diode parameters. The custom component supports model parameters, instance overrides, `M`/`N` scaling, `OFF`, and L/W model-bin selection; it does not model junction charge, capacitance, semiconductor noise, or temperature physics. |
7374
| Switch aliases `von`/`voff` and `ion`/`ioff` | Accepted | Lowered to `vt`/`vh` and `it`/`ih` | Existing switch model behavior | Read fixture | Missing pair or mixed native/alias forms are targeted errors | Current parser/runtime | Midpoint and half-span lowering only; no LTspice numeric parity claim. |
7475
| Switch `Vser`, `Lser` | Accepted in LTspice mode | Synthesizes helper voltage-source / inductor series chain | OP supported for `Vser`; `Lser` read fixture | Analytic/parser fixture | None expected for supported forms | Current parser/runtime | Parser-only topology synthesis: `Vser` adds a series voltage source from the first switch terminal toward an internal node; `Lser` adds a series inductor. Core switch models are unchanged. No LTspice numeric parity claim for switching dynamics. |

‎roadmap/ltspice-netlist-compatibility-plan.md‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: LTspice Netlist Compatibility Plan
33
status: Draft / Roadmap
44
scope: SpiceSharpParser + SpiceSharp
5-
last_reviewed: 2026-07-07
5+
last_reviewed: 2026-07-10
66
---
77

88
# LTspice Netlist Compatibility Plan
@@ -50,7 +50,7 @@ Goals:
5050

5151
- Make common LTspice-generated netlists parse, read, and run when their features can be represented safely by SpiceSharp and SpiceSharpBehavioral.
5252
- Prefer parser compatibility shims and explicit diagnostics before adding runtime behavior.
53-
- Preserve existing PSpice/ngspice-compatible behavior by default.
53+
- Preserve SPICE3f5/ngspice-compatible behavior by default and gate PSpice/LTspice operator differences behind explicit presets.
5454
- Build a small permission-safe fixture corpus; do not commit copied vendor libraries unless their license clearly permits redistribution.
5555
- Record known divergences instead of making blanket numeric-parity claims.
5656

@@ -78,7 +78,9 @@ Add compatibility settings as an explicit options object, not as scattered boole
7878
public sealed class CompatibilityOptions
7979
{
8080
public static CompatibilityOptions None { get; }
81+
public static CompatibilityOptions PSpice { get; }
8182
public static CompatibilityOptions LTspice { get; }
83+
public bool IsPSpice { get; }
8284
public bool IsLTspice { get; }
8385
}
8486
```
@@ -181,6 +183,7 @@ Implemented P1 behavior:
181183

182184
- Added `CompatibilityOptions` and wired it into parser and reader settings.
183185
- Preserved default behavior with `CompatibilityOptions.None`.
186+
- Added `CompatibilityOptions.PSpice` for fixture-backed PSpice expression differences.
184187
- Added `CompatibilityOptions.LTspice` with only fixture-backed behavior enabled.
185188
- Added a recognized-no-op control path for `.backanno` in LTspice mode.
186189
- Kept targeted unsupported diagnostics for `.tf`, `.net`, `.ferret`, `.loadbias`, `.savebias`, and `.machine` / `.endmachine`.
@@ -208,8 +211,9 @@ Implemented P2 behavior:
208211

209212
- Added dialect-neutral expression support for `fabs(x)`, one-argument `round(x)`, unary `!`, and single-character boolean `&` / `|`.
210213
- Added fixture-backed evidence for `arccos`, `arcsin`, `arctan`, `sgn`, `pwr`, `pwrs`, `hypot`, scalar `table(...)` / `tbl(...)`, and `**`.
211-
- Kept `^` as the existing exponent operator; LTspice boolean XOR is deferred to avoid changing current semantics.
212-
- Added LTspice-style smooth limiting support for `uplim(...)` and `dnlim(...)`, while keeping unary `~` as a targeted diagnostic.
214+
- Added explicit PSpice-mode `^` as boolean XOR with `&`, `^`, `|` precedence, while default/SPICE3f5 and LTspice modes retain `^` exponent behavior.
215+
- Added LTspice-mode unary `~` as a boolean-NOT alias and `xor(a,b)` as a two-argument boolean XOR function.
216+
- Added LTspice-style smooth limiting support for `uplim(...)` and `dnlim(...)`.
213217
- Added six-argument `EXP(v1 v2 td1 tau1 td2 tau2)` source waveform support with argument-count and positive-tau diagnostics.
214218
- Added LTspice-mode finite-cycle `PULSE(... Ncycles)` and `SINE(... Ncycles)` support with targeted diagnostics for invalid period/frequency and cycle-count arguments.
215219
- Added PWL file fixtures for supported local two-column text variants with optional header rows, leading blank/comment lines, and space/comma/semicolon/tab delimiters, plus targeted diagnostics for missing files, empty files, missing data rows, and malformed rows.
@@ -221,7 +225,6 @@ Implemented P2 behavior:
221225
Remaining follow-up:
222226

223227
- Compare existing random functions with LTspice semantics before making numeric claims.
224-
- Decide whether LTspice boolean XOR can be added without breaking existing `^` exponent behavior.
225228
- Defer nested/combined LTspice PWL specs, trigger restarts, time/value scale factors, `SCOPEDATA`, and relative `+time` points until fixture-backed runtime behavior is specified.
226229

227230
Acceptance criteria:

0 commit comments

Comments
 (0)