From 3f3194babf1be2bc4999f4fd0da8dd8b5c125053 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 4 May 2026 16:54:53 +0200 Subject: [PATCH 01/23] Update to meas: stdout-->stderr, remove unusable error message, reported by Dmitriy --- src/frontend/com_measure2.c | 7 +------ src/frontend/measure.c | 4 ++-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/frontend/com_measure2.c b/src/frontend/com_measure2.c index 29b6e63c9..5b3454052 100644 --- a/src/frontend/com_measure2.c +++ b/src/frontend/com_measure2.c @@ -1643,7 +1643,7 @@ get_measure2( *result = 0.0e0; /* default result */ if (!wl) { - printf("usage: measure .....\n"); + fprintf(cp_err, "Error: no assignment found in command meas.\n"); return MEASUREMENT_FAILURE; } @@ -1665,11 +1665,6 @@ get_measure2( wlTarg = NULL; wlWhen = NULL; - if (!words) { - fprintf(cp_err, "Error: no assignment found.\n"); - return MEASUREMENT_FAILURE; - } - precision = measure_get_precision(); wl_cnt = 0; while (words) { diff --git a/src/frontend/measure.c b/src/frontend/measure.c index 4efd1d7bf..1a7e427b2 100644 --- a/src/frontend/measure.c +++ b/src/frontend/measure.c @@ -119,7 +119,7 @@ com_meas(wordlist *wl) /* get output var name */ wl_count = wl_count->wl_next; if (!wl_count) { - fprintf(stdout, + fprintf(stderr, " meas %s failed!\n" " unspecified output var name\n\n", line_in); tfree(line_in); @@ -130,7 +130,7 @@ com_meas(wordlist *wl) fail = get_measure2(wl, &result, NULL, FALSE); if (fail) { - fprintf(stdout, " meas %s failed!\n\n", line_in); + fprintf(stderr, " meas %s failed!\n\n", line_in); tfree(line_in); return; } From 1f6e466c8e5505be5be10df160baff6801fe076a Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 5 May 2026 15:47:16 +0200 Subject: [PATCH 02/23] Update of wave README --- README.wavsim | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.wavsim b/README.wavsim index 8a6e23dcd..8d5d8e490 100644 --- a/README.wavsim +++ b/README.wavsim @@ -21,6 +21,12 @@ http://gareus.org/oss/spicesound/start Example files are available at \examples\wave +Compiling for MS Windows, 64 bit, with VS2022 or VS2026: +Download https://github.com/libsndfile/libsndfile/releases/download/1.2.2/libsndfile-1.2.2-win64.zip +Expand libsndfile-1.2.2-win64 into same level as ngspice, rename the directory to libsndfile. +Download https://github.com/libsndfile/libsamplerate/releases/download/0.2.2/libsamplerate-0.2.2-win64.zip +Expand libsamplerate-0.2.2-win64 into same level as ngspice, rename the directory to libsamplerate. + Compiling for macOS M2 requires installing libsndfile and libsamplerate from Homebrew. compile_macos_clang_M2.sh has been enhanced by adding -I/opt/homebrew/opt/libsndfile/include -I/opt/homebrew/opt/libsamplerate/include From 65fd1e833fda3e74eb8d13558b67daac87dfb768 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 5 May 2026 15:48:01 +0200 Subject: [PATCH 03/23] Add copying sndfile.dll and samplerate.dll --- visualc/make-install-vngspice.bat | 3 +++ visualc/make-install-vngspiced.bat | 3 +++ 2 files changed, 6 insertions(+) diff --git a/visualc/make-install-vngspice.bat b/visualc/make-install-vngspice.bat index aa8a3e0ae..54c2973d4 100644 --- a/visualc/make-install-vngspice.bat +++ b/visualc/make-install-vngspice.bat @@ -55,6 +55,9 @@ copy %cmsrc%\tlines64.cm %dst%\lib\ngspice\tlines.cm copy xspice\verilog\ivlng.dll %dst%\lib\ngspice\ivlng.dll copy xspice\verilog\shim.vpi %dst%\lib\ngspice\ivlng.vpi +copy ..\..\libsndfile\bin\sndfile.dll %dst%\bin\ +copy ..\..\libsamplerate\bin\samplerate.dll %dst%\bin\ + if "%2" == "fftw" goto copy2-64 if "%3" == "fftw" goto copy2-64 diff --git a/visualc/make-install-vngspiced.bat b/visualc/make-install-vngspiced.bat index 0f1d3548d..be3050914 100644 --- a/visualc/make-install-vngspiced.bat +++ b/visualc/make-install-vngspiced.bat @@ -55,6 +55,9 @@ copy %cmsrc%\tlines64.cm %dst%\lib\ngspice\tlines.cm copy xspice\verilog\ivlng.dll %dst%\lib\ngspice\ivlng.dll copy xspice\verilog\shim.vpi %dst%\lib\ngspice\ivlng.vpi +copy ..\..\libsndfile\bin\sndfile.dll %dst%\bin\ +copy ..\..\libsamplerate\bin\samplerate.dll %dst%\bin\ + if "%2" == "fftw" goto copy2-64 if "%3" == "fftw" goto copy2-64 From 936ca5cec7e4203604f8b669c255c90495ad1e06 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 5 May 2026 15:49:35 +0200 Subject: [PATCH 04/23] Update project files: integrate wave compilation including sdnfile.dll and samplerate.dll, make both project files more uniform. --- visualc/vngspice-fftw.vcxproj | 51 ++++++++++++++++++++++------------- visualc/vngspice.vcxproj | 19 ++++++++++--- 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/visualc/vngspice-fftw.vcxproj b/visualc/vngspice-fftw.vcxproj index 32095d9c1..0e8ee2e87 100644 --- a/visualc/vngspice-fftw.vcxproj +++ b/visualc/vngspice-fftw.vcxproj @@ -305,7 +305,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 Disabled - ..\src\maths\poly;..\src\frontend;..\src\spicelib\devices;tmp-bison;src\include;..\src\spicelib\parser;..\src\include;..\src\include\cppduals;.;..\..\fftw-3.3-dll64;%(AdditionalIncludeDirectories) + ..\..\libsamplerate\include;..\..\libsndfile\include;..\src\maths\poly;..\src\frontend;..\src\spicelib\devices;tmp-bison;src\include;..\src\spicelib\parser;..\src\include;..\src\include\cppduals;.;..\..\fftw-3.3-dll64;%(AdditionalIncludeDirectories) _CRT_SECURE_NO_DEPRECATE;SIMULATOR;XSPICE;NGDEBUG;CONFIG64;HAVE_LIBFFTW3;%(PreprocessorDefinitions) false @@ -323,7 +323,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 /openmp:llvm %(AdditionalOptions) - psapi.lib;KLU_COMPLEX.lib;$(IntDir)libfftw3-3.lib;%(AdditionalDependencies) + sndfile.lib;samplerate.lib;psapi.lib;KLU_COMPLEX.lib;$(IntDir)libfftw3-3.lib;%(AdditionalDependencies) true Windows 0 @@ -335,10 +335,12 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 MachineX64 true - KLU\x64\Debug;%(AdditionalLibraryDirectories) + ../../libsamplerate/lib;../../libsndfile/lib;KLU\x64\Debug;%(AdditionalLibraryDirectories) + copy /y "..\..\libsndfile\bin\sndfile.dll" "$(OutDir)" + copy /y "..\..\libsamplerate\bin\samplerate.dll" "$(OutDir)" copy /y "..\..\fftw-3.3-dll64\libfftw3-3.dll" "$(OutDir)" make-install-vngspiced.bat $(OutDir) fftw 64 @@ -358,7 +360,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 true Speed true - ..\src\maths\poly;..\src\frontend;..\src\spicelib\devices;tmp-bison;src\include;..\src\spicelib\parser;..\src\include;..\src\include\cppduals;.;..\..\fftw-3.3-dll64;%(AdditionalIncludeDirectories) + ..\..\libsamplerate\include;..\..\libsndfile\include;..\src\maths\poly;..\src\frontend;..\src\spicelib\devices;tmp-bison;src\include;..\src\spicelib\parser;..\src\include;..\src\include\cppduals;.;..\..\fftw-3.3-dll64;%(AdditionalIncludeDirectories) _CRT_SECURE_NO_DEPRECATE;SIMULATOR;XSPICE;CONFIG64;HAVE_LIBFFTW3;%(PreprocessorDefinitions) false @@ -376,7 +378,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 /openmp:llvm %(AdditionalOptions) - psapi.lib;KLU_COMPLEX.lib;$(IntDir)libfftw3-3.lib;%(AdditionalDependencies) + sndfile.lib;samplerate.lib;psapi.lib;KLU_COMPLEX.lib;$(IntDir)libfftw3-3.lib;%(AdditionalDependencies) true Windows 0 @@ -393,10 +395,13 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 MachineX64 true - KLU\x64\Release;%(AdditionalLibraryDirectories) + ../../libsamplerate/lib;../../libsndfile/lib;KLU\x64\Release;%(AdditionalLibraryDirectories) + + copy /y "..\..\libsndfile\bin\sndfile.dll" "$(OutDir)" + copy /y "..\..\libsamplerate\bin\samplerate.dll" "$(OutDir)" copy /y "..\..\fftw-3.3-dll64\libfftw3-3.dll" "$(OutDir)" make-install-vngspice.bat $(OutDir) fftw 64 @@ -511,7 +516,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 Disabled - ..\src\maths\poly;..\src\frontend;..\src\spicelib\devices;tmp-bison;src\include;..\src\spicelib\parser;..\src\include;..\src\include\cppduals;.;..\..\fftw-3.3-dll64;%(AdditionalIncludeDirectories) + ..\..\libsamplerate\include;..\..\libsndfile\include;..\src\maths\poly;..\src\frontend;..\src\spicelib\devices;tmp-bison;src\include;..\src\spicelib\parser;..\src\include;..\src\include\cppduals;.;..\..\fftw-3.3-dll64;%(AdditionalIncludeDirectories) _CRT_SECURE_NO_DEPRECATE;SIMULATOR;XSPICE;NGDEBUG;CONSOLE;CONFIG64;HAVE_LIBFFTW3;%(PreprocessorDefinitions) false @@ -529,7 +534,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 /openmp:llvm %(AdditionalOptions) - psapi.lib;KLU_COMPLEX.lib;$(IntDir)libfftw3-3.lib;%(AdditionalDependencies) + sndfile.lib;samplerate.lib;psapi.lib;KLU_COMPLEX.lib;$(IntDir)libfftw3-3.lib;%(AdditionalDependencies) true Console 0 @@ -541,10 +546,12 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 MachineX64 true - KLU\x64\Debug;%(AdditionalLibraryDirectories) + ../../libsamplerate/lib;../../libsndfile/lib;KLU\x64\Debug;%(AdditionalLibraryDirectories) + copy /y "..\..\libsndfile\bin\sndfile.dll" "$(OutDir)" + copy /y "..\..\libsamplerate\bin\samplerate.dll" "$(OutDir)" copy /y "..\..\fftw-3.3-dll64\libfftw3-3.dll" "$(OutDir)" make-install-vngspiced.bat $(OutDir) fftw 64 @@ -564,7 +571,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 true Speed true - ..\src\maths\poly;..\src\frontend;..\src\spicelib\devices;tmp-bison;src\include;..\src\spicelib\parser;..\src\include;..\src\include\cppduals;.;..\..\fftw-3.3-dll64;%(AdditionalIncludeDirectories) + ..\..\libsamplerate\include;..\..\libsndfile\include;..\src\maths\poly;..\src\frontend;..\src\spicelib\devices;tmp-bison;src\include;..\src\spicelib\parser;..\src\include;..\src\include\cppduals;.;..\..\fftw-3.3-dll64;%(AdditionalIncludeDirectories) _CRT_SECURE_NO_DEPRECATE;SIMULATOR;XSPICE;CONSOLE;CONFIG64;HAVE_LIBFFTW3;%(PreprocessorDefinitions) false @@ -582,7 +589,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 /openmp:llvm %(AdditionalOptions) - psapi.lib;KLU_COMPLEX.lib;$(IntDir)libfftw3-3.lib;%(AdditionalDependencies) + sndfile.lib;samplerate.lib;psapi.lib;KLU_COMPLEX.lib;$(IntDir)libfftw3-3.lib;%(AdditionalDependencies) true Console 0 @@ -597,7 +604,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 MachineX64 true - KLU\x64\Release;%(AdditionalLibraryDirectories) + ../../libsamplerate/lib;../../libsndfile/lib;KLU\x64\Release;%(AdditionalLibraryDirectories) @@ -673,7 +680,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 true Speed true - ..\src\maths\poly;..\src\frontend;..\src\spicelib\devices;tmp-bison;src\include;..\src\spicelib\parser;..\src\include;..\src\include\cppduals;.;..\..\fftw-3.3-dll64;%(AdditionalIncludeDirectories) + ..\..\libsamplerate\include;..\..\libsndfile\include;..\src\maths\poly;..\src\frontend;..\src\spicelib\devices;tmp-bison;src\include;..\src\spicelib\parser;..\src\include;..\src\include\cppduals;.;..\..\fftw-3.3-dll64;%(AdditionalIncludeDirectories) _CRT_SECURE_NO_DEPRECATE;SIMULATOR;XSPICE;USE_OMP;CONFIG64;HAVE_LIBFFTW3;%(PreprocessorDefinitions) false @@ -693,7 +700,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 /openmp:llvm %(AdditionalOptions) - psapi.lib;KLU_COMPLEX.lib;$(IntDir)libfftw3-3.lib;%(AdditionalDependencies) + sndfile.lib;samplerate.lib;psapi.lib;KLU_COMPLEX.lib;$(IntDir)libfftw3-3.lib;%(AdditionalDependencies) true Windows 0 @@ -710,10 +717,12 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 MachineX64 true - KLU\x64\Release;%(AdditionalLibraryDirectories) + ../../libsamplerate/lib;../../libsndfile/lib;KLU\x64\Release;%(AdditionalLibraryDirectories) + copy /y "..\..\libsndfile\bin\sndfile.dll" "$(OutDir)" + copy /y "..\..\libsamplerate\bin\samplerate.dll" "$(OutDir)" copy /y "..\..\fftw-3.3-dll64\libfftw3-3.dll" "$(OutDir)" make-install-vngspice.bat $(OutDir) fftw 64 @@ -785,7 +794,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 true Speed true - ..\src\maths\poly;..\src\frontend;..\src\spicelib\devices;tmp-bison;src\include;..\src\spicelib\parser;..\src\include;..\src\include\cppduals;.;..\..\fftw-3.3-dll64;%(AdditionalIncludeDirectories) + ..\..\libsamplerate\include;..\..\libsndfile\include;..\src\maths\poly;..\src\frontend;..\src\spicelib\devices;tmp-bison;src\include;..\src\spicelib\parser;..\src\include;..\src\include\cppduals;.;..\..\fftw-3.3-dll64;%(AdditionalIncludeDirectories) _CRT_SECURE_NO_DEPRECATE;SIMULATOR;XSPICE;CONSOLE;CONFIG64;USE_OMP;HAVE_LIBFFTW3;%(PreprocessorDefinitions) false @@ -805,7 +814,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 /openmp:llvm %(AdditionalOptions) - psapi.lib;KLU_COMPLEX.lib;$(IntDir)libfftw3-3.lib;%(AdditionalDependencies) + sndfile.lib;samplerate.lib;psapi.lib;KLU_COMPLEX.lib;$(IntDir)libfftw3-3.lib;%(AdditionalDependencies) true Console 0 @@ -820,10 +829,12 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 MachineX64 true - KLU\x64\Release;%(AdditionalLibraryDirectories) + ../../libsamplerate/lib;../../libsndfile/lib;KLU\x64\Release;%(AdditionalLibraryDirectories) + copy /y "..\..\libsndfile\bin\sndfile.dll" "$(OutDir)" + copy /y "..\..\libsamplerate\bin\samplerate.dll" "$(OutDir)" copy /y "..\..\fftw-3.3-dll64\libfftw3-3.dll" "$(OutDir)" make-install-vngspice.bat $(OutDir) fftw 64 @@ -934,6 +945,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 + @@ -1351,6 +1363,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 + @@ -1563,6 +1576,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 + @@ -2732,6 +2746,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 + diff --git a/visualc/vngspice.vcxproj b/visualc/vngspice.vcxproj index 12cc794b7..399e66524 100644 --- a/visualc/vngspice.vcxproj +++ b/visualc/vngspice.vcxproj @@ -348,6 +348,8 @@ + copy /y "..\..\libsndfile\bin\sndfile.dll" "$(OutDir)" + copy /y "..\..\libsamplerate\bin\samplerate.dll" "$(OutDir)" make-install-vngspiced.bat $(OutDir) 64 @@ -383,7 +385,7 @@ Default true stdcpp14 - %(AdditionalOptions) + /openmp:llvm %(AdditionalOptions) sndfile.lib;samplerate.lib;psapi.lib;KLU_COMPLEX.lib;%(AdditionalDependencies) @@ -407,6 +409,8 @@ + copy /y "..\..\libsndfile\bin\sndfile.dll" "$(OutDir)" + copy /y "..\..\libsamplerate\bin\samplerate.dll" "$(OutDir)" make-install-vngspice.bat $(OutDir) 64 @@ -556,6 +560,8 @@ + copy /y "..\..\libsndfile\bin\sndfile.dll" "$(OutDir)" + copy /y "..\..\libsamplerate\bin\samplerate.dll" "$(OutDir)" make-install-vngspiced.bat $(OutDir) 64 @@ -726,6 +732,8 @@ + copy /y "..\..\libsndfile\bin\sndfile.dll" "$(OutDir)" + copy /y "..\..\libsamplerate\bin\samplerate.dll" "$(OutDir)" make-install-vngspice.bat $(OutDir) 64 @@ -779,7 +787,8 @@ ../../libsamplerate/lib;../../libsndfile/lib;KLU/Release/;%(AdditionalLibraryDirectories) - make-install-vngspice.bat $(OutDir) + + make-install-vngspice.bat $(OutDir) $(ProjectDir)ngspice-x86.exe.manifest @@ -837,6 +846,8 @@ + copy /y "..\..\libsndfile\bin\sndfile.dll" "$(OutDir)" + copy /y "..\..\libsamplerate\bin\samplerate.dll" "$(OutDir)" make-install-vngspice.bat $(OutDir) 64 @@ -869,6 +880,7 @@ + @@ -885,7 +897,6 @@ - @@ -1482,6 +1493,7 @@ + @@ -1498,7 +1510,6 @@ - From 288b2808abca9b9ee911b0d5d11a75ccb920d328 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 6 May 2026 16:14:10 +0200 Subject: [PATCH 05/23] Fix a bug reported by Dmitriy: use length-1 --- src/maths/cmaths/cmath2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/maths/cmaths/cmath2.c b/src/maths/cmaths/cmath2.c index d6ce651af..e03288459 100644 --- a/src/maths/cmaths/cmath2.c +++ b/src/maths/cmaths/cmath2.c @@ -404,7 +404,7 @@ cx_m3avg(void* data, short int type, int length, int* newlength, short int* newt realpart(c[0]) = realpart(cc[0]); - for (i = 0; i < length; i++) { + for (i = 0; i < nlen; i++) { realpart(c[i]) = (realpart(cc[i - 1]) + realpart(cc[i + 1])) / 4. + realpart(cc[i]) / 2.; imagpart(c[i]) = (imagpart(cc[i - 1]) + imagpart(cc[i + 1])) / 4. + imagpart(cc[i]) / 2.; } From 19217bf018ec223a4cc2cbb265d95321b645149e Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 8 May 2026 10:53:02 +0200 Subject: [PATCH 06/23] Fix a bug reported by Dmitriy, take 2: use 1 to length-1 --- src/maths/cmaths/cmath2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/maths/cmaths/cmath2.c b/src/maths/cmaths/cmath2.c index e03288459..0c16d4617 100644 --- a/src/maths/cmaths/cmath2.c +++ b/src/maths/cmaths/cmath2.c @@ -404,7 +404,7 @@ cx_m3avg(void* data, short int type, int length, int* newlength, short int* newt realpart(c[0]) = realpart(cc[0]); - for (i = 0; i < nlen; i++) { + for (i = 1; i < nlen; i++) { realpart(c[i]) = (realpart(cc[i - 1]) + realpart(cc[i + 1])) / 4. + realpart(cc[i]) / 2.; imagpart(c[i]) = (imagpart(cc[i - 1]) + imagpart(cc[i + 1])) / 4. + imagpart(cc[i]) / 2.; } From b4ecedc616fb372432764a2c3dded6d2307896eb Mon Sep 17 00:00:00 2001 From: dwarning Date: Sat, 9 May 2026 15:55:27 +0200 Subject: [PATCH 07/23] vdmos bulk diode with smart recovery model --- src/spicelib/devices/vdmos/vdmos.c | 3 + src/spicelib/devices/vdmos/vdmosacld.c | 14 +++ src/spicelib/devices/vdmos/vdmosask.c | 7 ++ src/spicelib/devices/vdmos/vdmosbindCSC.c | 24 +++++ src/spicelib/devices/vdmos/vdmosdefs.h | 31 +++++- src/spicelib/devices/vdmos/vdmosload.c | 115 +++++++++++++++++++--- src/spicelib/devices/vdmos/vdmosmask.c | 3 + src/spicelib/devices/vdmos/vdmosmpar.c | 4 + src/spicelib/devices/vdmos/vdmosset.c | 29 +++++- src/spicelib/devices/vdmos/vdmostrun.c | 2 + 10 files changed, 216 insertions(+), 16 deletions(-) diff --git a/src/spicelib/devices/vdmos/vdmos.c b/src/spicelib/devices/vdmos/vdmos.c index 3fc352631..e2243c8a8 100644 --- a/src/spicelib/devices/vdmos/vdmos.c +++ b/src/spicelib/devices/vdmos/vdmos.c @@ -31,6 +31,7 @@ IFparm VDMOSpTable[] = { /* parameters */ OP( "cgd", VDMOS_CAPGD, IF_REAL, "Gate-Drain capacitance"), OP( "cds", VDMOS_CAPDS, IF_REAL, "Drain-Source capacitance"), OP( "idio", VDMOS_CDIO, IF_REAL, "Body diode current"), + OP( "qdio", VDMOS_QDIO, IF_REAL, "Body diode charge"), OPU( "dnode", VDMOS_DNODE, IF_INTEGER, "Number of the drain node "), OPU( "gnode", VDMOS_GNODE, IF_INTEGER, "Number of the gate node "), @@ -115,6 +116,8 @@ IFparm VDMOSmPTable[] = { /* model parameters */ IOP("xti", VDIO_MOD_XTI, IF_REAL, "Body diode saturation current temperature exponent"), IOP("is", VDIO_MOD_IS, IF_REAL, "Body diode saturation current"), IOP("vj", VDIO_MOD_VJ, IF_REAL, "Body diode junction potential"), + IOP("vp", VDIO_MOD_VP, IF_REAL, "Soft reverse recovery parameter"), + /* body diode capacitance (e.g. source-drain capacitance) */ IOPA("cjo", VDIO_MOD_CJ, IF_REAL, "Zero-bias body diode junction capacitance"), diff --git a/src/spicelib/devices/vdmos/vdmosacld.c b/src/spicelib/devices/vdmos/vdmosacld.c index fd90caa66..fb6348c21 100644 --- a/src/spicelib/devices/vdmos/vdmosacld.c +++ b/src/spicelib/devices/vdmos/vdmosacld.c @@ -156,6 +156,20 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt) *(here->VDMOSSPtempPtr + 1) += xcsT; *(here->VDMOSGPtempPtr + 1) += xcgT; } + if ((here->VDIOqpNode > 0) && (model->VDIOsoftRevRecParam!=0) && (here->VDIOtTransitTime!=0)) { + /* QP subcircuit */ + double gdres= *(ckt->CKTstate0 + here->VDIOresConduct); + double fac = here->VDIOtTransitTime / model->VDIOsoftRevRecParam; + double dcrrdvd = fac * gdres; + *(here->VDIOqpQpPtr) += 1/model->VDIOsoftRevRecParam; + *(here->VDIOqpQpPtr + 1) += here->VDIOtTransitTime * ckt->CKTomega; + *(here->VDIOqpPosPrimePtr) += -dcrrdvd; + *(here->VDIOqpNegPtr) += dcrrdvd; + /* Gain of VCVS (1-vp)/tau * j*omega*tau = (1-vp) * j*omega */ + double xgain = (1 - model->VDIOsoftRevRecParam) * ckt->CKTomega; + *(here->VDIOposPrimeQpPtr + 1) += xgain; + *(here->VDIOnegQpPtr + 1) += -xgain; + } } } return(OK); diff --git a/src/spicelib/devices/vdmos/vdmosask.c b/src/spicelib/devices/vdmos/vdmosask.c index f29ee0d03..32fcb4286 100644 --- a/src/spicelib/devices/vdmos/vdmosask.c +++ b/src/spicelib/devices/vdmos/vdmosask.c @@ -118,6 +118,13 @@ VDMOSask(CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value, return(OK); case VDMOS_CDIO: value->rValue = *(ckt->CKTstate0 + here->VDIOcurrent); + if ((here->VDIOqpNode > 0) && (here->VDIOtTransitTime!=0)) + value->rValue += here->VDIOqpGain * *(ckt->CKTstate0 + here->VDIOcqcsr); + return(OK); + case VDMOS_QDIO: + value->rValue = *(ckt->CKTstate0+here->VDIOcapCharge); + if ((here->VDIOqpNode > 0) && (here->VDIOtTransitTime!=0)) + value->rValue += here->VDIOqpGain * *(ckt->CKTstate0 + here->VDIOsrcapCharge); return(OK); case VDMOS_CG : if (ckt->CKTcurrentAnalysis & DOING_AC) { diff --git a/src/spicelib/devices/vdmos/vdmosbindCSC.c b/src/spicelib/devices/vdmos/vdmosbindCSC.c index bd24b856d..43fd9727e 100644 --- a/src/spicelib/devices/vdmos/vdmosbindCSC.c +++ b/src/spicelib/devices/vdmos/vdmosbindCSC.c @@ -80,6 +80,14 @@ VDMOSbindCSC (GENmodel *inModel, CKTcircuit *ckt) CREATE_KLU_BINDING_TABLE(VDMOSDevTtpPtr, VDMOSDevTtpBinding, VDMOSvdevTbranch, VDMOStNodePrime); CREATE_KLU_BINDING_TABLE(VDMOSTpdevTPtr, VDMOSTpdevTBinding, VDMOStNodePrime, VDMOSvdevTbranch); } + /* rev-rec */ + if (model->VDIOsoftRevRecParamGiven && model->VDIOsoftRevRecParam!=0 && model->VDIOtransitTime!=0) { + CREATE_KLU_BINDING_TABLE(VDIOqpQpPtr , VDIOqpQpBinding , VDIOqpNode, VDIOqpNode); + CREATE_KLU_BINDING_TABLE(VDIOqpPosPrimePtr, VDIOqpPosPrimeBinding, VDIOqpNode, VDIOposPrimeNode); + CREATE_KLU_BINDING_TABLE(VDIOqpNegPtr , VDIOqpNegBinding , VDIOqpNode, VDMOSdNode); + CREATE_KLU_BINDING_TABLE(VDIOposPrimeQpPtr, VDIOposPrimeQpBinding, VDIOposPrimeNode, VDIOqpNode); + CREATE_KLU_BINDING_TABLE(VDIOnegQpPtr , VDIOnegQpBinding , VDMOSdNode, VDIOqpNode); + } } } @@ -155,6 +163,14 @@ VDMOSbindCSCComplex (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSDevTtpPtr, VDMOSDevTtpBinding, VDMOSvdevTbranch, VDMOStNodePrime); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTpdevTPtr, VDMOSTpdevTBinding, VDMOStNodePrime, VDMOSvdevTbranch); } + /* rev-rec */ + if (model->VDIOsoftRevRecParamGiven && model->VDIOsoftRevRecParam!=0 && model->VDIOtransitTime!=0) { + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDIOqpQpPtr , VDIOqpQpBinding , VDIOqpNode, VDIOqpNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDIOqpPosPrimePtr, VDIOqpPosPrimeBinding, VDIOqpNode, VDIOposPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDIOqpNegPtr , VDIOqpNegBinding , VDIOqpNode, VDMOSdNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDIOposPrimeQpPtr, VDIOposPrimeQpBinding, VDIOposPrimeNode, VDIOqpNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDIOnegQpPtr , VDIOnegQpBinding , VDMOSdNode, VDIOqpNode); + } } } @@ -230,6 +246,14 @@ VDMOSbindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSDevTtpPtr, VDMOSDevTtpBinding, VDMOSvdevTbranch, VDMOStNodePrime); CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTpdevTPtr, VDMOSTpdevTBinding, VDMOStNodePrime, VDMOSvdevTbranch); } + /* rev-rec */ + if (model->VDIOsoftRevRecParamGiven && model->VDIOsoftRevRecParam!=0 && model->VDIOtransitTime!=0) { + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDIOqpQpPtr , VDIOqpQpBinding , VDIOqpNode, VDIOqpNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDIOqpPosPrimePtr, VDIOqpPosPrimeBinding, VDIOqpNode, VDIOposPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDIOqpNegPtr , VDIOqpNegBinding , VDIOqpNode, VDMOSdNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDIOposPrimeQpPtr, VDIOposPrimeQpBinding, VDIOposPrimeNode, VDIOqpNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDIOnegQpPtr , VDIOnegQpBinding , VDMOSdNode, VDIOqpNode); + } } } diff --git a/src/spicelib/devices/vdmos/vdmosdefs.h b/src/spicelib/devices/vdmos/vdmosdefs.h index 5409a520f..bd283e12d 100644 --- a/src/spicelib/devices/vdmos/vdmosdefs.h +++ b/src/spicelib/devices/vdmos/vdmosdefs.h @@ -49,6 +49,7 @@ typedef struct sVDMOSinstance { int VDMOSgNodePrime; /* number of the internal gate node of the mosfet */ int VDMOStNodePrime; /* number of the internal temp node between voltage source and Rthca */ int VDIOposPrimeNode; /* number of the internal node of the body diode */ + int VDIOqpNode; /* number of soft recovery charge node */ int VDMOSvdevTbranch; /* equation number of branch equation added for cktTemp source */ @@ -97,6 +98,9 @@ typedef struct sVDMOSinstance { double VDIOtF2; double VDIOtF3; + /* rev-rec */ + double VDIOqpGain;/* converts iterated diffcharge current */ + double VDMOSTempSH; /* for portability of SH temp to noise analysis */ double VDMOSgmT; @@ -216,6 +220,13 @@ typedef struct sVDMOSinstance { (source node, diode prime node) */ double *VDIORPsPtr; /* pointer to sparse matrix element at (diode prime node, source node) */ + /* rev-rec */ + double *VDIOqpQpPtr; + double *VDIOqpPosPrimePtr; + double *VDIOqpNegPtr; + double *VDIOposPrimeQpPtr; + double *VDIOnegQpPtr; + /* self heating */ double *VDMOSTemptempPtr; /* Transistor thermal contribution */ double *VDMOSTempdpPtr; @@ -290,6 +301,12 @@ typedef struct sVDMOSinstance { BindElement *VDMOSDevTdevTBinding ; BindElement *VDMOSDevTtpBinding ; BindElement *VDMOSTpdevTBinding ; + /* rev-rec */ + BindElement *VDIOqpQpBinding; + BindElement *VDIOqpPosPrimeBinding; + BindElement *VDIOqpNegBinding; + BindElement *VDIOposPrimeQpBinding; + BindElement *VDIOnegQpBinding; #endif } VDMOSinstance ; @@ -319,8 +336,16 @@ typedef struct sVDMOSinstance { #define VDIOdIdio_dT VDMOSstates+ 17 -#define VDMOSnumStates 18 +/* rev-rec */ +#define VDIOsrcapCharge VDMOSstates+18 +#define VDIOsrcapCurrent VDMOSstates+19 +#define VDIOqp VDMOSstates+20 +#define VDIOresCurrent VDMOSstates+21 +#define VDIOresConduct VDMOSstates+22 +#define VDIOcqcsr VDMOSstates+23 +#define VDIOgqcsr VDMOSstates+24 +#define VDMOSnumStates 25 /* per model data */ @@ -385,6 +410,7 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */ double VDIOgradCoeffTemp2; double VDIOtrb1; double VDIOtrb2; + double VDIOsoftRevRecParam; /* Soft reverse recovery parameter VP */ double VDMOStcvth; double VDMOSrthjc; @@ -482,6 +508,7 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */ unsigned VDMOSid_maxGiven :1; unsigned VDMOSidr_maxGiven :1; unsigned VDMOSderatingGiven :1; + unsigned VDIOsoftRevRecParamGiven : 1; } VDMOSmodel; #ifndef NMOS @@ -546,6 +573,7 @@ enum { VDIO_MOD_XTI, VDIO_MOD_TRB1, VDIO_MOD_TRB2, + VDIO_MOD_VP, VDMOS_MOD_TCVTH, VDMOS_MOD_RTHJC, VDMOS_MOD_RTHCA, @@ -599,6 +627,7 @@ enum { VDMOS_QGD, VDMOS_CQGD, VDMOS_CDIO, + VDMOS_QDIO, VDMOS_SOURCERESIST, VDMOS_DRAINRESIST, }; diff --git a/src/spicelib/devices/vdmos/vdmosload.c b/src/spicelib/devices/vdmos/vdmosload.c index f5c0d4e8d..12f39be0c 100644 --- a/src/spicelib/devices/vdmos/vdmosload.c +++ b/src/spicelib/devices/vdmos/vdmosload.c @@ -710,11 +710,17 @@ bypass: double Ith=0.0, dIth_dT=0.0; double dIdio_dT=0.0, dIth_dVdio=0.0; double vrb=0.0, dIrb_dT=0.0, dIth_dVrb=0.0; + /* rev-rec */ + double cdres, gdres; + double vqp; + double capsr, gqcsr, cqcsr; #ifndef NOBYPASS double tol; /* temporary for tolerance calculations */ #endif + int revrec = ((here->VDIOqpNode > 0) && (model->VDIOsoftRevRecParam!=0) && (here->VDIOtTransitTime!=0)); + gbpr = here->VDIOtConductance; vt = CONSTKoverQ * Temp; @@ -725,13 +731,17 @@ bypass: Check_dio = 1; if (ckt->CKTmode & MODEINITSMSIG) { vd = *(ckt->CKTstate0 + here->VDIOvoltage); + vqp = *(ckt->CKTstate0 + here->VDIOqp); } else if (ckt->CKTmode & MODEINITTRAN) { vd = *(ckt->CKTstate1 + here->VDIOvoltage); + vqp = *(ckt->CKTstate1 + here->VDIOqp); } else if ((ckt->CKTmode & MODEINITJCT) && (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) { vd = here->VDIOinitCond; + vqp=0; } else if (ckt->CKTmode & MODEINITJCT) { vd = here->VDIOtVcrit; + vqp=0; } else { #ifndef PREDICTOR if (ckt->CKTmode & MODEINITPRED) { @@ -744,10 +754,20 @@ bypass: *(ckt->CKTstate1 + here->VDIOconduct); *(ckt->CKTstate0 + here->VDIOdIdio_dT) = *(ckt->CKTstate1 + here->VDIOdIdio_dT); + vqp = DEVpred(ckt,here->VDIOqp); + *(ckt->CKTstate0 + here->VDIOresCurrent) = + *(ckt->CKTstate1 + here->VDIOresCurrent); + *(ckt->CKTstate0 + here->VDIOresConduct) = + *(ckt->CKTstate1 + here->VDIOresConduct); + *(ckt->CKTstate0 + here->VDIOcqcsr) = + *(ckt->CKTstate1 + here->VDIOcqcsr); + *(ckt->CKTstate0 + here->VDIOgqcsr) = + *(ckt->CKTstate1 + here->VDIOgqcsr); } else { #endif /* PREDICTOR */ vd = model->VDMOStype * (*(ckt->CKTrhsOld + here->VDIOposPrimeNode) - *(ckt->CKTrhsOld + here->VDMOSdNode)); + vqp = model->VDMOStype * *(ckt->CKTrhsOld+here->VDIOqpNode); #ifndef PREDICTOR } #endif /* PREDICTOR */ @@ -776,6 +796,11 @@ bypass: cd = *(ckt->CKTstate0 + here->VDIOcurrent); gd = *(ckt->CKTstate0 + here->VDIOconduct); dIdio_dT= *(ckt->CKTstate0 + here->VDIOdIdio_dT); + vqp= *(ckt->CKTstate0 + here->VDIOqp); + cdres= *(ckt->CKTstate0 + here->VDIOresCurrent); + gdres= *(ckt->CKTstate0 + here->VDIOresConduct); + cqcsr= *(ckt->CKTstate0 + here->VDIOcqcsr); + gqcsr= *(ckt->CKTstate0 + here->VDIOgqcsr); goto load; } } @@ -833,6 +858,10 @@ bypass: cd = cdb + ckt->CKTgmin*vd; gd = gdb + ckt->CKTgmin; + cdres = cd; + gdres = gd; + cqcsr = 0; + gqcsr = 0; if ((ckt->CKTmode & (MODEDCTRANCURVE | MODETRAN | MODEAC | MODEINITSMSIG)) || ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) { @@ -853,14 +882,35 @@ bypass: (here->VDIOtGradingCoeff / (here->VDIOtJctPot + here->VDIOtJctPot))*(vd*vd - here->VDIOtDepCap*here->VDIOtDepCap)); deplcap = czof2*(here->VDIOtF3 + here->VDIOtGradingCoeff*vd / here->VDIOtJctPot); } - diffcharge = here->VDIOtTransitTime*cdb; - *(ckt->CKTstate0 + here->VDIOcapCharge) = - diffcharge + deplcharge; - diffcap = here->VDIOtTransitTime*gdb; - capd = diffcap + deplcap; + if (revrec) { + /* + soft recovery with TT!=0 - add only depletion capacitance. + */ + *(ckt->CKTstate0 + here->VDIOcapCharge) = deplcharge; - here->VDIOcap = capd; + capd = deplcap; + here->VDIOcap = capd; + /* + DIOcap is now equal only to depletion capacitance + overlap capacitance. + Diffusion capacitance is modelled via Qp so there is no clear way to define it here. + Now prepare the charge for the capacitor connected to the QP node + */ + *(ckt->CKTstate0 + here->VDIOsrcapCharge) = here->VDIOtTransitTime * vqp; + capsr = here->VDIOtTransitTime; + } else { + /* + no soft recovery due to TT=0 + */ + diffcharge = here->VDIOtTransitTime*cdb; + diffcap = here->VDIOtTransitTime*gdb; + *(ckt->CKTstate0 + here->VDIOcapCharge) = diffcharge + deplcharge; + capd = diffcap + deplcap; + here->VDIOcap = capd; + + *(ckt->CKTstate0 + here->VDIOsrcapCharge) = 0; + capsr = 0; + } /* * store small-signal parameters @@ -869,6 +919,7 @@ bypass: (!(ckt->CKTmode & MODEUIC))) { if (ckt->CKTmode & MODEINITSMSIG) { *(ckt->CKTstate0 + here->VDIOcapCurrent) = capd; + *(ckt->CKTstate0 + here->VDIOresConduct) = gdres; continue; } @@ -889,6 +940,21 @@ bypass: *(ckt->CKTstate1 + here->VDIOcapCurrent) = *(ckt->CKTstate0 + here->VDIOcapCurrent); } + if (revrec) { + /* soft recovery subcircuit */ + if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->VDIOsrcapCharge) = + *(ckt->CKTstate0 + here->VDIOsrcapCharge); + } + error = NIintegrate(ckt,&geq,&ceq,capsr,here->VDIOsrcapCharge); + if(error) return(error); + gqcsr = geq; + cqcsr = *(ckt->CKTstate0 + here->VDIOsrcapCurrent); + if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->VDIOsrcapCurrent) = + *(ckt->CKTstate0 + here->VDIOsrcapCurrent); + } + } } } @@ -905,6 +971,11 @@ bypass: *(ckt->CKTstate0 + here->VDIOcurrent) = cd; *(ckt->CKTstate0 + here->VDIOconduct) = gd; *(ckt->CKTstate0 + here->VDIOdIdio_dT) = dIdio_dT; + *(ckt->CKTstate0 + here->VDIOqp) = vqp; + *(ckt->CKTstate0 + here->VDIOresCurrent) = cdres; + *(ckt->CKTstate0 + here->VDIOresConduct) = gdres; + *(ckt->CKTstate0 + here->VDIOcqcsr) = cqcsr; + *(ckt->CKTstate0 + here->VDIOgqcsr) = gqcsr; #ifndef NOBYPASS load: @@ -926,14 +997,10 @@ load: /* * load current vector */ - cdeq = cd - gd*vd; - if (model->VDMOStype == 1) { - *(ckt->CKTrhs + here->VDMOSdNode) += cdeq; - *(ckt->CKTrhs + here->VDIOposPrimeNode) -= cdeq; - } else { - *(ckt->CKTrhs + here->VDMOSdNode) -= cdeq; - *(ckt->CKTrhs + here->VDIOposPrimeNode) += cdeq; - } + cdeq = model->VDMOStype * (cd - gd*vd); + *(ckt->CKTrhs + here->VDMOSdNode) += cdeq; + *(ckt->CKTrhs + here->VDIOposPrimeNode) -= cdeq; + if (selfheat) { *(ckt->CKTrhs + here->VDIOposPrimeNode) += dIdio_dT*delTemp - dIrb_dT*delTemp; *(ckt->CKTrhs + here->VDMOSdNode) += -dIdio_dT*delTemp; @@ -959,6 +1026,26 @@ load: (*(here->VDMOSStempPtr) += dIrb_dT); (*(here->VDMOSDtempPtr) += -dIdio_dT); } + if (revrec) { + /* QP subcircuit */ + double fac = here->VDIOtTransitTime / model->VDIOsoftRevRecParam; + double dcrrdvd = fac*gdres; + double ceqrr = -fac*cdres + cqcsr + dcrrdvd*vd - gqcsr*vqp; + double grr = 1/model->VDIOsoftRevRecParam; + *(ckt->CKTrhs + here->VDIOqpNode) -= model->VDMOStype * ceqrr; + *(here->VDIOqpQpPtr) += grr + gqcsr; + *(here->VDIOqpPosPrimePtr) += -dcrrdvd; + *(here->VDIOqpNegPtr) += dcrrdvd; + /* Contribution to diode current */ + here->VDIOqpGain = (1 - model->VDIOsoftRevRecParam) / here->VDIOtTransitTime; + /* Linear contribution -(1-vp)/tau*ddt(Qp) */ + double geqrrd = here->VDIOqpGain*gqcsr; + double ceqrrd = model->VDMOStype * (here->VDIOqpGain*cqcsr - geqrrd*vqp); + *(ckt->CKTrhs + here->VDIOposPrimeNode) += -ceqrrd; + *(ckt->CKTrhs + here->VDMOSdNode) += ceqrrd; + *(here->VDIOposPrimeQpPtr) += geqrrd; + *(here->VDIOnegQpPtr) += -geqrrd; + } } } return(OK); diff --git a/src/spicelib/devices/vdmos/vdmosmask.c b/src/spicelib/devices/vdmos/vdmosmask.c index f1c79ec04..94c1bde04 100644 --- a/src/spicelib/devices/vdmos/vdmosmask.c +++ b/src/spicelib/devices/vdmos/vdmosmask.c @@ -182,6 +182,9 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value) case VDMOS_MOD_TKSUBTHRES2: value->rValue = model->VDMOStksubthres2; return(OK); + case VDIO_MOD_VP: + value->rValue = model->VDIOsoftRevRecParam; + return(OK); /* SOA */ case VDMOS_MOD_VGS_MAX: value->rValue = model->VDMOSvgsMax; diff --git a/src/spicelib/devices/vdmos/vdmosmpar.c b/src/spicelib/devices/vdmos/vdmosmpar.c index 20ad96aa6..e26a3adc8 100644 --- a/src/spicelib/devices/vdmos/vdmosmpar.c +++ b/src/spicelib/devices/vdmos/vdmosmpar.c @@ -166,6 +166,10 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel) model->VDIOtranTimeTemp1 = 0; model->VDIOtranTimeTemp2 = 0; break; + case VDIO_MOD_VP: + model->VDIOsoftRevRecParam = value->rValue; + model->VDIOsoftRevRecParamGiven = TRUE; + break; case VDIO_MOD_EG: model->VDIOeg = value->rValue; model->VDIOegGiven = TRUE; diff --git a/src/spicelib/devices/vdmos/vdmosset.c b/src/spicelib/devices/vdmos/vdmosset.c index 0adfce318..863ae61d2 100644 --- a/src/spicelib/devices/vdmos/vdmosset.c +++ b/src/spicelib/devices/vdmos/vdmosset.c @@ -251,6 +251,10 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, if (model->VDIOjctSatCur < ckt->CKTepsmin) model->VDIOjctSatCur = ckt->CKTepsmin; + if (!model->VDIOsoftRevRecParamGiven) { + model->VDIOsoftRevRecParam = 0.0; + } + /* loop through all the instances of the model */ for (here = VDMOSinstances(model); here != NULL; here = VDMOSnextInstance(here)) { @@ -431,6 +435,16 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, here->VDMOStcaseNode = 0; } + /* rev-rec */ + if (model->VDIOsoftRevRecParamGiven && model->VDIOsoftRevRecParam!=0 && model->VDIOtransitTime!=0) { + if(here->VDIOqpNode == 0) { + error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "qp"); + if(error) return(error); + here->VDIOqpNode = tmp->number; + } + } else { + here->VDIOqpNode = 0; + } /* macro to make elements with built in test for out of memory */ #define TSTALLOC(ptr,first,second) \ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ @@ -487,11 +501,20 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ TSTALLOC(VDMOSTemptcasePtr, VDMOStempNode, VDMOStcaseNode); TSTALLOC(VDMOSTptpPtr, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */ TSTALLOC(VDMOSTptcasePtr, VDMOStNodePrime, VDMOStcaseNode); - TSTALLOC(VDMOSTcasetpPtr, VDMOStcaseNode, VDMOStNodePrime); + TSTALLOC(VDMOSTcasetpPtr, VDMOStcaseNode, VDMOStNodePrime); TSTALLOC(VDMOSDevTdevTPtr, VDMOSvdevTbranch, VDMOSvdevTbranch); /* Vsrc=cktTemp to gnd */ TSTALLOC(VDMOSDevTtpPtr, VDMOSvdevTbranch, VDMOStNodePrime); TSTALLOC(VDMOSTpdevTPtr, VDMOStNodePrime, VDMOSvdevTbranch); } + + /* rev-rec */ + if (model->VDIOsoftRevRecParamGiven && model->VDIOsoftRevRecParam!=0 && model->VDIOtransitTime!=0) { + TSTALLOC(VDIOqpQpPtr , VDIOqpNode, VDIOqpNode); + TSTALLOC(VDIOqpPosPrimePtr, VDIOqpNode, VDIOposPrimeNode); + TSTALLOC(VDIOqpNegPtr , VDIOqpNode, VDMOSdNode); + TSTALLOC(VDIOposPrimeQpPtr, VDIOposPrimeNode, VDIOqpNode); + TSTALLOC(VDIOnegQpPtr, VDMOSdNode, VDIOqpNode); + } } } return(OK); @@ -538,6 +561,10 @@ VDMOSunsetup(GENmodel *inModel, CKTcircuit *ckt) here->VDMOSvdevTbranch = 0; } + /* rev-rec */ + if (here->VDIOqpNode > 0) + CKTdltNNum(ckt, here->VDIOqpNode); + here->VDIOqpNode = 0; } } return OK; diff --git a/src/spicelib/devices/vdmos/vdmostrun.c b/src/spicelib/devices/vdmos/vdmostrun.c index 1b35dfffe..9d8a3e56f 100644 --- a/src/spicelib/devices/vdmos/vdmostrun.c +++ b/src/spicelib/devices/vdmos/vdmostrun.c @@ -24,6 +24,8 @@ VDMOStrunc(GENmodel *inModel, CKTcircuit *ckt, double *timeStep) CKTterr(here->VDMOSqgs,ckt,timeStep); CKTterr(here->VDMOSqgd,ckt,timeStep); CKTterr(here->VDIOcapCharge,ckt,timeStep); + if (model->VDIOsoftRevRecParam!=0 && here->VDIOtTransitTime!=0) + CKTterr(here->VDIOsrcapCharge,ckt,timeStep); } } return(OK); From 55dc72a01fda3c5091aef522df5383039b93fdf2 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 10 May 2026 11:07:31 +0200 Subject: [PATCH 08/23] Restrict time step equalising: don't do it with next breakpoit at TSTOP, as simulations with may fail with ever decreasing time step. --- src/spicelib/analysis/dctran.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/spicelib/analysis/dctran.c b/src/spicelib/analysis/dctran.c index 033ca6a61..ff203a082 100644 --- a/src/spicelib/analysis/dctran.c +++ b/src/spicelib/analysis/dctran.c @@ -586,11 +586,12 @@ resume: } /* Try to equalise the last two time steps before the breakpoint, if the second step would be smaller than CKTdelta otherwise.*/ - else if (ckt->CKTtime + 1.9 * ckt->CKTdelta > ckt->CKTbreaks[0]) { + else if (!(ckt->CKTbreaks[0] == ckt->CKTfinalTime) && ckt->CKTtime + 1.9 * ckt->CKTdelta > ckt->CKTbreaks[0]) { ckt->CKTsaveDelta = ckt->CKTdelta; ckt->CKTdelta = (ckt->CKTbreaks[0] - ckt->CKTtime) / 2.; #ifdef STEPDEBUG - fprintf(stdout, "Delta equalising step at time %e with delta %e\n", ckt->CKTtime, ckt->CKTdelta); + fprintf(stdout, "Delta equalising step at time %e with delta %e and breakpoint at %e\n", + ckt->CKTtime, ckt->CKTdelta, ckt->CKTbreaks[0]); #endif } From 0f693a55d0f7c236c3771855fefade871243609b Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Fri, 10 Apr 2026 17:08:13 +0100 Subject: [PATCH 09/23] Fix Bug #776 - "vlnggen fails to find verilator in MSYS2/MINGW64 on Windows 10". Patch by Chaojun. --- src/xspice/verilog/vlnggen | 17 ++++++++++++----- src/xspice/vhdl/ghnggen | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/xspice/verilog/vlnggen b/src/xspice/verilog/vlnggen index bd846d373..69cecb905 100644 --- a/src/xspice/verilog/vlnggen +++ b/src/xspice/verilog/vlnggen @@ -36,16 +36,23 @@ else setcs cflags="--CFLAGS -fpic" // For g++ end -if $oscompiled = 2 | $oscompiled = 3 | $oscompiled = 8 // Windows +if $oscompiled = 1 | $oscompiled = 2 | $oscompiled = 8 // Windows (MINGW, Cygwin, MSVC) set windows=1 set dirsep1="\\" set dirsep2="/" - set vloc="C:/mingw64/bin/verilator" // Expected location on Windows - set run_verilator="perl $vloc" // Verilator is a Perl script + if $oscompiled = 1 // MINGW: verilator is a Perl wrapper, needs MSYS2 shell + set run_verilator="sh -c \"verilator" + set run_verilator_close="\"" + else + set vloc="C:/mingw64/bin/verilator" // Expected location on Windows + set run_verilator="perl $vloc" // Verilator is a Perl script + set run_verilator_close="" + end else set windows=0 set dirsep1="/" set run_verilator=verilator + set run_verilator_close="" end if $oscompiled = 7 // MacOS @@ -139,7 +146,7 @@ setcs prefix="Vlng" // Run Verilator on the given input files. -shell $run_verilator --Mdir $objdir --prefix $prefix $cflags --cc $argv +shell $run_verilator --Mdir $objdir --prefix $prefix $cflags --cc $argv$run_verilator_close if $shellstatus > 0 quit end @@ -304,7 +311,7 @@ end shell $run_verilator --Mdir $objdir --prefix $prefix $include $cflags + --cc --build --exe -+ $fn_main $fn $argv ++ $fn_main $fn $argv$run_verilator_close strcmp bad "$shellstatus" "0" diff --git a/src/xspice/vhdl/ghnggen b/src/xspice/vhdl/ghnggen index 800340219..211218984 100644 --- a/src/xspice/vhdl/ghnggen +++ b/src/xspice/vhdl/ghnggen @@ -23,7 +23,7 @@ end set noglob -if $oscompiled = 2 | $oscompiled = 3 | $oscompiled = 8 // Windows +if $oscompiled = 1 | $oscompiled = 2 | $oscompiled = 8 // Windows (MINGW, Cygwin, MSVC) set windows=1 set dirsep1="\\" set dirsep2="/" From 9ad729ec15bc1b13d52aa448647c7d36ccb599c4 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Thu, 16 Apr 2026 10:42:04 +0100 Subject: [PATCH 10/23] CMPP: also skip over single-quoted strings in code-model source. --- src/xspice/cmpp/mod_lex.l | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xspice/cmpp/mod_lex.l b/src/xspice/cmpp/mod_lex.l index 14b1f9043..7cf0acdb9 100644 --- a/src/xspice/cmpp/mod_lex.l +++ b/src/xspice/cmpp/mod_lex.l @@ -90,6 +90,7 @@ Z [0-9A-Za-z_] } \"(\\.|[^"\\])*\" {return TOK_IDENTIFIER;} /* Literal string. */ +\'(\\.|[^'\\])*\' {return TOK_IDENTIFIER;} ARGS {return TOK_ARGS;} INIT {return TOK_INIT;} From 06afc7c1daf253c1178f8b11d245c9c6a43b3630 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Thu, 7 May 2026 18:05:43 +0100 Subject: [PATCH 11/23] Command "setplot new" may set name and description of the new plot. --- src/frontend/commands.c | 4 ++-- src/frontend/postcoms.c | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/frontend/commands.c b/src/frontend/commands.c index eb03fb159..c4e592246 100644 --- a/src/frontend/commands.c +++ b/src/frontend/commands.c @@ -188,7 +188,7 @@ struct comm spcp_coms[] = { NULL, "[plotname] ... : Throw away all the data in the plot." } , { "setplot", com_splot, FALSE, TRUE, - { 0400, 0, 0, 0 }, E_DEFHMASK, 0, 1, + { 0400, 0, 0, 0 }, E_DEFHMASK, 0, 4, NULL, "[plotname] : Change the current working plot." } , { "setcirc", com_scirc, TRUE, FALSE, @@ -734,7 +734,7 @@ struct comm nutcp_coms[] = { NULL, "[plotname] ... : Throw away all the data in the plot." } , { "setplot", com_splot, FALSE, TRUE, - { 0400, 0, 0, 0 }, E_DEFHMASK, 0, 1, + { 0400, 0, 0, 0 }, E_DEFHMASK, 0, 4, NULL, "[plotname] : Change the current working plot." } , { "setcirc", com_scirc, TRUE, FALSE, diff --git a/src/frontend/postcoms.c b/src/frontend/postcoms.c index a346d8e8b..248aa5a99 100644 --- a/src/frontend/postcoms.c +++ b/src/frontend/postcoms.c @@ -1177,6 +1177,17 @@ DelPlotWindows(struct plot *pl) #endif } +/* Helper for com_splot(). */ + +static int new_str(wordlist **pwl, char **ps) +{ + *pwl = (*pwl)->wl_next; + if (!*pwl) + return 1; + tfree(*ps); + *ps = copy((*pwl)->wl_word); + return 0; +} /* * command 'setplot' @@ -1194,6 +1205,18 @@ com_splot(wordlist *wl) if (wl) { plot_setcur(wl->wl_word); + + if (cieq(wl->wl_word, "new")) { + /* The user may also supply, name, title and typename strings. + * The typename is the 'true name' used in commands! + */ + + if (new_str(&wl, &plot_cur->pl_typename)) + return; + if (new_str(&wl, &plot_cur->pl_title)) + return; + new_str(&wl, &plot_cur->pl_name); + } return; } From 07ca1354ebf93e350cd962a61a6922f155723a46 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Thu, 7 May 2026 18:07:53 +0100 Subject: [PATCH 12/23] Disable output redirection for "let" so that normal comparison operators may be used. --- src/frontend/control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/control.c b/src/frontend/control.c index 9c982ef23..5349c5063 100644 --- a/src/frontend/control.c +++ b/src/frontend/control.c @@ -59,7 +59,7 @@ int stackp = 0; */ /* no redirection after the following commands (we may need more to add here!) */ -static char *noredirect[] = { "stop", "define", "circbyline", NULL}; +static char *noredirect[] = { "if", "let", "stop", "define", "circbyline", NULL}; /* This function returns the (first) structure wit the label s */ From 93567da529ea46fcecebd3694a21cb906ec3cb7c Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Thu, 7 May 2026 18:14:31 +0100 Subject: [PATCH 13/23] Do not report an error when correctly indexing a length-1 vector. --- src/frontend/evaluate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/frontend/evaluate.c b/src/frontend/evaluate.c index 01127e1d0..4290a4ee3 100644 --- a/src/frontend/evaluate.c +++ b/src/frontend/evaluate.c @@ -720,15 +720,15 @@ op_ind(struct pnode *arg1, struct pnode *arg2) /* Just in case we were sloppy */ v->v_numdims = 1; v->v_dims[0] = v->v_length; - if (v->v_length <= 1) { - fprintf(cp_err, "Error: indexing a scalar (%s)\n", + if (v->v_length < 1) { + fprintf(cp_err, "Error: indexing empty vector (%s)\n", v->v_name); return (NULL); } } if (ind->v_length != 1) { - fprintf(cp_err, "Error:strchr %s is not of length 1\n", + fprintf(cp_err, "Error: index vector %s is not of length 1\n", ind->v_name); return (NULL); } From 954242616dc0f3c2b77a378e2d10d38d954383dc Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Thu, 7 May 2026 18:24:12 +0100 Subject: [PATCH 14/23] Filter duplicate entries in sourcepath. --- src/frontend/inpcom.c | 51 +++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 357e38561..3551975ef 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -9903,7 +9903,7 @@ static int inp_poly_2g6_compat(struct card* deck) { int add_to_sourcepath(const char* filepath, const char* path) { char* fpath=NULL; - wordlist *addwl=NULL, *newwl=NULL, *startwl, *endwl; + wordlist *addwl=NULL, *startwl, *endwl; if ((filepath && path) || (!filepath && !path)) return 1; @@ -9919,24 +9919,51 @@ int add_to_sourcepath(const char* filepath, const char* path) else return 1; - startwl = newwl = wl_from_string("sourcepath=("); - endwl = wl_from_string(")"); + startwl = wl_from_string("sourcepath=("); + + /* Add expanded fpath to 'sourcepath' list variable. */ - /* add fpath to 'sourcepath' list variable */ if (cp_getvar("sourcepath", CP_LIST, NULL, 0)) { - wordlist* wl = vareval("sourcepath"); - wl_append(newwl, wl); - } - /* new sourcepath variable */ - else { + wordlist *wl, *scan, *scan_new, *next; + + wl = vareval("sourcepath"); + + /* Are any new paths already in the list? */ + + for (scan = wl; scan; scan = scan->wl_next) { + scan_new = addwl; + while (scan_new) { + next = scan_new->wl_next; + if (!strcmp(scan->wl_word, scan_new->wl_word)) { + /* Entries match. */ + + if (scan_new == addwl) + addwl = next; + wl_delete_slice(scan_new, next); + } + scan_new = next; + } + if (!addwl) { + wl_free(wl); + tfree(fpath); + return 0; // Not an error. + } + } + wl_append(startwl, wl); + } else { + /* New sourcepath variable, why not use addwl here? */ + wordlist* wl = wl_from_string(fpath); - wl_append(newwl, wl); + wl_append(startwl, wl); } /* add new entry */ if (addwl) - wl_append(newwl, addwl); + wl_append(startwl, addwl); + /* add end section */ - wl_append(newwl, endwl); + + endwl = wl_from_string(")"); + wl_append(startwl, endwl); // fprintf(stdout, "Added to variable 'sourcepath':\n %s\n", fpath); From 785be3194c3ae68d7e6f0b9c5470646ac48107bd Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Thu, 7 May 2026 18:28:14 +0100 Subject: [PATCH 15/23] Fix two bugs in the "let" command: "let plot.vec = ..." fails when creating a new vector; if the new vector does not exist, "let" may modify a "const" value. It is likely that existing scripts rely on the second one, so variable "sanelet" must be set to enable the fix. --- src/frontend/com_let.c | 95 +++++++++++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 29 deletions(-) diff --git a/src/frontend/com_let.c b/src/frontend/com_let.c index 794311ba4..eae479e88 100644 --- a/src/frontend/com_let.c +++ b/src/frontend/com_let.c @@ -42,16 +42,12 @@ static char* kivec(char* rhs); */ void com_let(wordlist *wl) { - char *p, *s; + char *line, *vec_name, *rhs, *plot_name, *index_start; index_range_t p_dst_index[MAXDIMS]; int n_dst_index; struct pnode *names = (struct pnode *) NULL; struct dvec *vec_src = (struct dvec *) NULL; - char *rhs; - - /* Start of index NULL is a flag for no index */ - char *p_index_start = (char *) NULL; - + struct plot *tplot; /* let with no arguments is equivalent to display */ if (!wl) { @@ -59,24 +55,26 @@ void com_let(wordlist *wl) return; } - p = wl_flatten(wl); /* Everything after let -> string */ + line = wl_flatten(wl); /* Everything after let -> string */ /* Separate vector name from RHS of assignment */ + n_dst_index = 0; - if ((rhs = strchr(p, '=')) == (char *) NULL) { + if ((rhs = strchr(line, '=')) == (char *) NULL) { fprintf(cp_err, "Error: bad let syntax\n"); - txfree(p); + txfree(line); return; } *rhs++ = '\0'; + vec_name = line; /* Handle indexing. At start, p = LHS; rhs = RHS. If index is found * p = leftmost part of orig p up to first '['. So p always * becomes the vector name, possibly with some spaces at the end. */ - if ((s = strchr(p, '[')) != NULL) { + + if ((index_start = strchr(vec_name, '[')) != NULL) { /* This null makes the dest vector name a null-terminated string */ - *s = '\0'; - p_index_start = s + 1; + *index_start++ = '\0'; } /* "Remove" any spaces at the end of the vector name at p by stepping @@ -85,22 +83,51 @@ void com_let(wordlist *wl) * the original NULL if there was no whitespace) with a NULL. */ { char *q; - for (q = p + strlen(p) - 1; *q <= ' ' && p <= q; q--) { - ; - } + for (q = vec_name + strlen(vec_name) - 1; + *q <= ' ' && vec_name <= q; + q--) ; *++q = '\0'; } /* Sanity check */ - if (eq(p, "all") || strchr(p, '@') || *p == '\0' || isdigit_c(*p)) { - fprintf(cp_err, "Error: bad variable name \"%s\"\n", p); + if (eq(vec_name, "all") || strchr(vec_name, '@') || + *vec_name == '\0' || isdigit_c(*vec_name)) { + fprintf(cp_err, "Error: bad variable name \"%s\"\n", vec_name); goto quit; } /* Locate the vector being assigned values. If NULL, the vector * does not exist */ - struct dvec *vec_dst = vec_get(p); - if (vec_dst != (struct dvec *) NULL) { + struct dvec *vec_dst = vec_get(vec_name); + + if (vec_dst == (struct dvec *) NULL) { + /* If the name has a dot (plotname.vecname), remove the plotname + * and check it. + */ + + plot_name = vec_name; + vec_name = strchr(vec_name, '.'); + if (vec_name) { + *vec_name++ = '\0'; + tplot = get_plot(plot_name); + if (!tplot) { + txfree(line); + return; // Error reported by get_plot(). + } + } else { + vec_name = plot_name; + tplot = NULL; + } + } else if (vec_dst->v_plot != plot_cur && plot_cur) { + /* Found a vector in another plot, possibly 'const'. + * Many scripts likely depend on this so ignore only when + * explicitly requested. + */ + + if (!strchr(vec_name, '.') && cp_getvar("sanelet", CP_BOOL, NULL, 0)) + vec_dst = (struct dvec *) NULL; + tplot = NULL; + } else { /* Fix-up dimension count and limit. Sometimes these are * not set properly. If not set, give the vector 1 dimension and * ensure the right length */ @@ -113,7 +140,7 @@ void com_let(wordlist *wl) } /* If the vector was indexed, find the indices */ - if (p_index_start != (char *) NULL) { + if (index_start != (char *) NULL) { /* Test for an attempt to index an undefined vector */ if (vec_dst == (struct dvec *) NULL) { fprintf(cp_err, @@ -121,8 +148,8 @@ void com_let(wordlist *wl) goto quit; } - if (find_indices(p_index_start, vec_dst, p_dst_index) != 0) { - txfree(p); + if (find_indices(index_start, vec_dst, p_dst_index) != 0) { + txfree(line); return; } n_dst_index = vec_dst->v_numdims; @@ -160,10 +187,12 @@ void com_let(wordlist *wl) } else goto quit; - } - /* evaluate the rhs expression as usual, math characters may not be used in vec names, - the expression parser then will complain about a syntax error */ - else { + } else { + /* Evaluate the rhs expression as usual, math characters may not + * be used in vec names, so the expression parser then will complain + * about a syntax error. + */ + if ((names = ft_getpnames_from_string( rhs, TRUE)) == (struct pnode*)NULL) { fprintf(cp_err, "Error: RHS \"%s\" invalid\n", rhs); @@ -192,13 +221,21 @@ void com_let(wordlist *wl) if (vec_dst == (struct dvec *) NULL) { /* p is not an existing vector. So make a new one equal to vec_src * in all ways, except enforce that it is a permanent vector. */ - vec_dst = dvec_alloc(copy(p), + vec_dst = dvec_alloc(copy(vec_name), vec_src->v_type, vec_src->v_flags | VF_PERMANENT, vec_src->v_length, NULL); copy_vector_data(vec_dst, vec_src); - vec_new(vec_dst); /* Add tp current plot */ + if (tplot) { + struct plot *cplot = plot_cur; + + plot_cur = tplot; + vec_new(vec_dst); + plot_cur = cplot; + } else { + vec_new(vec_dst); /* Add to current plot */ + } cp_addkword(CT_VECTOR, vec_dst->v_name); } /* end of case of new vector */ else { @@ -293,7 +330,7 @@ quit: /* frees also vec_src, if pnode `names' is simple value */ free_pnode(names); } - txfree(p); + txfree(line); } /* end of function com_let */ From 96c81fd58c5a34ff4ba2abd88a0d0cb1d9f403d2 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Thu, 7 May 2026 18:36:54 +0100 Subject: [PATCH 16/23] Add CPP macros to allow XSPICE macros to be used in local functions. --- src/include/ngspice/cm.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/include/ngspice/cm.h b/src/include/ngspice/cm.h index 1f3854e3a..59a0b60bd 100644 --- a/src/include/ngspice/cm.h +++ b/src/include/ngspice/cm.h @@ -79,6 +79,14 @@ NON-STANDARD FEATURES #endif #endif +/* Define the type and standard name of the single argument to code-model + * functions as macros. These may be used to enable the use XSPICE macros + * in other functions of the code model. + */ + +#define XSPICE_ARG_TYPE Mif_Private_t * +#define XSPICE_ARG mif_private + /* * type safe variants of the functions for char arguments */ From 7cba7ddee053198ee3dc344470139f858cd913df Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Wed, 6 May 2026 17:55:52 +0100 Subject: [PATCH 17/23] Allow building without soundfile libraries. --- src/frontend/commands.c | 36 +++++++++++++++++------------- src/frontend/dotcards.c | 2 ++ src/frontend/postcoms.c | 2 ++ src/frontend/sndprint.c | 4 +++- src/spicelib/devices/vsrc/vsjack.c | 16 ++++++++++++- 5 files changed, 42 insertions(+), 18 deletions(-) diff --git a/src/frontend/commands.c b/src/frontend/commands.c index c4e592246..027b9a0d9 100644 --- a/src/frontend/commands.c +++ b/src/frontend/commands.c @@ -248,14 +248,16 @@ struct comm spcp_coms[] = { { 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS, arg_print, "[col] expr ... : Print vector values." } , - { "sndprint", com_sndprint, FALSE, FALSE, - { 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS, - arg_print, - "[col] expr ... : Print vector values." }, - { "sndparam", com_sndparam, FALSE, FALSE, - { 1, 1, 1, 1 }, E_BEGINNING | E_NOPLOTS, 1, LOTS, - arg_load, - "file samplerate : set sndprint parameters." }, +#if defined(HAVE_LIBSNDFILE) && defined(HAVE_LIBSAMPLERATE) + { "sndprint", com_sndprint, FALSE, FALSE, + { 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS, + arg_print, + "[col] expr ... : Print vector values." }, + { "sndparam", com_sndparam, FALSE, FALSE, + { 1, 1, 1, 1 }, E_BEGINNING | E_NOPLOTS, 1, LOTS, + arg_load, + "file samplerate : set sndprint parameters." }, +#endif #ifdef XSPICE { "esave", EVTsave, FALSE, TRUE, { 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS, @@ -793,14 +795,16 @@ struct comm nutcp_coms[] = { { 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS, arg_print, "[col] expr ... : Print vector values." } , - { "sndprint", com_sndprint, FALSE, FALSE, - { 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS, - arg_print, - "[col] expr ... : Print vector values." }, - { "sndparam", com_sndparam, FALSE, FALSE, - { 1, 1, 1, 1 }, E_BEGINNING | E_NOPLOTS, 1, LOTS, - arg_load, - "file samplerate : set sndprint parameters." }, +#if defined(HAVE_LIBSNDFILE) && defined(HAVE_LIBSAMPLERATE) + { "sndprint", com_sndprint, FALSE, FALSE, + { 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS, + arg_print, + "[col] expr ... : Print vector values." }, + { "sndparam", com_sndparam, FALSE, FALSE, + { 1, 1, 1, 1 }, E_BEGINNING | E_NOPLOTS, 1, LOTS, + arg_load, + "file samplerate : set sndprint parameters." }, +#endif { "load", com_load, FALSE, TRUE, { 1, 1, 1, 1 }, E_BEGINNING | E_NOPLOTS, 1, LOTS, arg_load, diff --git a/src/frontend/dotcards.c b/src/frontend/dotcards.c index 6dc2bc034..60a3e1ac6 100644 --- a/src/frontend/dotcards.c +++ b/src/frontend/dotcards.c @@ -355,6 +355,7 @@ ft_cktcoms(bool terse) fprintf(cp_err, "Error: .plot: no %s analysis found.\n", plottype); } +#if defined(HAVE_LIBSNDFILE) && defined(HAVE_LIBSAMPLERATE) } else if (eq(command->wl_word, ".sndparam")) { if (terse) { fprintf(cp_out, ".sndparam line ignored since rawfile was produced.\n"); @@ -390,6 +391,7 @@ ft_cktcoms(bool terse) if (!found) fprintf(cp_err, "Error: .sndprint: no %s analysis found.\n", plottype); } +#endif // Sound file support } else if (ciprefix(".four", command->wl_word)) { if (terse) { fprintf(cp_out, diff --git a/src/frontend/postcoms.c b/src/frontend/postcoms.c index 248aa5a99..425587071 100644 --- a/src/frontend/postcoms.c +++ b/src/frontend/postcoms.c @@ -430,6 +430,7 @@ done: tfree(buf2); } +#if defined(HAVE_LIBSNDFILE) && defined(HAVE_LIBSAMPLERATE) /* tweaked version of print - write sound-files */ @@ -558,6 +559,7 @@ com_sndparam(wordlist* wl) snd_configure(file, srate, fmt, mult, off, oversampling); return; } +#endif // HAVE_LIBSNDFILE /* Write out some data into a ngspice raw file with 'write filename expr'. diff --git a/src/frontend/sndprint.c b/src/frontend/sndprint.c index e35b2dec5..9174a7c3b 100644 --- a/src/frontend/sndprint.c +++ b/src/frontend/sndprint.c @@ -1,12 +1,13 @@ #include #include -#include #include #include #include #include "sndprint.h" #include "ngspice/ngspice.h" +#if defined(HAVE_LIBSNDFILE) && defined(HAVE_LIBSAMPLERATE) +#include static int o_samplerate = 48000; static int o_sndfmt = (SF_FORMAT_WAV | SF_FORMAT_PCM_24); @@ -323,3 +324,4 @@ double snd_get_samplerate(void) { /* vi:set ts=8 sts=2 sw=2: */ +#endif // HAVE_LIBSNDFILE diff --git a/src/spicelib/devices/vsrc/vsjack.c b/src/spicelib/devices/vsrc/vsjack.c index 06bf3b45a..9988fc695 100644 --- a/src/spicelib/devices/vsrc/vsjack.c +++ b/src/spicelib/devices/vsrc/vsjack.c @@ -2,6 +2,9 @@ #include #include +#include "ngspice/ngspice.h" + +#if defined(HAVE_LIBSNDFILE) && defined(HAVE_LIBSAMPLERATE) /////// SNDFILE /////// #include #include @@ -12,7 +15,6 @@ // the whole audio file, do it in smaller chunks #define VS_RESAMPLING_CHUNK 1024 -#include "ngspice/ngspice.h" #include "vsjack.h" extern char* inp_pathresolve(const char* name); @@ -229,3 +231,15 @@ int vsjack_open(int d, char *file, int channel, double oversampling) { } /* vi:set ts=8 sts=4 sw=4: */ +#else // not HAVE_LIBSNDFILE + +double vsjack_get_value(int d, double time, double time_offset) { + return 0; +} + +int vsjack_open(int d, char *file, int channel, double oversampling) { + fprintf(stderr, "Error: Ngspice built without soundfile support.\n"); + controlled_exit(1); + return -1; +} +#endif From 201ae8cac7216b9743c43d9c7a75b72b54181647 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 10 May 2026 16:35:28 +0200 Subject: [PATCH 18/23] Allow building without soundfile libraries. Emit error message if soundfile source is requested. --- src/spicelib/devices/vsrc/vsrcpar.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/spicelib/devices/vsrc/vsrcpar.c b/src/spicelib/devices/vsrc/vsrcpar.c index 94f1a5cae..0b235d279 100644 --- a/src/spicelib/devices/vsrc/vsrcpar.c +++ b/src/spicelib/devices/vsrc/vsrcpar.c @@ -296,6 +296,7 @@ VSRCparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select) break; case VSRC_SOUND: { +#if defined(HAVE_LIBSNDFILE) && defined(HAVE_LIBSAMPLERATE) int id, channel; double oversampling; here->VSRCfunctionType = SOUND; @@ -315,6 +316,10 @@ VSRCparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select) oversampling = here->VSRCcoeffs[5]; vsjack_open(id, jfile, channel, oversampling); tfree(jfile); +#else + fprintf(stderr, "\nError: ngspice is compiled without soundfile support!\n"); + controlled_exit(EXIT_BAD); +#endif } break; From 760b12b14eee737f8de02dc26c954521c8e518eb Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 10 May 2026 16:36:11 +0200 Subject: [PATCH 19/23] Enable soundfile support for VS2022/2026 builds. --- visualc/src/include/ngspice/config.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/visualc/src/include/ngspice/config.h b/visualc/src/include/ngspice/config.h index c378057e0..323d278b1 100644 --- a/visualc/src/include/ngspice/config.h +++ b/visualc/src/include/ngspice/config.h @@ -5,8 +5,9 @@ /* select major ngspice options */ /* to undefine, replace #define by #undef and comment out */ -/* S parameter analysis */ -#define RFSPICE 1 +/* Define if you want soundfile (*.wav) support */ +#define HAVE_LIBSNDFILE +#define HAVE_LIBSAMPLERATE /* Define if you want PSS analysis */ #define WITH_PSS /**/ @@ -28,6 +29,9 @@ /**********************************************************************/ /********* Don't change entries found below ***************************/ +/* S parameter analysis */ +#define RFSPICE 1 + /* The xspice enhancements */ #define XSPICE 1 From 95cf8738da612a0cfa55be97a2b86fe04dc84e93 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 10 May 2026 16:36:35 +0200 Subject: [PATCH 20/23] Avoid compiler warning (VS2022) --- src/frontend/com_let.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/com_let.c b/src/frontend/com_let.c index eae479e88..71e923f58 100644 --- a/src/frontend/com_let.c +++ b/src/frontend/com_let.c @@ -47,7 +47,7 @@ void com_let(wordlist *wl) int n_dst_index; struct pnode *names = (struct pnode *) NULL; struct dvec *vec_src = (struct dvec *) NULL; - struct plot *tplot; + struct plot *tplot = NULL; /* let with no arguments is equivalent to display */ if (!wl) { From 3dce275b164272a0a53aa31f8289eb960c77de89 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 11 May 2026 15:09:32 +0200 Subject: [PATCH 21/23] reset time to 0 upon initialisation of shared ngspice --- src/frontend/resource.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/frontend/resource.c b/src/frontend/resource.c index 303cb65de..acec7db42 100644 --- a/src/frontend/resource.c +++ b/src/frontend/resource.c @@ -74,6 +74,7 @@ init_rlimits(void) void init_time(void) { + timebegin.secs = 0; perf_timer_get_time(&timebegin); } From 6b7cde537dd8e309d3981b95b18b668692b1781d Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 11 May 2026 15:10:21 +0200 Subject: [PATCH 22/23] Reset plot list to const plot. --- src/frontend/mw_coms.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/frontend/mw_coms.c b/src/frontend/mw_coms.c index aebf6cf18..c7eb46075 100644 --- a/src/frontend/mw_coms.c +++ b/src/frontend/mw_coms.c @@ -14,6 +14,8 @@ #include "runcoms.h" #include "spiceif.h" +#include "plotting/plotting.h" + /* Clears ckt and removes current circ. form database */ void @@ -82,7 +84,7 @@ com_removecirc(wordlist *wl) /* If the plot is the first one and there are no other plots */ if (!plot_list->pl_next && strcmp(plot_list->pl_title, namecircuit) == 0) - plot_list = NULL; + plot_list = &constantplot; else if (plot_list && plot_list->pl_next) { p = plot_list; From 7911d0870d665c0a11b3c1d917cc91c6a634d37f Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 15 May 2026 01:00:56 +0200 Subject: [PATCH 23/23] Correct paths in example file --- examples/wave/sndtst.cir | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/wave/sndtst.cir b/examples/wave/sndtst.cir index 8108d7231..4d0f422bb 100644 --- a/examples/wave/sndtst.cir +++ b/examples/wave/sndtst.cir @@ -1,9 +1,9 @@ simple audio test -V_V2 1 0 file ..\exampleswav\gits.wav snd 0 0 1.0 0 0 32 +V_V2 1 0 file gits.wav snd 0 0 1.0 0 0 32 R_R1 1 0 1M -.sndparam ..\exampleswav\test-io.wav 48000 wav24 1.0 0.0 1.0 +.sndparam test-io.wav 48000 wav24 1.0 0.0 1.0 .sndprint tran v(1) .tran 2.08333e-05 2.0 0 2.08333e-05 .op @@ -11,7 +11,7 @@ R_R1 1 0 1M .control if $?batchmode else - sndparam ..\exampleswav\test-io.wav 48000 wav24 1.0 0.0 1.0 + sndparam $inputdir/test-io.wav 48000 wav24 1.0 0.0 1.0 tran 6.5104166e-07 3.0 0.1 6.5104166e-07 rusage sndprint v(1)