Skip to content

Commit a5a7bf1

Browse files
Prototype
1 parent 45ab543 commit a5a7bf1

7 files changed

Lines changed: 231 additions & 2 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Mosfet circuit
2+
Md 0 1 2 3 my-pmos
3+
.model my-pmos.1 pmos(level = 49 lmin=0.18u)
4+
.model my-pmos.2 pmos(level = 49 lmin=1.18u)
5+
.END
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using SpiceSharp.Components;
2+
using SpiceSharp.Entities;
3+
using SpiceSharp.Simulations;
4+
using System.Collections.Generic;
5+
using System.Xml.Linq;
6+
7+
public class BSIM3AggregateModel : Entity
8+
{
9+
/// <summary>
10+
/// Gets the models in the aggregate model based on sizes.
11+
/// </summary>
12+
public HashSet<BSIM3Model> Models { get; } = [];
13+
14+
/// <summary>
15+
/// Creates an aggregate model.
16+
/// </summary>
17+
/// <param name="name">The name.</param>
18+
public BSIM3AggregateModel(string name)
19+
: base(name)
20+
{
21+
}
22+
23+
/// <summary>
24+
/// Creates an aggregate model based on sizes.
25+
/// </summary>
26+
/// <param name="name"></param>
27+
/// <param name="models"></param>
28+
public BSIM3AggregateModel(string name, IEnumerable<BSIM3Model> models)
29+
: base(name)
30+
{
31+
foreach (var model in models)
32+
Models.Add(model);
33+
}
34+
35+
public override void CreateBehaviors(ISimulation simulation)
36+
{
37+
throw new System.NotImplementedException();
38+
}
39+
40+
/// <inheritdoc />
41+
public override IEntity Clone()
42+
{
43+
var n = new BSIM3AggregateModel(Name);
44+
foreach (var model in Models)
45+
n.Models.Add((BSIM3Model)model.Clone());
46+
return n;
47+
}
48+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
using SpiceSharp.Components;
2+
using SpiceSharpParser.Common.Validation;
3+
using SpiceSharpParser.ModelReaders.Netlist.Spice.Context;
4+
using SpiceSharpParser.ModelReaders.Netlist.Spice.Context.Models;
5+
using SpiceSharpParser.Models.Netlist.Spice.Objects;
6+
using SpiceSharpParser.Models.Netlist.Spice.Objects.Parameters;
7+
using System;
8+
9+
namespace SpiceSharpParser.ModelReaders.Netlist.Spice.Readers.EntityGenerators.Models
10+
{
11+
public class ComplexMosfetModelGenerator : MosfetModelGenerator, ICustomModelGenerator
12+
{
13+
public ComplexMosfetModelGenerator()
14+
{
15+
}
16+
17+
public Context.Models.Model Process(Context.Models.Model model, IModelsRegistry models)
18+
{
19+
20+
if (model.Entity is BSIM3Model bsim3Model)
21+
{
22+
23+
if (model.Name.Contains("."))
24+
{
25+
var aggregateName = bsim3Model.Name.Substring(0, bsim3Model.Name.IndexOf('.'));
26+
var aggregate = models.FindModel(aggregateName);
27+
if (aggregate != null)
28+
{
29+
var aggrategeEntity = aggregate.Entity as BSIM3AggregateModel;
30+
aggrategeEntity.Models.Add(bsim3Model);
31+
32+
return aggregate;
33+
}
34+
else
35+
{
36+
var aggrategeEntity = new BSIM3AggregateModel(aggregateName);
37+
aggrategeEntity.Models.Add(bsim3Model);
38+
39+
return new Context.Models.Model(aggregateName, aggrategeEntity, null);
40+
}
41+
42+
}
43+
44+
}
45+
return model;
46+
}
47+
48+
public override void AddGenericLevel<TModel, TParameters>(int level)
49+
{
50+
base.AddGenericLevel<TModel, TParameters>(level);
51+
}
52+
53+
public override void AddLevel<TModel, TParameters>(int level)
54+
{
55+
Levels[level] = (name, type, _) =>
56+
{
57+
var mosfet = (TModel)Activator.CreateInstance(typeof(TModel), name);
58+
switch (type.ToLower())
59+
{
60+
case "nmos": mosfet.SetParameter("nmos", true); break;
61+
case "pmos": mosfet.SetParameter("pmos", true); break;
62+
}
63+
64+
return new Context.Models.Model(name, mosfet, mosfet.Parameters);
65+
};
66+
}
67+
68+
69+
public override Context.Models.Model Generate(string id, string type, ParameterCollection parameters, IReadingContext context)
70+
{
71+
var clonedParameters = (ParameterCollection)parameters.Clone();
72+
73+
int level = 1;
74+
string version = null;
75+
int lindex = -1, vindex = -1;
76+
for (int i = 0; i < clonedParameters.Count; i++)
77+
{
78+
if (clonedParameters[i] is AssignmentParameter ap)
79+
{
80+
if (ap.Name.ToLower() == "level")
81+
{
82+
lindex = i;
83+
level = (int)Math.Round(context.Evaluator.EvaluateDouble(ap.Value));
84+
}
85+
86+
if (ap.Name.ToLower() == "version")
87+
{
88+
vindex = i;
89+
version = ap.Value.ToLower();
90+
}
91+
92+
if (vindex >= 0 && lindex >= 0)
93+
{
94+
break;
95+
}
96+
}
97+
}
98+
99+
if (lindex >= 0)
100+
{
101+
clonedParameters.RemoveAt(lindex);
102+
}
103+
104+
if (vindex >= 0)
105+
{
106+
clonedParameters.RemoveAt(vindex < lindex ? vindex : vindex - 1);
107+
}
108+
109+
// Generate the model
110+
Context.Models.Model model;
111+
if (Levels.ContainsKey(level))
112+
{
113+
model = Levels[level].Invoke(id, type, version);
114+
}
115+
else
116+
{
117+
context.Result.ValidationResult.AddError(ValidationEntrySource.Reader, $"Unknown mosfet model level {level}", parameters.LineInfo);
118+
return null;
119+
}
120+
121+
// Read all the parameters
122+
SetParameters(context, model.Entity, clonedParameters);
123+
124+
return model;
125+
}
126+
127+
}
128+
}

src/SpiceSharpParser.IntegrationTests/Examples/Extensions/CustomMosfetModelTest.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,36 @@ public void When_BSIM1_Used_NoExceptions()
8080
spiceSharpReader.Settings.Mappings.Components.Map("M", mosfetGenerator);
8181

8282

83+
var spiceSharpModel = spiceSharpReader.Read(parseResult.FinalModel);
84+
85+
Assert.False(spiceSharpModel.ValidationResult.HasError);
86+
Assert.False(spiceSharpModel.ValidationResult.HasWarning);
87+
}
88+
89+
[Fact]
90+
public void When_BSIM3_Used_NoExceptions()
91+
{
92+
// Create a model from text file
93+
string path = Path.Combine(Directory.GetCurrentDirectory(), "Examples/Circuits/MosfetExample3.cir");
94+
var netlistContent = File.ReadAllText(path);
95+
var parser = new SpiceNetlistParser();
96+
parser.Settings.Lexing.HasTitle = true;
97+
var parseResult = parser.ParseNetlist(netlistContent);
98+
99+
// Convert to Spice#
100+
var spiceSharpReader = new SpiceSharpReader();
101+
spiceSharpReader.Settings.CaseSensitivity.IsModelTypeCaseSensitive = false;
102+
103+
// custom mosfet models
104+
var modelGenerator = new ComplexMosfetModelGenerator();
105+
modelGenerator.AddGenericLevel<BSIM3Model, SpiceSharpBSIM.Components.Semiconductors.BSIM.BSIM3Behaviors.ModelParameters>(49);
106+
107+
spiceSharpReader.Settings.Mappings.Models.Map(new[] { "PMOS", "NMOS" }, modelGenerator);
108+
var mosfetGenerator = new MosfetGenerator();
109+
mosfetGenerator.AddMosfet<SpiceSharp.Components.Mosfet3Model, SpiceSharp.Components.Mosfet3>();
110+
spiceSharpReader.Settings.Mappings.Components.Map("M", mosfetGenerator);
111+
112+
83113
var spiceSharpModel = spiceSharpReader.Read(parseResult.FinalModel);
84114

85115
Assert.False(spiceSharpModel.ValidationResult.HasError);

src/SpiceSharpParser.IntegrationTests/SpiceSharpParser.IntegrationTests.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@
9797
<None Update="Examples\Circuits\Example04_reversed.cir">
9898
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
9999
</None>
100+
<None Update="Examples\Circuits\MosfetExample3.cir">
101+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
102+
</None>
100103
<None Update="Examples\Circuits\MosfetExample2.cir">
101104
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
102105
</None>

src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/IModelGenerator.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,9 @@ public interface IModelGenerator
77
{
88
Model Generate(string id, string type, SpiceSharpParser.Models.Netlist.Spice.Objects.ParameterCollection parameters, IReadingContext context);
99
}
10+
11+
public interface ICustomModelGenerator : IModelGenerator
12+
{
13+
Context.Models.Model Process(Context.Models.Model model, IModelsRegistry models);
14+
}
1015
}

src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/StochasticModelsGenerator.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,18 @@ public Context.Models.Model GenerateModel(IModelGenerator modelGenerator, string
8282
RegisterDevAndLotModels(parameters, stochasticModelRegistry, model, (modelId) =>
8383
{
8484
var stochasticCandidate = modelGenerator.Generate(modelId, type, filteredParameters, context);
85-
context.ModelsRegistry.RegisterModelInstance(stochasticCandidate);
86-
return stochasticCandidate;
85+
86+
if (modelGenerator is ICustomModelGenerator custom)
87+
{
88+
var model = custom.Process(stochasticCandidate, context.ModelsRegistry);
89+
context.ModelsRegistry.RegisterModelInstance(model);
90+
return model;
91+
}
92+
else
93+
{
94+
context.ModelsRegistry.RegisterModelInstance(stochasticCandidate);
95+
return stochasticCandidate;
96+
}
8797
});
8898
return model;
8999
}

0 commit comments

Comments
 (0)