Skip to content

Commit ea8e95d

Browse files
Refactor LTspiceADeviceGenerator
1 parent b620949 commit ea8e95d

8 files changed

Lines changed: 1300 additions & 590 deletions

File tree

src/SpiceSharpParser.CustomComponents/ARCHITECTURE.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,18 @@ type so existing callers keep the same API.
9595

9696
### LTspice A-devices
9797

98-
An A-device is translated in three stages:
98+
`LTspiceADeviceGenerator` coordinates a staged translation:
9999

100100
1. `LTspiceADeviceInstanceReader` reads the eight terminals, model name, flags,
101101
and raw parameter expressions.
102-
2. `LTspiceADeviceValidator` checks model-specific requirements and parameter
102+
2. `LTspiceADeviceCatalog` selects a declarative definition containing the
103+
portable subcircuit, terminal order, output terminals, and parameter map.
104+
3. `LTspiceADeviceValidator` checks model-specific requirements and parameter
103105
ranges.
104-
3. `LTspiceADeviceGenerator` selects the appropriate digital or analog
105-
subcircuit expansion.
106+
4. `LTspiceADeviceConnections` applies terminal-8 common/unused semantics and
107+
detaches unused outputs.
108+
5. `LTspiceADeviceExpander` evaluates parameters, creates any private digital
109+
rails, and instantiates the selected digital or analog subcircuit.
106110

107111
Expansion may add several entities. If any part fails, the generator restores
108112
the reading context to its pre-expansion state and reports one reader
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Globalization;
4+
5+
namespace SpiceSharpParser.CustomComponents
6+
{
7+
/// <summary>
8+
/// Resolves native A-device terminal positions into portable subcircuit nodes.
9+
/// </summary>
10+
internal sealed class LTspiceADeviceConnections
11+
{
12+
private readonly bool[] _unusedTerminals;
13+
private readonly string[] _terminals;
14+
15+
private LTspiceADeviceConnections(
16+
string[] terminals,
17+
bool[] unusedTerminals)
18+
{
19+
_terminals = terminals;
20+
_unusedTerminals = unusedTerminals;
21+
}
22+
23+
public static LTspiceADeviceConnections Create(
24+
LTspiceADeviceInstance instance,
25+
LTspiceADeviceDefinition definition,
26+
string portableInstanceName,
27+
bool nodeNamesAreCaseSensitive)
28+
{
29+
var terminals = (string[])instance.Terminals.Clone();
30+
var unused = new bool[LTspiceADeviceInstance.TerminalCount];
31+
StringComparison comparison = nodeNamesAreCaseSensitive
32+
? StringComparison.Ordinal
33+
: StringComparison.OrdinalIgnoreCase;
34+
string commonNode = terminals[(int)ADeviceTerminal.T8Common];
35+
36+
for (int index = 0; index < terminals.Length; index++)
37+
{
38+
unused[index] = terminals[index].Equals(commonNode, comparison);
39+
}
40+
41+
// Repeating terminal 8 means "not connected" in native A-device
42+
// syntax. Inputs may safely remain tied to common. Outputs cannot:
43+
// the portable macromodel has a real output stage, so give each
44+
// unused output a private node.
45+
foreach (ADeviceTerminal outputTerminal in definition.OutputTerminals)
46+
{
47+
int index = (int)outputTerminal;
48+
if (unused[index])
49+
{
50+
terminals[index] = portableInstanceName
51+
+ ".__a_nc"
52+
+ (index + 1).ToString(CultureInfo.InvariantCulture);
53+
}
54+
}
55+
56+
return new LTspiceADeviceConnections(terminals, unused);
57+
}
58+
59+
public string CommonNode => Get(ADeviceTerminal.T8Common);
60+
61+
public bool IsUnused(ADeviceTerminal terminal)
62+
{
63+
return _unusedTerminals[(int)terminal];
64+
}
65+
66+
public IReadOnlyList<string> CreateSubcircuitNodes(
67+
LTspiceADeviceDefinition definition,
68+
string highRailNode,
69+
string lowRailNode)
70+
{
71+
int railCount = definition.CreatesDigitalRails ? 2 : 0;
72+
var result = new List<string>(
73+
definition.SubcircuitTerminals.Count + railCount);
74+
foreach (ADeviceTerminal terminal in definition.SubcircuitTerminals)
75+
{
76+
result.Add(Get(terminal));
77+
}
78+
79+
if (definition.CreatesDigitalRails)
80+
{
81+
result.Add(highRailNode);
82+
result.Add(lowRailNode);
83+
}
84+
85+
return result;
86+
}
87+
88+
private string Get(ADeviceTerminal terminal)
89+
{
90+
return _terminals[(int)terminal];
91+
}
92+
}
93+
}

0 commit comments

Comments
 (0)