diff --git a/src/SpiceSharpParser.IntegrationTests/Examples/Circuits/MosfetExample3.cir b/src/SpiceSharpParser.IntegrationTests/Examples/Circuits/MosfetExample3.cir new file mode 100644 index 00000000..cae39dda --- /dev/null +++ b/src/SpiceSharpParser.IntegrationTests/Examples/Circuits/MosfetExample3.cir @@ -0,0 +1,5 @@ +Mosfet circuit +Md 0 1 2 3 my-pmos +.model my-pmos.1 pmos(level = 49 lmin=0.18u) +.model my-pmos.2 pmos(level = 49 lmin=1.18u) +.END diff --git a/src/SpiceSharpParser.IntegrationTests/Examples/Extensions/Aggregate.cs b/src/SpiceSharpParser.IntegrationTests/Examples/Extensions/Aggregate.cs new file mode 100644 index 00000000..71dab453 --- /dev/null +++ b/src/SpiceSharpParser.IntegrationTests/Examples/Extensions/Aggregate.cs @@ -0,0 +1,48 @@ +using SpiceSharp.Components; +using SpiceSharp.Entities; +using SpiceSharp.Simulations; +using System.Collections.Generic; +using System.Xml.Linq; + +public class BSIM3AggregateModel : Entity +{ + /// + /// Gets the models in the aggregate model based on sizes. + /// + public HashSet Models { get; } = []; + + /// + /// Creates an aggregate model. + /// + /// The name. + public BSIM3AggregateModel(string name) + : base(name) + { + } + + /// + /// Creates an aggregate model based on sizes. + /// + /// + /// + public BSIM3AggregateModel(string name, IEnumerable models) + : base(name) + { + foreach (var model in models) + Models.Add(model); + } + + public override void CreateBehaviors(ISimulation simulation) + { + throw new System.NotImplementedException(); + } + + /// + public override IEntity Clone() + { + var n = new BSIM3AggregateModel(Name); + foreach (var model in Models) + n.Models.Add((BSIM3Model)model.Clone()); + return n; + } +} \ No newline at end of file diff --git a/src/SpiceSharpParser.IntegrationTests/Examples/Extensions/ComplexMosfetModelGenerator.cs b/src/SpiceSharpParser.IntegrationTests/Examples/Extensions/ComplexMosfetModelGenerator.cs new file mode 100644 index 00000000..57ea5929 --- /dev/null +++ b/src/SpiceSharpParser.IntegrationTests/Examples/Extensions/ComplexMosfetModelGenerator.cs @@ -0,0 +1,43 @@ +using SpiceSharp.Components; +using SpiceSharpParser.ModelReaders.Netlist.Spice.Context.Models; + +namespace SpiceSharpParser.ModelReaders.Netlist.Spice.Readers.EntityGenerators.Models +{ + public class ComplexMosfetModelGenerator : MosfetModelGenerator, ICustomModelGenerator + { + public ComplexMosfetModelGenerator() + { + } + + public Context.Models.Model Process(Context.Models.Model model, IModelsRegistry models) + { + + if (model.Entity is BSIM3Model bsim3Model) + { + + if (model.Name.Contains(".")) + { + var aggregateName = bsim3Model.Name.Substring(0, bsim3Model.Name.IndexOf('.')); + var aggregate = models.FindModel(aggregateName); + if (aggregate != null) + { + var aggrategeEntity = aggregate.Entity as BSIM3AggregateModel; + aggrategeEntity.Models.Add(bsim3Model); + + return aggregate; + } + else + { + var aggrategeEntity = new BSIM3AggregateModel(aggregateName); + aggrategeEntity.Models.Add(bsim3Model); + + return new Context.Models.Model(aggregateName, aggrategeEntity, null); + } + + } + + } + return model; + } + } +} \ No newline at end of file diff --git a/src/SpiceSharpParser.IntegrationTests/Examples/Extensions/CustomMosfetModelTest.cs b/src/SpiceSharpParser.IntegrationTests/Examples/Extensions/CustomMosfetModelTest.cs index ed0a7c82..6204284c 100644 --- a/src/SpiceSharpParser.IntegrationTests/Examples/Extensions/CustomMosfetModelTest.cs +++ b/src/SpiceSharpParser.IntegrationTests/Examples/Extensions/CustomMosfetModelTest.cs @@ -80,6 +80,36 @@ public void When_BSIM1_Used_NoExceptions() spiceSharpReader.Settings.Mappings.Components.Map("M", mosfetGenerator); + var spiceSharpModel = spiceSharpReader.Read(parseResult.FinalModel); + + Assert.False(spiceSharpModel.ValidationResult.HasError); + Assert.False(spiceSharpModel.ValidationResult.HasWarning); + } + + [Fact] + public void When_BSIM3_Used_NoExceptions() + { + // Create a model from text file + string path = Path.Combine(Directory.GetCurrentDirectory(), "Examples/Circuits/MosfetExample3.cir"); + var netlistContent = File.ReadAllText(path); + var parser = new SpiceNetlistParser(); + parser.Settings.Lexing.HasTitle = true; + var parseResult = parser.ParseNetlist(netlistContent); + + // Convert to Spice# + var spiceSharpReader = new SpiceSharpReader(); + spiceSharpReader.Settings.CaseSensitivity.IsModelTypeCaseSensitive = false; + + // custom mosfet models + var modelGenerator = new ComplexMosfetModelGenerator(); + modelGenerator.AddGenericLevel(49); + + spiceSharpReader.Settings.Mappings.Models.Map(new[] { "PMOS", "NMOS" }, modelGenerator); + var mosfetGenerator = new MosfetGenerator(); + mosfetGenerator.AddMosfet(); + spiceSharpReader.Settings.Mappings.Components.Map("M", mosfetGenerator); + + var spiceSharpModel = spiceSharpReader.Read(parseResult.FinalModel); Assert.False(spiceSharpModel.ValidationResult.HasError); diff --git a/src/SpiceSharpParser.IntegrationTests/SpiceSharpParser.IntegrationTests.csproj b/src/SpiceSharpParser.IntegrationTests/SpiceSharpParser.IntegrationTests.csproj index 95097b93..2b1b40db 100644 --- a/src/SpiceSharpParser.IntegrationTests/SpiceSharpParser.IntegrationTests.csproj +++ b/src/SpiceSharpParser.IntegrationTests/SpiceSharpParser.IntegrationTests.csproj @@ -97,6 +97,9 @@ Always + + Always + Always diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/IModelGenerator.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/IModelGenerator.cs index 37544c3f..4c4dcff9 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/IModelGenerator.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/IModelGenerator.cs @@ -7,4 +7,9 @@ public interface IModelGenerator { Model Generate(string id, string type, SpiceSharpParser.Models.Netlist.Spice.Objects.ParameterCollection parameters, IReadingContext context); } + + public interface ICustomModelGenerator : IModelGenerator + { + Context.Models.Model Process(Context.Models.Model model, IModelsRegistry models); + } } \ No newline at end of file diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/StochasticModelsGenerator.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/StochasticModelsGenerator.cs index dbea6bfe..5d1af38a 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/StochasticModelsGenerator.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/StochasticModelsGenerator.cs @@ -82,8 +82,18 @@ public Context.Models.Model GenerateModel(IModelGenerator modelGenerator, string RegisterDevAndLotModels(parameters, stochasticModelRegistry, model, (modelId) => { var stochasticCandidate = modelGenerator.Generate(modelId, type, filteredParameters, context); - context.ModelsRegistry.RegisterModelInstance(stochasticCandidate); - return stochasticCandidate; + + if (modelGenerator is ICustomModelGenerator custom) + { + var model = custom.Process(stochasticCandidate, context.ModelsRegistry); + context.ModelsRegistry.RegisterModelInstance(model); + return model; + } + else + { + context.ModelsRegistry.RegisterModelInstance(stochasticCandidate); + return stochasticCandidate; + } }); return model; }