diff --git a/INSTALL b/INSTALL index 8555ceea3..3a67481b8 100644 --- a/INSTALL +++ b/INSTALL @@ -18,7 +18,7 @@ Table of contents 1.5.1 Most useful options 1.5.2 Options Specific to Enable Ngspice as a shared library 1.5.3 Options Useful for Debugging Ngspice - 1.6 Installation on Red Hat, Oracle or Centos Linux + 1.6 Installation on Red Hat, Oracle or CentOS Linux 2 Compilers and Options 3 Compiling For Multiple Architectures 4 Installation Names @@ -67,32 +67,40 @@ This file describes the procedures to install ngspice from sources. If libfftw is detected on your system, it will be used instead of the internal fft algorithms. - If you want to compile the source from the git repository you need - additional software: autoconf, automake, libtool. + If you want to compile the source from the git repository, or if you want to + use the compile script ./compile_linux.sh, you will need additional software: + autoconf, automake, libtool. The following software may be needed when enabling additional features: - editline, tcl/tk, adms. + editline, tcl/tk. - Please have a look at the actual ngspice manual, downloadable at + Please have a look at the current ngspice manual, downloadable at http://ngspice.sourceforge.net/docs.html, which gives you much more information on ngspice and its usage. For compiling ngspice as a shared library, see section 1.4. -1.2 Install from tarball (e.g. ngspice-36.tar.gz) +1.2 Install from tarball (e.g. ngspice-40.tar.gz) This covers installation from a release distribution (for example - ngspice-36.tar.gz, the so called tar ball). + ngspice-40.tar.gz, the so called tar ball). - After downloading the tar ball to a local directory unpack it using: + After downloading the tar ball to a local directory, unpack it by command: - $ tar -zxvf ngspice-36.tar.gz + $ tar -zxvf ngspice-40.tar.gz Now change directories in to the top-level source directory (where this INSTALL file can be found). - You should be able to do: + The most comfortable way to compile ngspice is running the compile script + compile_linux.sh within the terminal window by ./compile_linux.sh. Admin + rights are required to allow the installation included in the script. + + CentOS users may need to add -std=c99 to the CFLAGS in the ../configure + statement. + + If you want to compile ngspice manually, you should be able to do: $ mkdir release $ cd release @@ -105,18 +113,15 @@ This file describes the procedures to install ngspice from sources. A simple ../configure might be sufficient for a basic ngspice, but the preferred arguments to ../configure are --with-x --with-readline=yes and --disable-debug - providing you with a comfortably working ngspice (see section 1.4 for details). + providing you with a comfortably working ngspice. - See the section titled 'Advanced Install' for instructions about additional arguments + See the section 1.5 titled 'Advanced Install' for instructions about additional arguments that can be passed to ../configure to customise the build and installation. - Do not use the script ./autogen.sh, because it is not required for - compiling and installing ngspice from the tarball. - A fully featured ngspice on LINUX may be obtained with the following commands: $ mkdir release $ cd release - $ ../configure --with-x --enable-xspice --disable-debug --enable-cider --with-readline=yes --enable-openmp + $ ../configure --with-x --enable-xspice --disable-debug --enable-cider --with-readline=yes --enable-osdi --enable-openmp $ make 2>&1 | tee make.log $ sudo make install @@ -141,6 +146,12 @@ This file describes the procedures to install ngspice from sources. The project uses the GNU build process. The compile output should go into a separate directory, so to e.g. maintain separate debug and release versions. + The most comfortable way to compile ngspice is running the compile script + compile_linux.sh within the terminal window by ./compile_linux.sh. Admin + rights are required to allow the installation included in the script. + + If you want to copile ngspice manually, you may run + $ ./autogen.sh $ mkdir debug $ cd debug @@ -148,7 +159,7 @@ This file describes the procedures to install ngspice from sources. $ make $ sudo make install - See the section titled 'Advanced Install' for instructions about arguments + See the section 1.5 titled 'Advanced Install' for instructions about arguments that can be passed to ./configure to customize the build and installation. Preferred arguments to ./configure to obtain a comfortably working ngspice may be @@ -156,21 +167,21 @@ This file describes the procedures to install ngspice from sources. executable). A fully featured ngspice on LINUX may be obtained with the following commands: - $ ./autogen.sh --adms + $ ./autogen.sh $ mkdir release $ cd release - $ ../configure --with-x --enable-xspice --disable-debug --enable-cider --with-readline=yes --enable-openmp --enable-adms + $ ../configure --with-x --enable-xspice --disable-debug --enable-cider --with-readline=yes --enable-openmp --enable-osdi $ make 2>&1 | tee make.log $ sudo make install - A bash script compile_linux.sh is available including all useful options, + The bash script compile_linux.sh includes all the useful options, compiling and installation procedures. 1.4 ngspice as a shared library The relevant configure options for the ngspice shared library are: - $ --with-ngshared --enable-xspice --disable-debug --enable-cider --enable-openmp + $ --with-ngshared --enable-xspice --disable-debug --enable-cider --enable-osdi --enable-openmp Typically the two aliases libngspice.so, libngspice.so.0 and the compiled library libngspice.so.0.0.1 are made. The install locations depend on @@ -312,13 +323,17 @@ This file describes the procedures to install ngspice from sources. problem yourself, then the development team will love to hear from you. -1.6 Installation on Red Hat, Oracle or Centos +1.6 Installation on Red Hat, Oracle or CentOS - These OSs, widely distributed among commercial users, require some + These OSs, widely distributed among commercial users, but offering + only an old gcc compiler, e.g. version 4.8, will require some special considerations. There is an extra document, "NGSPICE on Red Hat Like Distributions.pdf", provided by Justin Fisher, available with the ngspice distribution. + CentOS users may need to add -std=c99 to the CFLAGS in their ../configure + statement. + 2 Compilers and Options ===================== @@ -502,10 +517,10 @@ This file describes the procedures to install ngspice from sources. --disable-debug (-O2 optimization, no debug information) A fully featured ngspice on Windows may be obtained with the following commands: - $ ./autogen.sh --adms + $ ./autogen.sh $ mkdir release $ cd release - $ ../configure --with-wingui --enable-cider --disable-debug --enable-openmp --enable-xspice --enable-adms + $ ../configure --with-wingui --enable-cider --disable-debug --enable-openmp --enable-xspice --enable-osdi $ make install However, to compile code extracted from the git repository the procedure is @@ -523,7 +538,7 @@ This file describes the procedures to install ngspice from sources. Go to directory ngspice $ cd /d/Spice/ngspice Start compiling, e.g. by calling - $ ./autogen.sh --adms + $ ./autogen.sh $ ./compile_min.sh Update the ngspice files: @@ -680,7 +695,7 @@ This file describes the procedures to install ngspice from sources. You then will not have any graphics interface. In CYGWIN you may add --with-x for the X11 graphics (not available in mingw). A typical configure command may look like - ./configure --enable-adms --enable-xspice --enable-cider --enable-openmp + ./configure --enable-osdi --enable-xspice --enable-cider --enable-openmp --disable-debug CFLAGS=-m64 LDFLAGS=-m64 prefix=C:/Spice64 @@ -708,7 +723,9 @@ cross-compile-shared.sh. 3. Execute this command: sudo port install autoconf automake libtool bison flex ncurses readline fontconfig freetype libomp xorg-libXaw - 4. Use one of the scripts provided: compile_macos.sh or build-for-mac-os.sh + 4. Use one of the scripts provided: compile_macos_clang.sh or compile_macos_gcc.sh + gcc may be installed from Homebre at https://formulae.brew.sh/formula/gcc, with the + advantage that it supports OpenMP. 5. Or run the commands manually: Configure NGSPICE invoking "./configure". A complete set of features is: ./configure --enable-cider --enable-xspice --enable-openmp --enable-pss --enable-debug=no diff --git a/compile_linux.sh b/compile_linux.sh index 06c0d5b6d..5454ba0ec 100755 --- a/compile_linux.sh +++ b/compile_linux.sh @@ -9,10 +9,13 @@ # for details please see the ngspice manual, chapt. 32.1. # Declare 'compile_linux.sh' executable and start compiling with # './compile_linux.sh' or './compile_linux.sh d' from the ngspice directory. +# CentOS users may need to add -std=c99 to the CFLAGS in the ../configure +# statement. # Options: -# --adms and --enable-adms will install extra HICUM, EKV and MEXTRAM models via the -# adms interface. You need to download and install the *.va files via ng-adms-va.tgz -# Please see the ngspice manual, chapt. 13, for more info on adms. +# --enable-osdi will enable the OSDI interface, which, in conjuction with the +# external OpenVAF Verilig-A compiler, will allow access to advanced compact +# device models writen in Verilog-A. +# Please see the ngspice manual, chapt. 13, for more info on using OSDI/OpenVAF. # CIDER, XSPICE, and OpenMP may be selected at will. # --disable-debug will give O2 optimization (versus O0 for debug) and removes all debugging info. @@ -39,26 +42,18 @@ fi ./autogen.sh if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi -# Alternatively, if compiling sources from git, and want to add adms created devices, -# you may need to uncomment the following two lines (and don't forget to add adms option -# to the ../configure statement): -#./autogen.sh --adms -#if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi - echo if test "$1" = "d"; then cd debug if [ $? -ne 0 ]; then echo "cd debug failed"; exit 1 ; fi echo "configuring for 64 bit debug" echo -# You may add --enable-adms to the following command for adding adms generated devices ../configure --with-x --enable-xspice --enable-cider --enable-predictor --enable-osdi --with-readline=yes --enable-openmp CFLAGS="-g -m64 -O0 -Wall -Wno-unused-but-set-variable" LDFLAGS="-m64 -g" else cd release if [ $? -ne 0 ]; then echo "cd release failed"; exit 1 ; fi echo "configuring for 64 bit release" echo -# You may add --enable-adms to the following command for adding adms generated devices ../configure --with-x --enable-xspice --enable-cider --enable-predictor --enable-osdi --with-readline=yes --enable-openmp --disable-debug CFLAGS="-m64 -O2" LDFLAGS="-m64 -s" fi if [ $? -ne 0 ]; then echo "../configure failed"; exit 1 ; fi diff --git a/examples/TransmissionLines/ltra1_1_line.sp b/examples/TransmissionLines/ltra1_1_line.sp index 2d9c93bb5..959efa3db 100644 --- a/examples/TransmissionLines/ltra1_1_line.sp +++ b/examples/TransmissionLines/ltra1_1_line.sp @@ -1,6 +1,6 @@ MOSdriver -- lossy line LTRA model -- C load -m5 0 168 2 0 mn0p9 w = 18.0u l=0.9u -m6 1 168 2 1 mp1p0 w = 36.0u l=1.0u +m5 2 168 0 0 mn0p9 w = 18.0u l=0.9u +m6 2 168 1 1 mp1p0 w = 36.0u l=1.0u CN2 2 0 0.025398e-12 CN3 3 0 0.007398e-12 o1 2 0 3 0 lline @@ -8,12 +8,13 @@ vdd 1 0 dc 5.0 VS 168 0 PULSE (0 5 15.9NS 0.2NS 0.2NS 15.8NS 32NS ) .control TRAN 0.2N 47N 0 0.1N +rusage plot v(2) v(3) ylimit -0.5 5 .endc .MODEL mn0p9 NMOS VTO=0.8 KP=48U GAMMA=0.30 PHI=0.55 -+LAMBDA=0.00 CGSO=0 CGDO=0 CJ=0 CJSW=0 TOX=18000N LD=0.0U ++LAMBDA=0.00 CGSO=0 CGDO=0 CJ=0 CJSW=0 TOX=18N LD=0.0U .MODEL mp1p0 PMOS VTO=-0.8 KP=21U GAMMA=0.45 PHI=0.61 -+LAMBDA=0.00 CGSO=0 CGDO=0 CJ=0 CJSW=0 TOX=18000N LD=0.0U ++LAMBDA=0.00 CGSO=0 CGDO=0 CJ=0 CJSW=0 TOX=18N LD=0.0U .model lline ltra rel=1 r=12.45 g=0 l=8.972e-9 c=0.468e-12 +len=16 steplimit compactrel=1.0e-3 compactabs=1.0e-14 .end diff --git a/examples/TransmissionLines/ltra1_4_line.sp b/examples/TransmissionLines/ltra1_4_line.sp index 8d30a7578..f946454e0 100644 --- a/examples/TransmissionLines/ltra1_4_line.sp +++ b/examples/TransmissionLines/ltra1_4_line.sp @@ -135,7 +135,9 @@ VS1 2 0 PULSE (0 5 15.9Ns 0.2Ns 0.2Ns 15.8Ns 32Ns) VS2 4 0 PULSE (0 5 15.9Ns 0.2Ns 0.2Ns 15.8Ns 32Ns) .control +option noinit TRAN 0.1N 47.9N +rusage plot v(5) v(6) v(7) v(8) v(9) v(10) v(11) v(12) .endc * diff --git a/examples/TransmissionLines/ltra2_2_line.sp b/examples/TransmissionLines/ltra2_2_line.sp index 2a4ceaa7f..ac331a1ab 100644 --- a/examples/TransmissionLines/ltra2_2_line.sp +++ b/examples/TransmissionLines/ltra2_2_line.sp @@ -1,8 +1,8 @@ MOSdriver -- 2 lossy lines LTRA model -- C load -m5 0 168 2 0 mn0p9 w = 18.0u l=0.9u -m6 1 168 2 1 mp1p0 w = 36.0u l=1.0u -m1 0 3 4 0 mn0p9 w = 18.0u l=0.9u -m2 1 3 4 1 mp1p0 w = 36.0u l=1.0u +m5 2 168 0 0 mn0p9 w = 18.0u l=0.9u +m6 2 168 1 1 mp1p0 w = 36.0u l=1.0u +m1 4 3 0 0 mn0p9 w = 18.0u l=0.9u +m2 4 3 1 1 mp1p0 w = 36.0u l=1.0u CN2 2 0 0.025398e-12 CN3 3 0 0.007398e-12 CN4 4 0 0.025398e-12 @@ -13,7 +13,9 @@ vdd 1 0 dc 5.0 VS 168 0 PULSE (0 5 15.9NS 0.2NS 0.2NS 15.8NS 32NS ) .control TRAN 0.2N 47N 0 0.1N -plot v(2) v(3) v(4) v(5) +rusage +set xbrushwidth=3 +plot v(168) v(2) v(3) v(4) v(5) .endc .MODEL mn0p9 NMOS VTO=0.8 KP=48U GAMMA=0.30 PHI=0.55 +LAMBDA=0.00 CGSO=0 CGDO=0 CJ=0 CJSW=0 TOX=18000N LD=0.0U diff --git a/examples/TransmissionLines/ltra3_2_line.sp b/examples/TransmissionLines/ltra3_2_line.sp index 1a756520e..7d25d2969 100644 --- a/examples/TransmissionLines/ltra3_2_line.sp +++ b/examples/TransmissionLines/ltra3_2_line.sp @@ -84,6 +84,9 @@ VS2 268 0 PULSE (0 5 15.9N 0.2N 0.2N 15.8N 60N) * .control TRAN 0.2N 47.9NS +rusage +set color0=white +set xbrushwidth=3 PLOT v(648) v(651) v(751) .endc * diff --git a/examples/TransmissionLines/ltra4_1_line.sp b/examples/TransmissionLines/ltra4_1_line.sp index 8dc8ada61..ef7aca7b1 100644 --- a/examples/TransmissionLines/ltra4_1_line.sp +++ b/examples/TransmissionLines/ltra4_1_line.sp @@ -53,6 +53,9 @@ x3 3 4 10 dioload +reltol=1e-3 abstol=1e-14 .control tran 0.1ns 60ns +rusage +set color0=white +set xbrushwidth=3 plot v(1) v(2) v(3) .endc diff --git a/examples/TransmissionLines/ltra5_1_line.sp b/examples/TransmissionLines/ltra5_1_line.sp index f8a1c5ffa..90944e742 100644 --- a/examples/TransmissionLines/ltra5_1_line.sp +++ b/examples/TransmissionLines/ltra5_1_line.sp @@ -60,6 +60,9 @@ x1 2 3 xonecm tran 0.001ns 10ns 0 0.1ns * onecm10 *tran 0.001ns 10ns 0 0.01ns +rusage +set color0=white +set xbrushwidth=3 plot v(1) v(2) v(3) .endc diff --git a/examples/TransmissionLines/ltra6_2_line.sp b/examples/TransmissionLines/ltra6_2_line.sp index 452791297..ab06028e1 100644 --- a/examples/TransmissionLines/ltra6_2_line.sp +++ b/examples/TransmissionLines/ltra6_2_line.sp @@ -75,6 +75,9 @@ rt2 5 0 50 .options acct reltol=1e-3 abstol=1e-12 .control tran 0.1ns 60ns +rusage +*set color0=white +set xbrushwidth=3 plot v(2) v(4) v(5) .endc diff --git a/examples/TransmissionLines/ltra7_4_line.sp b/examples/TransmissionLines/ltra7_4_line.sp index 7be4615a0..b7733d9a1 100644 --- a/examples/TransmissionLines/ltra7_4_line.sp +++ b/examples/TransmissionLines/ltra7_4_line.sp @@ -106,7 +106,11 @@ x1 2 3 4 5 6 7 8 9 test VS1 1 0 PWL(15.9NS 0.0 16.1Ns 5.0 31.9Ns 5.0 32.1Ns 0.0) .control -TRAN 0.2NS 50NS +option noinit +TRAN 0.2NS 50NS +rusage +*set color0=white +set xbrushwidth=3 plot v(1) v(2) v(6) v(7) v(8) v(9) .endc * diff --git a/examples/osdi/psp103/c7552_ann_psp.net b/examples/osdi/psp103/c7552_ann_psp.net index 526240a58..78c0a5fc7 100644 --- a/examples/osdi/psp103/c7552_ann_psp.net +++ b/examples/osdi/psp103/c7552_ann_psp.net @@ -1,6 +1,7 @@ -* ISCAS85 benchmark circuit SPICE netlist +* ISCAS85 benchmark circuit SPICE netlist, PSP103 * generated by spicegen.pl 1.0 * by Jingye Xu @ VLSI group, Dept of ECE, UIC +* Modified for PSP103 model via OSDI/OpenVAF by Holger Vogt * Path to the models .include Modelcards/psp103_nmos-2.mod diff --git a/examples/p-to-n-examples/555-timer-2.cir b/examples/p-to-n-examples/555-timer-2.cir index c34619948..1ea194c71 100644 --- a/examples/p-to-n-examples/555-timer-2.cir +++ b/examples/p-to-n-examples/555-timer-2.cir @@ -86,6 +86,7 @@ if $?batchmode else run + rusage time plot v(16) v(13) v(17) v(1)+6 v(4)+6 v(3)+6 end .endc diff --git a/examples/sp/filter.lib b/examples/sp/filter.lib new file mode 100644 index 000000000..173d853dc --- /dev/null +++ b/examples/sp/filter.lib @@ -0,0 +1,185 @@ +.SUBCKT filter 1 2 3 +*2-port S-parameter file +*Title: * simple test for xfer code model: comparison +*Generated by ngspice at Tue May 23 06:49:31 2023 +* Hz S RI R +* Z1=50.000000 Z2=50.000000 + +R1N 1 10 -5.000000e+01 +R1P 10 11 1.000000e+02 +R2N 2 20 -5.000000e+01 +R2P 20 21 1.000000e+02 + +*S11 FREQ DB PHASE +E11 11 12 FREQ {V(10,3)}= DB ++( 1.000000e+07Hz, 3.654967e-07, -7.619541e+01) ++( 1.487179e+07Hz, 1.964030e-07, -1.157703e+02) ++( 1.974359e+07Hz, -1.084219e-07, -1.569277e+02) ++( 2.461538e+07Hz, -5.321598e-06, -1.985756e+02) ++( 2.948718e+07Hz, -1.265047e-05, -2.395114e+02) ++( 3.435897e+07Hz, -2.727603e-05, -2.792878e+02) ++( 3.923077e+07Hz, -6.620604e-05, -3.184596e+02) ++( 4.410256e+07Hz, -1.624082e-04, -3.582070e+02) ++( 4.897436e+07Hz, -3.755273e-04, -3.996839e+02) ++( 5.384615e+07Hz, -7.725656e-04, -4.432805e+02) ++( 5.871795e+07Hz, -1.320643e-03, -4.881884e+02) ++( 6.358974e+07Hz, -1.599290e-03, -5.330311e+02) ++( 6.846154e+07Hz, -4.631092e-04, -5.776220e+02) ++( 7.333333e+07Hz, -1.388239e-02, -6.262936e+02) ++( 7.820513e+07Hz, -1.245578e+01, -8.015034e+02) ++( 8.307692e+07Hz, -1.142468e+00, -6.888087e+02) ++( 8.794872e+07Hz, -1.292324e+00, -7.542062e+02) ++( 9.282051e+07Hz, -2.163078e+00, -8.283885e+02) ++( 9.769231e+07Hz, -3.764829e+00, -9.213357e+02) ++( 1.025641e+08Hz, -4.165673e+00, -1.041098e+03) ++( 1.074359e+08Hz, -2.143343e+00, -1.139856e+03) ++( 1.123077e+08Hz, -1.084156e+00, -1.201868e+03) ++( 1.171795e+08Hz, -7.962690e-01, -1.249480e+03) ++( 1.220513e+08Hz, -1.204024e+00, -1.318959e+03) ++( 1.269231e+08Hz, -4.148462e-01, -1.169292e+03) ++( 1.317949e+08Hz, -1.026085e-02, -1.240330e+03) ++( 1.366667e+08Hz, -1.360661e-04, -1.265793e+03) ++( 1.415385e+08Hz, -2.410965e-03, -1.281511e+03) ++( 1.464103e+08Hz, -3.787891e-03, -1.293132e+03) ++( 1.512821e+08Hz, -3.602264e-03, -1.302433e+03) ++( 1.561538e+08Hz, -2.547410e-03, -1.310211e+03) ++( 1.610256e+08Hz, -1.530232e-03, -1.316893e+03) ++( 1.658974e+08Hz, -8.667728e-04, -1.322741e+03) ++( 1.707692e+08Hz, -4.905888e-04, -1.327928e+03) ++( 1.756410e+08Hz, -2.840626e-04, -1.332578e+03) ++( 1.805128e+08Hz, -1.688713e-04, -1.336783e+03) ++( 1.853846e+08Hz, -1.041703e-04, -1.340612e+03) ++( 1.902564e+08Hz, -6.546576e-05, -1.344121e+03) ++( 1.951282e+08Hz, -4.228835e-05, -1.347353e+03) ++( 2.000000e+08Hz, -2.867354e-05, -1.350343e+03) + +*S12 FREQ DB PHASE +E12 12 3 FREQ {V(20,3)}= DB ++( 1.000000e+07Hz, -1.248758e+02, -1.373971e+02) ++( 1.487179e+07Hz, -9.831399e+01, -1.647281e+02) ++( 1.974359e+07Hz, -7.673566e+01, -2.026127e+02) ++( 2.461538e+07Hz, -5.898226e+01, -2.906518e+02) ++( 2.948718e+07Hz, -5.542440e+01, -3.666485e+02) ++( 3.435897e+07Hz, -5.204910e+01, -4.009490e+02) ++( 3.923077e+07Hz, -4.814977e+01, -4.271950e+02) ++( 4.410256e+07Hz, -4.426072e+01, -4.514100e+02) ++( 4.897436e+07Hz, -4.063346e+01, -4.755494e+02) ++( 5.384615e+07Hz, -3.749934e+01, -5.003303e+02) ++( 5.871795e+07Hz, -3.516924e+01, -5.256223e+02) ++( 6.358974e+07Hz, -3.433887e+01, -5.509590e+02) ++( 6.846154e+07Hz, -3.971774e+01, -5.765977e+02) ++( 7.333333e+07Hz, -2.496027e+01, -4.260244e+02) ++( 7.820513e+07Hz, -2.540060e-01, -5.317362e+02) ++( 8.307692e+07Hz, -6.358120e+00, -6.335796e+02) ++( 8.794872e+07Hz, -5.894279e+00, -6.719727e+02) ++( 9.282051e+07Hz, -4.063864e+00, -7.129969e+02) ++( 9.769231e+07Hz, -2.367660e+00, -7.603597e+02) ++( 1.025641e+08Hz, -2.098602e+00, -8.143919e+02) ++( 1.074359e+08Hz, -4.094614e+00, -8.636479e+02) ++( 1.123077e+08Hz, -6.557734e+00, -8.998592e+02) ++( 1.171795e+08Hz, -7.759301e+00, -9.295624e+02) ++( 1.220513e+08Hz, -6.159604e+00, -9.703161e+02) ++( 1.269231e+08Hz, -1.040475e+01, -1.077742e+03) ++( 1.317949e+08Hz, -2.627115e+01, -1.123641e+03) ++( 1.366667e+08Hz, -4.503397e+01, -9.675219e+02) ++( 1.415385e+08Hz, -3.255698e+01, -9.893598e+02) ++( 1.464103e+08Hz, -3.059532e+01, -1.012566e+03) ++( 1.512821e+08Hz, -3.081422e+01, -1.036661e+03) ++( 1.561538e+08Hz, -3.231825e+01, -1.058931e+03) ++( 1.610256e+08Hz, -3.453111e+01, -1.077318e+03) ++( 1.658974e+08Hz, -3.699828e+01, -1.091740e+03) ++( 1.707692e+08Hz, -3.947129e+01, -1.103061e+03) ++( 1.756410e+08Hz, -4.184769e+01, -1.112161e+03) ++( 1.805128e+08Hz, -4.409577e+01, -1.119694e+03) ++( 1.853846e+08Hz, -4.621280e+01, -1.126103e+03) ++( 1.902564e+08Hz, -4.820666e+01, -1.131686e+03) ++( 1.951282e+08Hz, -5.008836e+01, -1.136645e+03) ++( 2.000000e+08Hz, -5.186916e+01, -1.141123e+03) + +*S21 FREQ DB PHASE +E21 21 22 FREQ {V(10,3)}= DB ++( 1.000000e+07Hz, -1.248758e+02, -1.373971e+02) ++( 1.487179e+07Hz, -9.831399e+01, -1.647281e+02) ++( 1.974359e+07Hz, -7.673566e+01, -2.026127e+02) ++( 2.461538e+07Hz, -5.898226e+01, -2.906518e+02) ++( 2.948718e+07Hz, -5.542440e+01, -3.666485e+02) ++( 3.435897e+07Hz, -5.204910e+01, -4.009490e+02) ++( 3.923077e+07Hz, -4.814977e+01, -4.271950e+02) ++( 4.410256e+07Hz, -4.426072e+01, -4.514100e+02) ++( 4.897436e+07Hz, -4.063346e+01, -4.755494e+02) ++( 5.384615e+07Hz, -3.749934e+01, -5.003303e+02) ++( 5.871795e+07Hz, -3.516924e+01, -5.256223e+02) ++( 6.358974e+07Hz, -3.433887e+01, -5.509590e+02) ++( 6.846154e+07Hz, -3.971774e+01, -5.765977e+02) ++( 7.333333e+07Hz, -2.496027e+01, -4.260244e+02) ++( 7.820513e+07Hz, -2.540060e-01, -5.317362e+02) ++( 8.307692e+07Hz, -6.358120e+00, -6.335796e+02) ++( 8.794872e+07Hz, -5.894279e+00, -6.719727e+02) ++( 9.282051e+07Hz, -4.063864e+00, -7.129969e+02) ++( 9.769231e+07Hz, -2.367660e+00, -7.603597e+02) ++( 1.025641e+08Hz, -2.098602e+00, -8.143919e+02) ++( 1.074359e+08Hz, -4.094614e+00, -8.636479e+02) ++( 1.123077e+08Hz, -6.557734e+00, -8.998592e+02) ++( 1.171795e+08Hz, -7.759301e+00, -9.295624e+02) ++( 1.220513e+08Hz, -6.159604e+00, -9.703161e+02) ++( 1.269231e+08Hz, -1.040475e+01, -1.077742e+03) ++( 1.317949e+08Hz, -2.627115e+01, -1.123641e+03) ++( 1.366667e+08Hz, -4.503397e+01, -9.675219e+02) ++( 1.415385e+08Hz, -3.255698e+01, -9.893598e+02) ++( 1.464103e+08Hz, -3.059532e+01, -1.012566e+03) ++( 1.512821e+08Hz, -3.081422e+01, -1.036661e+03) ++( 1.561538e+08Hz, -3.231825e+01, -1.058931e+03) ++( 1.610256e+08Hz, -3.453111e+01, -1.077318e+03) ++( 1.658974e+08Hz, -3.699828e+01, -1.091740e+03) ++( 1.707692e+08Hz, -3.947129e+01, -1.103061e+03) ++( 1.756410e+08Hz, -4.184769e+01, -1.112161e+03) ++( 1.805128e+08Hz, -4.409577e+01, -1.119694e+03) ++( 1.853846e+08Hz, -4.621280e+01, -1.126103e+03) ++( 1.902564e+08Hz, -4.820666e+01, -1.131686e+03) ++( 1.951282e+08Hz, -5.008836e+01, -1.136645e+03) ++( 2.000000e+08Hz, -5.186916e+01, -1.141123e+03) + +*S22 FREQ DB PHASE +E22 22 3 FREQ {V(20,3)}= DB ++( 1.000000e+07Hz, 1.633257e-07, -1.859873e+01) ++( 1.487179e+07Hz, -1.597472e-07, -3.368599e+01) ++( 1.974359e+07Hz, -9.840549e-08, -6.829764e+01) ++( 2.461538e+07Hz, -5.748843e-06, -2.027281e+02) ++( 2.948718e+07Hz, -1.209271e-05, -3.137855e+02) ++( 3.435897e+07Hz, -2.686288e-05, -3.426102e+02) ++( 3.923077e+07Hz, -6.619051e-05, -3.559304e+02) ++( 4.410256e+07Hz, -1.626503e-04, -3.646130e+02) ++( 4.897436e+07Hz, -3.750315e-04, -3.714149e+02) ++( 5.384615e+07Hz, -7.720713e-04, -3.773802e+02) ++( 5.871795e+07Hz, -1.321131e-03, -3.830562e+02) ++( 6.358974e+07Hz, -1.599127e-03, -3.888868e+02) ++( 6.846154e+07Hz, -4.639695e-04, -3.955734e+02) ++( 7.333333e+07Hz, -1.388161e-02, -4.057551e+02) ++( 7.820513e+07Hz, -1.245578e+01, -4.419690e+02) ++( 8.307692e+07Hz, -1.142468e+00, -3.983505e+02) ++( 8.794872e+07Hz, -1.292324e+00, -4.097393e+02) ++( 9.282051e+07Hz, -2.163078e+00, -4.176053e+02) ++( 9.769231e+07Hz, -3.764828e+00, -4.193838e+02) ++( 1.025641e+08Hz, -4.165672e+00, -4.076855e+02) ++( 1.074359e+08Hz, -2.143343e+00, -4.074397e+02) ++( 1.123077e+08Hz, -1.084156e+00, -4.178506e+02) ++( 1.171795e+08Hz, -7.962687e-01, -4.296447e+02) ++( 1.220513e+08Hz, -1.204024e+00, -4.416736e+02) ++( 1.269231e+08Hz, -4.148459e-01, -4.461929e+02) ++( 1.317949e+08Hz, -1.026073e-02, -4.669521e+02) ++( 1.366667e+08Hz, -1.361528e-04, -4.892508e+02) ++( 1.415385e+08Hz, -2.411138e-03, -5.172082e+02) ++( 1.464103e+08Hz, -3.788042e-03, -5.519999e+02) ++( 1.512821e+08Hz, -3.601989e-03, -5.908887e+02) ++( 1.561538e+08Hz, -2.547212e-03, -6.276516e+02) ++( 1.610256e+08Hz, -1.529976e-03, -6.577430e+02) ++( 1.658974e+08Hz, -8.674572e-04, -6.807399e+02) ++( 1.707692e+08Hz, -4.901623e-04, -6.981937e+02) ++( 1.756410e+08Hz, -2.836349e-04, -7.117446e+02) ++( 1.805128e+08Hz, -1.694495e-04, -7.226059e+02) ++( 1.853846e+08Hz, -1.034247e-04, -7.315943e+02) ++( 1.902564e+08Hz, -6.587183e-05, -7.392507e+02) ++( 1.951282e+08Hz, -4.251059e-05, -7.459375e+02) ++( 2.000000e+08Hz, -2.798303e-05, -7.519027e+02) + +.ENDS diff --git a/examples/sp/filter.sp b/examples/sp/filter.sp new file mode 100644 index 000000000..5851bcf6e --- /dev/null +++ b/examples/sp/filter.sp @@ -0,0 +1,91 @@ +* Simple test for xfer code model: comparison +* +* This circuit compares the results of an AC analysis of a filter (node out) +* with those from a behavioural model controlled by measured S-parameters +* of that circuit (node xout). The AC analysis has more data points than +* that used to measure the S-parameters, to prevent the results from matching +* exactly. + +* The use of S-parameters to create a behavioural simulation of a component +* was discussed here: +* https://sourceforge.net/p/ngspice/discussion/120973/thread/51228e0b01/ + +* Circuit from: +* Novarianti, Dini. (2019). +* Design and Implementation of Chebyshev Band Pass Filter with +* M-Derived Section in Frequency Band 88 - 108 MHz. +* Jurnal Jartel: Jurnal Jaringan Telekomunikasi. 8. 7-11. +* 10.33795/jartel.v8i1.147. +* +* https://www.researchgate.net/publication/352822864_Design_and_Implementation_of_Chebyshev_Band_Pass_Filter_with_M-Derived_Section_in_Frequency_Band_88_-_108_MHz + +* Set this parameter to 1 to generate a Touchstone file that can be used +* to generate the behavioural part of the circuit, filter.lib + +.param do_sp=0 +.csparam do_sp=do_sp + +.if (do_sp) + +.csparam Rbase=50 ; This is required by "wrs2p", below. +vgen 1 0 dc 0 ac 1 portnum 1 + +.else + +vgen in 0 dc 0 ac 1 +rs in 1 50 + +.endif + +l1 1 2 0.058u +c2 2 0 40.84p +l3 2 3 0.128u +c4 3 0 47.91p +l5 3 4 0.128u +c6 4 0 40.48p +l7 4 5 0.058u + +la 5 6 0.044u +lb 6 a 0.078u +cb a 0 17.61p +lc 6 b 0.151u +cc b 0 34.12p +c7 6 7 26.035p + +l8 7 0 0.0653u +c8 7 8 20.8p +l9 8 0 0.055u +c9 8 9 20.8p +l10 9 0 0.653u + +c10 9 out 45.64p + +.if (do_sp) + +vl out 0 dc 0 ac 0 portnum 2 + +.else + +rl out 0 50 + +* Behavioural circuit, for comparison. + +.inc filter.lib +R1 in port1 50 +xsp port1 xout 0 filter +R2 xout 0 50 + +.endif + +.control +if $&do_sp + sp lin 40 10meg 200meg + wrs2p filter.s2p + plot S_1_1 S_2_2 polar +else + ac lin 400 10meg 200meg + plot db(mag(out)) 5*unwrap(ph(out)) db(mag(xout)) 5*unwrap(ph(xout)) +end + +.endc +.end diff --git a/examples/vbic/self-heat.sp b/examples/vbic/self-heat.sp index 02a9695d1..93ceb9195 100644 --- a/examples/vbic/self-heat.sp +++ b/examples/vbic/self-heat.sp @@ -1,7 +1,6 @@ VBIC Output Test Ic=f(Vc,Ib) vs self heating -.option absmos=1e-12 relmos=1e-6 relv=1e-6 absv=1e-9 post vc c 0 0 -vb b 0 1 +ib 0 b 10u ve e 0 0 vs s 0 0 vc1 c c1 0 @@ -9,42 +8,16 @@ vb1 b b1 0 ve1 e e1 0 vs1 s s1 0 .temp 27 -Q1 c1 b1 e1 s1 t mod1 area=1 -.model mod1 npn Level=4 -+ Tnom=27 RCX=10 RCI=60 VO=2 GAMM=2.e-11 -+ HRCF=2 RBX=10 RBI=40 RE=2 -+ RS=20 RBP=40 IS=1e-16 NF=1.00000e+00 -+ NR=1.00000e+00 FC=9.00000e-01 CBEO=0 -+ CJE=1.e-13 PE=0.75 ME=0.33 -+ AJE=-5.00000e-01 CBCO=0 CJC=2e-14 -+ QCO=1e-12 CJEP=1e-13 PC=7.50000e-01 -+ MC=3.30000e-01 AJC=-5.00000e-01 CJCP=4e-13 -+ PS=7.50000e-01 MS=3.30000e-01 AJS=-5.00000e-01 -+ IBEI=1e-18 WBE=1.0000 NEI=1.00000e+00 -+ IBEN=5e-15 NEN=2.00000e+00 IBCI=2e-17 -+ NCI=1.00000e+00 IBCN=5e-15 NCN=2.00000e+00 -+ AVC1=2 AVC2=15 ISP=1e-15 -+ WSP=1.000e+00 NFP=1.00000e+00 IBEIP=0 -+ IBENP=0 IBCIP=0 NCIP=1.00000e+00 -+ IBCNP=0 NCNP=2.00000e+00 VEF=10 -+ VER=4 IKF=0.002 IKR=0.0002 IKP=0.0002 -+ TF=1.e-11 QTF=0 XTF=20 -+ VTF=0 ITF=0.08 TR=1e-10 -+ KFN=0 AFN=1.0e+00 -+ BFN=1.0000e+00 XRE=0 XRB=0 -+ XRC=0 XRS=0 XVO=0 -+ EA=1.12000e+00 EAIE=1.12000e+00 -+ EANE=1.12000e+00 EANC=1.12000e+00 -+ EANS=1.12000e+00 XIS=3.00000e+00 -+ XII=3.00000e+00 XIN=3.00000e+00 -+ TNF=0 TAVC=0 -+ RTH=300 CTH=0 -+ TD=0 -*+ TD=2.e-11 +Q1 c1 b1 e1 s1 dt M_BFP780 area=1 + +.include Infineon_VBIC.lib + .control -dc vc 0.0 5.0001 0.05 vb 0.7 1.0001 0.05 -altermod @mod1[RTH]=0 -dc vc 0.0 5.0001 0.05 vb 0.7 1.0001 0.05 +dc vc 0.0 5.0 0.05 ib 50u 500u 50u +settype temperature v(dt) +plot v(dt) +altermod @M_BFP780[RTH]=0 +dc vc 0.0 5.0 0.05 ib 50u 500u 50u plot dc1.vc1#branch dc2.vc1#branch .endc .end diff --git a/examples/vdmos/ro_11_vdmos.sp b/examples/vdmos/ro_11_vdmos.sp index f277dc49a..23b2b7cc9 100644 --- a/examples/vdmos/ro_11_vdmos.sp +++ b/examples/vdmos/ro_11_vdmos.sp @@ -18,17 +18,18 @@ xinv7 9 8 1 0 inv xinv8 10 9 1 0 inv xinv9 2 10 1 0 inv -.model N1 vdmos cgdmin=0.05p cgdmax=0.2p a=1.2 cgs=0.15p rg=10 kp=1e-5 rb=1e7 cjo=1n ksubthres=0.2 -.model P1 vdmos cgdmin=0.05p cgdmax=0.2p a=1.2 cgs=0.15p rg=10 kp=1e-5 rb=1e7 cjo=1n pchan ksubthres=0.2 +.model N1 vdmos vto=1 cgdmin=0.05p cgdmax=0.2p a=1.2 cgs=0.15p rg=10 kp=1e-5 rb=1e7 cjo=1n ksubthres=0.2 +.model P1 vdmos vto=-1 cgdmin=0.05p cgdmax=0.2p a=1.2 cgs=0.15p rg=10 kp=1e-5 rb=1e7 cjo=1n pchan ksubthres=0.2 -.tran 0.1n 5u +.tran 0.1n 10u +.ic v(6)=2.5 .control run rusage * current and output in a single plot -plot v(6) 1000*(-I(vdd)) ylimit -1 6 +plot v(6) 50000*(-I(vdd)) ylimit -1 6 .endc .end diff --git a/examples/xspice/pll/pll-xspice-fstep.cir b/examples/xspice/pll/pll-xspice-fstep.cir index d66a96061..0bb2fb17f 100644 --- a/examples/xspice/pll/pll-xspice-fstep.cir +++ b/examples/xspice/pll/pll-xspice-fstep.cir @@ -66,9 +66,10 @@ abridge-w1 [d_divout d_ref d_Un d_D] [s1 s2 u1 d1] dac1 ; change to d_u or d_Un .control save cont s1 s2 u1 d1 +set xbrushwidth=2 let isbmode = $?batchmode if isbmode = 0 - iplot cont + iplot -w $&simtime cont endif * calculate breakpoint for switching frequency let t1_3 = simtime/3 diff --git a/src/ciderlib/twod/twodest.c b/src/ciderlib/twod/twodest.c index d51297f93..01b646c42 100644 --- a/src/ciderlib/twod/twodest.c +++ b/src/ciderlib/twod/twodest.c @@ -66,10 +66,31 @@ TWOdestroy(TWOdevice *pDevice) FREE( pElem ); } FREE( pDevice->elements ); + for (int xIndex = 1; xIndex < pDevice->numXNodes; xIndex++) { + FREE(pDevice->elemArray[xIndex]); + } FREE( pDevice->elemArray ); } - /* destroy the contacts & channels */ + if (pDevice->pMaterials) { + TWOmaterial* pMtmp = pDevice->pMaterials; + while (pMtmp) { + TWOmaterial* pMtmpnext = pMtmp->next; + FREE(pMtmp); + pMtmp = pMtmpnext; + } + } + + if (pDevice->pFirstContact) { + struct sTWOcontact* pFCtmp = pDevice->pFirstContact; + while (pFCtmp) { + struct sTWOcontact* pFCtmpnext = pFCtmp->next; + FREE(pFCtmp); + pFCtmp = pFCtmpnext; + } + } + + /* destroy the channels */ /* NOT IMPLEMENTED */ FREE( pDevice ); diff --git a/src/frontend/breakp.c b/src/frontend/breakp.c index f420a938a..190e91730 100644 --- a/src/frontend/breakp.c +++ b/src/frontend/breakp.c @@ -205,7 +205,26 @@ com_iplot(wordlist *wl) /* settrace(wl, VF_PLOT); */ struct dbcomm *d, *td, *currentdb = NULL; - char *s; + double window; + char *s; + + /* Look for "-w window-size" at the front, indicating a windowed iplot. */ + + if (wl->wl_next && !strcmp("-w", wl->wl_word)) { + char *cp; + int error; + + wl = wl->wl_next; + cp = wl->wl_word; + window = INPevaluate(&cp, &error, 0); + if (error || window <= 0) { + fprintf(cp_err, "Incremental plot width must be positive.\n"); + return; + } + wl = wl->wl_next; + } else { + window = 0.0; + } /* We use a modified ad-hoc algorithm here where db_also denotes vectors on the same command line and db_next denotes @@ -215,6 +234,7 @@ com_iplot(wordlist *wl) d = TMALLOC(struct dbcomm, 1); d->db_analysis = NULL; d->db_number = debugnumber++; + d->db_value1 = window; // Field re-use if (eq(s, "all")) { d->db_type = DB_IPLOTALL; } else { diff --git a/src/frontend/commands.c b/src/frontend/commands.c index 028f24071..225dbf884 100644 --- a/src/frontend/commands.c +++ b/src/frontend/commands.c @@ -426,7 +426,7 @@ struct comm spcp_coms[] = { { "iplot", com_iplot, TRUE, TRUE, { 0200, 0200, 0200, 0200 }, E_DEFHMASK, 0, LOTS, NULL, - "[all] [node ...] : Incrementally plot a node." } , + "[-w width] [all] [node ...] : Incrementally plot nodes." } , { "status", com_sttus, TRUE, FALSE, { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, NULL, diff --git a/src/frontend/evaluate.c b/src/frontend/evaluate.c index f38aff246..ee9bec045 100644 --- a/src/frontend/evaluate.c +++ b/src/frontend/evaluate.c @@ -191,7 +191,7 @@ doop(char what, struct dvec *v1, *v2, *res; ngcomplex_t *c1 = NULL, *c2 = NULL, lc; double *d1 = NULL, *d2 = NULL, ld; - int length = 0, i; + int length = 0, i, longer; void *data; bool free1 = FALSE, free2 = FALSE, relflag = FALSE; @@ -253,6 +253,7 @@ doop(char what, /* Make sure we have data of the same length. */ length = ((v1->v_length > v2->v_length) ? v1->v_length : v2->v_length); if (v1->v_length < length) { + longer = 2; free1 = TRUE; if (isreal(v1)) { ld = 0.0; @@ -275,6 +276,7 @@ doop(char what, c1[i] = lc; } } else { + longer = 0; if (isreal(v1)) d1 = v1->v_realdata; else @@ -282,6 +284,7 @@ doop(char what, } if (v2->v_length < length) { + longer = 1; free2 = TRUE; if (isreal(v2)) { ld = 0.0; @@ -335,10 +338,27 @@ doop(char what, } /* This is a non-obvious thing */ + if (v1->v_scale != v2->v_scale) { - fprintf(cp_err, "Warning: scales of %s and %s are different.\n", - v1->v_name, v2->v_name); - res->v_scale = NULL; + switch (longer) { + case 0: + if (!v1->v_scale) + res->v_scale = v2->v_scale; + else if (!v2->v_scale) + res->v_scale = v1->v_scale; + else + fprintf(cp_err, + "Warning: scales of %s and %s are different.\n", + v1->v_name, v2->v_name); + res->v_scale = v1->v_scale; // Do something! + break; + case 1: + res->v_scale = v1->v_scale; + break; + case 2: + res->v_scale = v2->v_scale; + break; + } } else { res->v_scale = v1->v_scale; } diff --git a/src/frontend/init.c b/src/frontend/init.c index 6c3a77513..a19d2f4db 100644 --- a/src/frontend/init.c +++ b/src/frontend/init.c @@ -20,6 +20,7 @@ cp_init(void) cp_chars[128] cp_maxhistlength (set to 10000 in com_history.c) cp_curin, cp_curout, cp_curerr (defined in streams.c) + cp_no_histsubst */ { cp_vset("history", CP_NUM, &cp_maxhistlength); @@ -28,6 +29,10 @@ cp_init(void) cp_curout = stdout; cp_curerr = stderr; + /* Enable history substitution */ + if (cp_getvar("histsubst", CP_BOOL, NULL, 0)) + cp_no_histsubst = FALSE; + /* io redirection in streams.c: cp_in set to cp_curin etc. */ cp_ioreset(); diff --git a/src/frontend/inp.c b/src/frontend/inp.c index aca467a86..ed9415156 100644 --- a/src/frontend/inp.c +++ b/src/frontend/inp.c @@ -890,23 +890,36 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) /* handle .if ... .elseif ... .else ... .endif statements. */ dotifeval(deck); + /* get csparams and create vectors, available + in plot 'const' of a .control section */ for (dd = deck; dd; dd = dd->nextcard) { - /* get csparams and create vectors, being - available in .control section, in plot 'const' */ if (ciprefix(".csparam", dd->line)) { wordlist *wlist = NULL; char *cstoken[3]; int i; dd->line[0] = '*'; s = skip_ws(dd->line + 8); - cstoken[0] = gettok_char(&s, '=', FALSE, FALSE); - cstoken[1] = gettok_char(&s, '=', TRUE, FALSE); - cstoken[2] = gettok(&s); - for (i = 3; --i >= 0; ) { - wlist = wl_cons(cstoken[i], wlist); + while (s && *s) { + char* nexttoken = s; + cstoken[0] = gettok_char(&s, '=', FALSE, FALSE); + cstoken[1] = gettok_char(&s, '=', TRUE, FALSE); + cstoken[2] = gettok(&s); + /* guard against buggy input line */ + if (!cstoken[0] || !cstoken[1] || !cstoken[2] || strchr(cstoken[2],'=')) { + fprintf(stderr, "Warning: bad csparam definition, %s skipped!\n", nexttoken); + fprintf(stderr, " See line %d, .%s\n\n", dd->linenum, dd->line + 1); + tfree(cstoken[0]); + tfree(cstoken[1]); + tfree(cstoken[2]); + break; + } + for (i = 3; --i >= 0; ) { + wlist = wl_cons(cstoken[i], wlist); + } + com_let(wlist); + wl_free(wlist); + wlist = NULL; } - com_let(wlist); - wl_free(wlist); } } diff --git a/src/frontend/inpc_probe.c b/src/frontend/inpc_probe.c index 7ef70ce93..825eef914 100644 --- a/src/frontend/inpc_probe.c +++ b/src/frontend/inpc_probe.c @@ -895,6 +895,9 @@ void inp_probe(struct card* deck) else if (err == 2) { fprintf(stderr, "Warning: Zero voltage sources already set,\n .probe %s will be ignored\n", wltmp->wl_word); } + else if (err == 3) { + fprintf(stderr, "Warning: Number of nodes mismatch,\n .probe %s will be ignored\n", wltmp->wl_word); + } continue; } else if (!haveall) { @@ -1358,6 +1361,15 @@ static int setallvsources(struct card *tmpcard, NGHASHPTR instances, char *instn char nodenumstr[3]; char *nodename1 = get_terminal_name(instname, itoa10(nodenum, nodenumstr), instances); + if (!nodename1) { + tfree(begstr); + tfree(strnode1); + ds_free(&BVrefline); + ds_free(&Bpowerline); + ds_free(&Bpowersave); + return 3; + } + newline = tprintf("%s %s %s", begstr, newnode, instline); char* vline = tprintf("vcurr_%s:probe_int_%s:%s_%s %s %s 0", instname, nodename1, nodenumstr, strnode1, strnode1, newnode); diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index e2344177a..a4b157de3 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -136,7 +136,6 @@ static void inp_reorder_params( static int inp_split_multi_param_lines(struct card *deck, int line_number); static void inp_sort_params(struct card *param_cards, struct card *card_bf_start, struct card *s_c, struct card *e_c); -char *inp_remove_ws(char *s); static void inp_compat(struct card *deck); static void inp_bsource_compat(struct card *deck); static bool inp_temper_compat(struct card *card); @@ -153,7 +152,7 @@ static char inp_get_elem_ident(char *type); static void rem_mfg_from_models(struct card *start_card); static void inp_fix_macro_param_func_paren_io(struct card *begin_card); static void inp_fix_gnd_name(struct card *deck); -static void inp_chk_for_multi_in_vcvs(struct card *deck, int *line_number); +static void inp_chk_for_e_source_to_xspice(struct card *deck, int *line_number); static void inp_add_control_section(struct card *deck, int *line_number); static char *get_quoted_token(char *string, char **token); static void replace_token(char *string, char *token, int where, int total); @@ -167,7 +166,6 @@ static void inp_check_syntax(struct card *deck); static char *inp_spawn_brace(char *s); static char *inp_pathresolve_at(const char *name, const char *dir); -char *search_plain_identifier(char *str, const char *identifier); struct nscope *inp_add_levels(struct card *deck); static struct card_assoc *find_subckt(struct nscope *scope, const char *name); @@ -177,6 +175,7 @@ static struct modellist *inp_find_model( struct nscope *scope, const char *name); void tprint(struct card *deck); +static char* libprint(struct card* t, const char *dir); static void inp_repair_dc_ps(struct card* oldcard); static void inp_get_w_l_x(struct card* oldcard); @@ -185,8 +184,6 @@ static char* eval_m(char* line, char* tline); static char* eval_tc(char* line, char* tline); static char* eval_mvalue(char* line, char* tline); -static void rem_double_braces(struct card* card); - extern void inp_probe(struct card* card); #ifndef EXT_ASC static void utf8_syntax_check(struct card *deck); @@ -619,16 +616,19 @@ static char *cat2strings(char *s1, char *s2, bool spa) /* line1 + line2 ----> - line1 line 2 + line1 line2 Proccedure: store regular card in prev, skip comment lines (*..) and some - others + others, add tokens from + lines to prev using dstring. */ -static void inp_stitch_continuation_lines(struct card *working) +static void inp_stitch_continuation_lines(struct card* working) { - struct card *prev = NULL; + struct card* prev = NULL; + bool firsttime = TRUE; + + DS_CREATE(newline, 200); while (working) { - char *s, c, *buffer; + char* s, c; for (s = working->line; (c = *s) != '\0' && c <= ' '; s++) ; @@ -636,11 +636,110 @@ static void inp_stitch_continuation_lines(struct card *working) #ifdef TRACE /* SDB debug statement */ printf("In inp_read, processing linked list element line = %d, s = " - "%s . . . \n", - working->linenum, s); + "%s . . . \n", + working->linenum, s); #endif switch (c) { + case '#': + case '$': + case '*': + case '\0': + /* skip these cards, and keep prev as the last regular card */ + working = working->nextcard; /* for these chars, go to next + card */ + break; + + case '+': /* handle continuation */ + if (!prev) { + working->error = + copy("Illegal continuation line: ignored."); + working = working->nextcard; + break; + } + + /* We now may have lept over some comment lines, which are + located among the continuation lines. We have to delete them + here to prevent a memory leak */ + while (prev->nextcard != working) { + struct card* tmpl = prev->nextcard->nextcard; + line_free_x(prev->nextcard, FALSE); + prev->nextcard = tmpl; + } + + if (firsttime) { + sadd(&newline, prev->line); + firsttime = FALSE; + } + else { + /* replace '+' by space */ + *s = ' '; + sadd(&newline, s); + /* mark for later removal */ + *s = '*'; + } + + break; + + default: /* regular one-line card */ + if (!firsttime) { + tfree(prev->line); + prev->line = copy(ds_get_buf(&newline)); + ds_clear(&newline); + firsttime = TRUE; + /* remove final used '+' line, if regular line is following */ + struct card* tmpl = prev->nextcard->nextcard; + line_free_x(prev->nextcard, FALSE); + prev->nextcard = tmpl; + } + prev = working; + working = working->nextcard; + break; + } + } + /* remove final used '+' line when no regular line is following */ + if (!firsttime) { + tfree(prev->line); + prev->line = copy(ds_get_buf(&newline)); + } + ds_free(&newline); +} + +#ifdef CIDER +/* Only if we have a CIDER .model line with regular structure +'.model modname modtype level', +with modtype being one of numos, numd, nbjt: +Concatenate lines +line1 + + line2 + ----> + line1 line 2 +Store the original lines in card->actualLine, to be used for +CIDER model parameter parsing in INPparseNumMod() of inpgmod.c + */ +static void inp_cider_models(struct card* working) +{ + struct card* prev = NULL; + bool iscmod = FALSE; + + while (working) { + char *s, c, *buffer; + + for (s = working->line; (c = *s) != '\0' && c <= ' '; s++) + ; + + if(!iscmod) + iscmod = is_cider_model(s); + +#ifdef TRACE + /* SDB debug statement */ + printf("In inp_read, processing linked list element line = %d, s = " + "%s . . . \n", + working->linenum, s); +#endif + + if (iscmod) { + switch (c) { case '#': case '$': case '*': @@ -653,7 +752,7 @@ static void inp_stitch_continuation_lines(struct card *working) case '+': /* handle continuation */ if (!prev) { working->error = - copy("Illegal continuation line: ignored."); + copy("Illegal continuation line: ignored."); working = working->nextcard; break; } @@ -662,7 +761,7 @@ static void inp_stitch_continuation_lines(struct card *working) located among the continuation lines. We have to delete them here to prevent a memory leak */ while (prev->nextcard != working) { - struct card *tmpl = prev->nextcard->nextcard; + struct card* tmpl = prev->nextcard->nextcard; line_free_x(prev->nextcard, FALSE); prev->nextcard = tmpl; } @@ -670,14 +769,14 @@ static void inp_stitch_continuation_lines(struct card *working) /* create buffer and write last and current line into it. When reading a PDK, the following may be called more than 1e6 times. */ #if defined (_MSC_VER) - /* vsnprintf (used by tprintf) in Windows is efficient, VS2019 arb. referencevalue 7, - cat2strings() yields ref. speed value 12 only, CYGWIN is 12 in both cases, - MINGW is 36. */ + /* vsnprintf (used by tprintf) in Windows is efficient, VS2019 arb. referencevalue 7, + cat2strings() yields ref. speed value 12 only, CYGWIN is 12 in both cases, + MINGW is 36. */ buffer = tprintf("%s %s", prev->line, s + 1); #else - /* vsnprintf in Linux is very inefficient, ref. value 24 - cat2strings() is efficient with ref. speed value 6, - MINGW is 12 */ + /* vsnprintf in Linux is very inefficient, ref. value 24 + cat2strings() is efficient with ref. speed value 6, + MINGW is 12 */ buffer = cat2strings(prev->line, s + 1, TRUE); #endif /* replace prev->line by buffer */ @@ -687,16 +786,16 @@ static void inp_stitch_continuation_lines(struct card *working) working->nextcard = NULL; /* add original line to prev->actualLine */ if (prev->actualLine) { - struct card *end; + struct card* end; for (end = prev->actualLine; end->nextcard; - end = end->nextcard) + end = end->nextcard) ; end->nextcard = working; tfree(s); } else { prev->actualLine = - insert_new_line(NULL, s, prev->linenum, 0); + insert_new_line(NULL, s, prev->linenum, 0); prev->actualLine->level = prev->level; prev->actualLine->nextcard = working; } @@ -706,11 +805,15 @@ static void inp_stitch_continuation_lines(struct card *working) default: /* regular one-line card */ prev = working; working = working->nextcard; + iscmod = is_cider_model(s); break; + } } + else + working = working->nextcard; } } - +#endif /* * search for `=' assignment operator @@ -929,8 +1032,8 @@ struct card *inp_readall(FILE *fp, const char *dir_name, utf8_syntax_check(working); #endif - /* some syntax checks, including title line */ - inp_check_syntax(cc); + /* some syntax checks, excluding title line */ + inp_check_syntax(working); if (newcompat.lt && newcompat.a) ltspice_compat_a(working); @@ -992,7 +1095,7 @@ struct card *inp_readall(FILE *fp, const char *dir_name, subckt_w_params = NULL; if (!cp_getvar("no_auto_gnd", CP_BOOL, NULL, 0)) inp_fix_gnd_name(working); - inp_chk_for_multi_in_vcvs(working, &rv.line_number); + inp_chk_for_e_source_to_xspice(working, &rv.line_number); /* "addcontrol" variable is set if "ngspice -a file" was used. */ @@ -1587,6 +1690,10 @@ struct inp_read_t inp_read( FILE *fp, int call_depth, const char *dir_name, if this is a command file or called from within a .control section. */ inp_stripcomments_deck(cc->nextcard, comfile || is_control); +#ifdef CIDER + inp_cider_models(cc->nextcard); +#endif + inp_stitch_continuation_lines(cc->nextcard); rv.line_number = line_number; @@ -1906,7 +2013,6 @@ static void inp_fix_gnd_name(struct card *c) } } - /* * transform a VCVS "gate" instance into a XSPICE instance * @@ -1924,7 +2030,336 @@ static void inp_fix_gnd_name(struct card *c) * the x,y list is fixed to length 2 */ -static void inp_chk_for_multi_in_vcvs(struct card *c, int *line_number) +static int inp_chk_for_multi_in_vcvs(struct card *c, int *line_number) +{ + char *fcn_b, *line; + + line = c->line; + if (((fcn_b = strstr(line, "nand(")) != NULL || + (fcn_b = strstr(line, "and(")) != NULL || + (fcn_b = strstr(line, "nor(")) != NULL || + (fcn_b = strstr(line, "or(")) != NULL) && + isspace_c(fcn_b[-1])) { +#ifndef XSPICE + fprintf(stderr, + "\n" + "Error: XSPICE is required to run the 'multi-input " + "pwl' option in line %d\n" + " %s\n" + "\n" + "See manual chapt. 31 for installation " + "instructions\n", + *line_number, line); + controlled_exit(EXIT_BAD); +#else + char keep, *comma_ptr, *xy_values1[5], *xy_values2[5]; + char *out_str, *ctrl_nodes_str, + *xy_values1_b = NULL, *ref_str, *fcn_name, + *fcn_e = NULL, *out_b, *out_e, *ref_e; + char *m_instance, *m_model; + char *xy_values2_b = NULL, *xy_values1_e = NULL, + *ctrl_nodes_b = NULL, *ctrl_nodes_e = NULL; + int xy_count1, xy_count2; + bool ok = FALSE; + + do { + ref_e = skip_non_ws(line); + + out_b = skip_ws(ref_e); + + out_e = skip_back_ws(fcn_b, out_b); + if (out_e <= out_b) + break; + + fcn_e = strchr(fcn_b, '('); + + ctrl_nodes_b = strchr(fcn_e, ')'); + if (!ctrl_nodes_b) + break; + ctrl_nodes_b = skip_ws(ctrl_nodes_b + 1); + + comma_ptr = strchr(ctrl_nodes_b, ','); + if (!comma_ptr) + break; + + xy_values1_b = skip_back_ws(comma_ptr, ctrl_nodes_b); + if (xy_values1_b[-1] == '}') { + while (--xy_values1_b >= ctrl_nodes_b) + if (*xy_values1_b == '{') + break; + } else { + xy_values1_b = skip_back_non_ws(xy_values1_b, ctrl_nodes_b); + } + if (xy_values1_b <= ctrl_nodes_b) + break; + + ctrl_nodes_e = skip_back_ws(xy_values1_b, ctrl_nodes_b); + if (ctrl_nodes_e <= ctrl_nodes_b) + break; + + xy_values1_e = skip_ws(comma_ptr + 1); + if (*xy_values1_e == '{') { + xy_values1_e = inp_spawn_brace(xy_values1_e); + } else { + xy_values1_e = skip_non_ws(xy_values1_e); + } + if (!xy_values1_e) + break; + + xy_values2_b = skip_ws(xy_values1_e); + + ok = TRUE; + } while (0); + + if (!ok) { + fprintf(stderr, "ERROR: malformed line: %s\n", line); + controlled_exit(EXIT_FAILURE); + } + + ref_str = copy_substring(line, ref_e); + out_str = copy_substring(out_b, out_e); + fcn_name = copy_substring(fcn_b, fcn_e); + ctrl_nodes_str = copy_substring(ctrl_nodes_b, ctrl_nodes_e); + + keep = *xy_values1_e; + *xy_values1_e = '\0'; + xy_count1 = + get_comma_separated_values(xy_values1, xy_values1_b); + *xy_values1_e = keep; + + xy_count2 = get_comma_separated_values(xy_values2, xy_values2_b); + + // place restrictions on only having 2 point values; this can + // change later + if (xy_count1 != 2 && xy_count2 != 2) + fprintf(stderr, + "ERROR: only expecting 2 pair values for " + "multi-input vcvs!\n"); + + m_instance = tprintf("%s %%vd[ %s ] %%vd( %s ) %s", ref_str, + ctrl_nodes_str, out_str, ref_str); + m_instance[0] = 'a'; + + m_model = tprintf(".model %s multi_input_pwl ( x = [%s %s] y " + "= [%s %s] model = \"%s\" )", + ref_str, xy_values1[0], xy_values2[0], xy_values1[1], + xy_values2[1], fcn_name); + + tfree(ref_str); + tfree(out_str); + tfree(fcn_name); + tfree(ctrl_nodes_str); + tfree(xy_values1[0]); + tfree(xy_values1[1]); + tfree(xy_values2[0]); + tfree(xy_values2[1]); + + *c->line = '*'; + c = insert_new_line(c, m_instance, (*line_number)++, c->linenum_orig); + c = insert_new_line(c, m_model, (*line_number)++, c->linenum_orig); +#endif + return 1; + } else { + return 0; // No keyword match. */ + } +} + +/* replace the E and G source FREQ function by an XSPICE xfer instance + * (used by Touchstone to netlist converter programs). + * E1 n1 n2 FREQ {expression} = DB values ... + * will become + * B1_gen 1_gen 0 v = expression + * A1_gen 1_gen %d(n1 n2) 1_gen + * .model 1_gen xfer db=true table=[ values ] + */ + +static void replace_freq(struct card *c, int *line_number) +{ +#ifdef XSPICE + char *line, *e, *e_e, *n1, *n1_e, *n2, *n2_e, *freq; + char *expr, *expr_e, *in, *in_e, *keywd, *cp, *list, *list_e; + int db, ri, rad, got_key, diff; + char pt, key[4]; + + line = c->line; + + /* First token is a node name. */ + + e = line + 1; + e_e = skip_non_ws(e); + n1 = skip_ws(e_e); + n1_e = skip_non_ws(n1); + freq = strstr(n1_e, "freq"); + if (!freq || !isspace_c(freq[-1]) || !isspace_c(freq[4])) + return; + n2 = skip_ws(n1_e); + if (n2 == freq) { + n2 = NULL; + } else { + n2_e = skip_non_ws(n2); + if (freq != skip_ws(n2_e)) // Three nodes or another keyword. + return; + } + + /* Isolate the input expression. */ + + expr = skip_ws(freq + 4); + if (*expr != '{') + return; + expr = skip_ws(expr + 1); + expr_e = strchr(expr, '}'); + if (!expr_e) + return; + skip_back_ws(expr_e, expr); + + /* Is the expression just a node name, or v(node) or v(node1, node2)? */ + + in = NULL; + diff = 0; + if (*expr < '0' || *expr > '9') { + for (in_e = expr; in_e < expr_e; ++in_e) { + if ((*in_e < '0' || *in_e > '9') && (*in_e < 'a' || *in_e > 'z') && + *in_e != '_') + break; + } + if (in_e == expr_e) { + /* A simple identifier. */ + + in = expr; + } + } + if (expr[0] == 'v' && expr[1] == '(' && expr_e[-1] == ')') { + in = expr + 2; + in_e = expr_e - 1; + cp = strchr(in, ','); + diff = (cp && cp < in_e); // Assume v(n1, n2) + } + + /* Look for a keyword. Previous processing may put braces around it. */ + + keywd = skip_ws(expr_e + 1); + if (*keywd == '=') + keywd = skip_ws(keywd + 1); + + db = 1; + rad = 0; + ri = 0; + do { + if (!keywd) + return; + list = keywd; // Perhaps not keyword + if (*keywd == '{') + ++keywd; + cp = key; + while (*keywd && !isspace_c(*keywd) && *keywd != '}' && + cp - key < sizeof key - 1) { + *cp++ = *keywd++; + } + *cp = 0; + if (*keywd == '}') + ++keywd; + if (!isspace_c(*keywd)) + return; + + /* Parse the format keyword, if any. */ + + got_key = 0; + if (!strcmp(key, "mag")) { + db = 0; + got_key = 1; + } else if (!strcmp(key, "db")) { + db = 1; + got_key = 1; + } else if (!strcmp(key, "rad")) { + rad = 1; + got_key = 1; + } else if (!strcmp(key, "deg")) { + rad = 0; + got_key = 1; + } else if (!strcmp(key, "r_i")) { + ri = 1; + got_key = 1; + } + + /* Get the list of values. */ + + if (got_key) + list = skip_ws(keywd); + if (!list) + return; + keywd = list; + } while(got_key); + + list_e = list + strlen(list) - 1; + skip_back_ws(list_e, list); + if (list >= list_e) + return; + + /* All good, rewrite the line. + * Macro BSTR is used to pass counted string arguments to tprintf(). + */ + +#define BSTR(s) (int)(s##_e - s), s + + pt = (*line == 'e') ? 'v' : 'i'; + *line = '*'; // Make a comment + if (in) { + /* Connect input nodes directly. */ + + if (diff) { + /* Differential input. */ + + if (n2) { + line = tprintf("a_gen_%.*s %%vd(%.*s) %%%cd(%.*s %.*s) " + "gen_model_%.*s", + BSTR(e), BSTR(in), pt, BSTR(n1), BSTR(n2), BSTR(e)); + } else { + line = tprintf("a_gen_%.*s %%vd(%.*s) %%%c(%.*s) " + "gen_model_%.*s", + BSTR(e), BSTR(in), pt, BSTR(n1), BSTR(e)); + } + } else { + /* Single node input. */ + + if (n2) { + line = tprintf("a_gen_%.*s %.*s %%%cd(%.*s %.*s) " + "gen_model_%.*s", + BSTR(e), BSTR(in), pt, BSTR(n1), BSTR(n2), + BSTR(e)); + } else { + line = tprintf("a_gen_%.*s %.*s %%%c(%.*s) gen_model_%.*s", + BSTR(e), BSTR(in), pt, BSTR(n1), BSTR(e)); + } + } + } else { + /* Use a B-source for input. */ + + line = tprintf("b_gen_%.*s gen_node_%.*s 0 v=%.*s", + BSTR(e), BSTR(e), BSTR(expr)); + c = insert_new_line(c, line, (*line_number)++, c->linenum_orig); + if (n2) { + line = tprintf("a_gen_%.*s gen_node_%.*s %%%cd(%.*s %.*s) " + "gen_model_%.*s", + BSTR(e), BSTR(e), pt, BSTR(n1), BSTR(n2), BSTR(e)); + } else { + line = tprintf("a_gen_%.*s gen_node_%.*s %%%c(%.*s) " + "gen_model_%.*s", + BSTR(e), BSTR(e), pt, BSTR(n1), BSTR(e)); + } + } + c = insert_new_line(c, line, (*line_number)++, c->linenum_orig); + + line = tprintf(".model gen_model_%.*s xfer %s table = [%.*s]", + BSTR(e), + ri ? "r_i=true" : rad ? "rad=true" : !db ? "db=false" : "", + BSTR(list)); + c = insert_new_line(c, line, (*line_number)++, c->linenum_orig); +#endif +} + +/* Convert some E and G-source variants to XSPICE code models. */ + +static void inp_chk_for_e_source_to_xspice(struct card *c, int *line_number) { int skip_control = 0; @@ -1945,143 +2380,17 @@ static void inp_chk_for_multi_in_vcvs(struct card *c, int *line_number) continue; } - if (*line == 'e') { + if (*line == 'e' && inp_chk_for_multi_in_vcvs(c, line_number)) + continue; + if (*line != 'e' && *line != 'g') + continue; - char *fcn_b; + /* Is it the FREQ form with S-parameter table? */ - if (((fcn_b = strstr(line, "nand(")) != NULL || - (fcn_b = strstr(line, "and(")) != NULL || - (fcn_b = strstr(line, "nor(")) != NULL || - (fcn_b = strstr(line, "or(")) != NULL) && - isspace_c(fcn_b[-1])) { -#ifndef XSPICE - fprintf(stderr, - "\n" - "Error: XSPICE is required to run the 'multi-input " - "pwl' option in line %d\n" - " %s\n" - "\n" - "See manual chapt. 31 for installation " - "instructions\n", - *line_number, line); - controlled_exit(EXIT_BAD); -#else - char keep, *comma_ptr, *xy_values1[5], *xy_values2[5]; - char *out_str, *ctrl_nodes_str, - *xy_values1_b = NULL, *ref_str, *fcn_name, - *fcn_e = NULL, *out_b, *out_e, *ref_e; - char *m_instance, *m_model; - char *xy_values2_b = NULL, *xy_values1_e = NULL, - *ctrl_nodes_b = NULL, *ctrl_nodes_e = NULL; - int xy_count1, xy_count2; - bool ok = FALSE; - - do { - ref_e = skip_non_ws(line); - - out_b = skip_ws(ref_e); - - out_e = skip_back_ws(fcn_b, out_b); - if (out_e <= out_b) - break; - - fcn_e = strchr(fcn_b, '('); - - ctrl_nodes_b = strchr(fcn_e, ')'); - if (!ctrl_nodes_b) - break; - ctrl_nodes_b = skip_ws(ctrl_nodes_b + 1); - - comma_ptr = strchr(ctrl_nodes_b, ','); - if (!comma_ptr) - break; - - xy_values1_b = skip_back_ws(comma_ptr, ctrl_nodes_b); - if (xy_values1_b[-1] == '}') { - while (--xy_values1_b >= ctrl_nodes_b) - if (*xy_values1_b == '{') - break; - } - else { - xy_values1_b = - skip_back_non_ws(xy_values1_b, ctrl_nodes_b); - } - if (xy_values1_b <= ctrl_nodes_b) - break; - - ctrl_nodes_e = skip_back_ws(xy_values1_b, ctrl_nodes_b); - if (ctrl_nodes_e <= ctrl_nodes_b) - break; - - xy_values1_e = skip_ws(comma_ptr + 1); - if (*xy_values1_e == '{') { - xy_values1_e = inp_spawn_brace(xy_values1_e); - } - else { - xy_values1_e = skip_non_ws(xy_values1_e); - } - if (!xy_values1_e) - break; - - xy_values2_b = skip_ws(xy_values1_e); - - ok = TRUE; - } while (0); - - if (!ok) { - fprintf(stderr, "ERROR: malformed line: %s\n", line); - controlled_exit(EXIT_FAILURE); - } - - ref_str = copy_substring(line, ref_e); - out_str = copy_substring(out_b, out_e); - fcn_name = copy_substring(fcn_b, fcn_e); - ctrl_nodes_str = copy_substring(ctrl_nodes_b, ctrl_nodes_e); - - keep = *xy_values1_e; - *xy_values1_e = '\0'; - xy_count1 = - get_comma_separated_values(xy_values1, xy_values1_b); - *xy_values1_e = keep; - - xy_count2 = - get_comma_separated_values(xy_values2, xy_values2_b); - - // place restrictions on only having 2 point values; this can - // change later - if (xy_count1 != 2 && xy_count2 != 2) - fprintf(stderr, - "ERROR: only expecting 2 pair values for " - "multi-input vcvs!\n"); - - m_instance = tprintf("%s %%vd[ %s ] %%vd( %s ) %s", ref_str, - ctrl_nodes_str, out_str, ref_str); - m_instance[0] = 'a'; - - m_model = tprintf(".model %s multi_input_pwl ( x = [%s %s] y " - "= [%s %s] model = \"%s\" )", - ref_str, xy_values1[0], xy_values2[0], xy_values1[1], - xy_values2[1], fcn_name); - - tfree(ref_str); - tfree(out_str); - tfree(fcn_name); - tfree(ctrl_nodes_str); - tfree(xy_values1[0]); - tfree(xy_values1[1]); - tfree(xy_values2[0]); - tfree(xy_values2[1]); - - *c->line = '*'; - c = insert_new_line(c, m_instance, (*line_number)++, c->linenum_orig); - c = insert_new_line(c, m_model, (*line_number)++, c->linenum_orig); -#endif - } - } + replace_freq(c, line_number); } } - /* If ngspice is started with option -a, then variable 'autorun' * will be set and a control section is inserted to try and ensure * some analysis is done; @@ -3300,13 +3609,23 @@ static struct card *expand_section_ref(struct card *c, const char *dir_name) * every library section reference (when the given section_name_ === NULL) * or * just those references occuring in the given library section definition + * + * Command .libsave saves the loaded and parsed lib, to be read by .include */ static void expand_section_references(struct card *c, const char *dir_name) { - for (; c; c = c->nextcard) - if (ciprefix(".lib", c->line)) + for (; c; c = c->nextcard) { + struct card* p = c; + if (ciprefix(".libsave", c->line)) { c = expand_section_ref(c, dir_name); + char *filename = libprint(p, dir_name); + fprintf(stdout, "\nLibrary\n%s\nsaved to %s\n", p->line + 9, filename); + tfree(filename); + } + else if (ciprefix(".lib", c->line)) + c = expand_section_ref(c, dir_name); + } } @@ -4239,7 +4558,7 @@ static void inp_fix_param_values(struct card *c) brackets around all params inside a pair of square brackets */ end_of_str = beg_of_str; - while (*end_of_str != ']') + while (*end_of_str != ']' && *end_of_str != '\0') end_of_str++; /* string xx yyy from vector [xx yyy] */ tmp_str = vec_str = @@ -4315,7 +4634,7 @@ static void inp_fix_param_values(struct card *c) /* A complex value following the '=' token: code to put curly brackets around all params inside a pair < > */ end_of_str = beg_of_str; - while (*end_of_str != '>') + while (*end_of_str != '>' && *end_of_str != '\0') end_of_str++; /* string xx yyy from vector [xx yyy] */ vec_str = copy_substring(beg_of_str + 1, end_of_str); @@ -4480,7 +4799,8 @@ static int inp_get_param_level( return level; } - +/* Return the number of terminals for a given device, characterized by + the first letter of its instance line. Returns 0 upon error. */ int get_number_terminals(char *c) { int i, j, k; @@ -4488,6 +4808,9 @@ int get_number_terminals(char *c) char nam_buf[128]; bool area_found = FALSE; + if (!c) + return 0; + switch (*c) { case 'r': case 'c': @@ -5917,14 +6240,9 @@ static void inp_compat(struct card *card) /* Find equation, starts with '{', till end of line */ str_ptr = strchr(cut_line, '{'); if (str_ptr == NULL) { - /* if not, equation may start with a '(' */ - str_ptr = strchr(cut_line, '('); - if (str_ptr == NULL) { - fprintf(stderr, "ERROR: mal formed R line: %s\n", - curr_line); - controlled_exit(EXIT_FAILURE); - } - equation = gettok_char(&str_ptr, ')', TRUE, TRUE); + fprintf(stderr, "ERROR: mal formed R line: %s\n", curr_line); + fprintf(stderr, " {...} or '...' around equation's right hand side are missing!\n"); + controlled_exit(EXIT_FAILURE); } else equation = gettok_char(&str_ptr, '}', TRUE, TRUE); @@ -6001,14 +6319,9 @@ static void inp_compat(struct card *card) /* Find equation, starts with '{', till end of line */ str_ptr = strchr(cut_line, '{'); if (str_ptr == NULL) { - /* if not, equation may start with a '(' */ - str_ptr = strchr(cut_line, '('); - if (str_ptr == NULL) { - fprintf(stderr, "ERROR: mal formed C line: %s\n", - curr_line); - controlled_exit(EXIT_FAILURE); - } - equation = gettok_char(&str_ptr, ')', TRUE, TRUE); + fprintf(stderr, "ERROR: mal formed C line: %s\n", curr_line); + fprintf(stderr, " {...} or '...' around equation's right hand side are missing!\n"); + controlled_exit(EXIT_FAILURE); } else equation = gettok_char(&str_ptr, '}', TRUE, TRUE); @@ -6076,14 +6389,9 @@ static void inp_compat(struct card *card) /* Find equation, starts with '{', till end of line */ str_ptr = strchr(cut_line, '{'); if (str_ptr == NULL) { - /* if not, equation may start with a '(' */ - str_ptr = strchr(cut_line, '('); - if (str_ptr == NULL) { - fprintf(stderr, "ERROR: mal formed L line: %s\n", - curr_line); - controlled_exit(EXIT_FAILURE); - } - equation = gettok_char(&str_ptr, ')', TRUE, TRUE); + fprintf(stderr, "ERROR: mal formed L line: %s\n", curr_line); + fprintf(stderr, " {...} or '...' around equation's right hand side are missing!\n"); + controlled_exit(EXIT_FAILURE); } else equation = gettok_char(&str_ptr, '}', TRUE, TRUE); @@ -6921,6 +7229,27 @@ static void inp_poly_err(struct card *card) #endif +/* Print the parsed library to lib_out?.lib, with ? a growing number + if multiple libs are saved in a single run. Don't save the .libsave line.*/ +static char* libprint(struct card* t, const char *dir_name) +{ + struct card* tmp; + static int npr = 1; + char *outfile = tprintf("%s/lib_out%d.lib", dir_name, npr); + npr++; + FILE* fd = fopen(outfile, "w"); + if (fd) { + for (tmp = t; tmp; tmp = tmp->nextcard) + if (*(tmp->line) != '*' && !ciprefix(".libsave", tmp->line)) + fprintf(fd, "%s\n", tmp->line); + fclose(fd); + } + else { + fprintf(stderr, "Warning: Can't open file %s \n command .libsave ignored!\n", outfile); + } + return outfile; +} + /* Used for debugging. You may add * tprint(working); @@ -8020,14 +8349,14 @@ static void inp_check_syntax(struct card *deck) if (*cut_line == '*' || *cut_line == '\0') continue; // check for unusable leading characters and change them to '*' - if (strchr("=[]?()&%$\"!:,\f;", *cut_line)) { + if (strchr("=[]?()&%$\"!:,\f", *cut_line)) { if (ft_stricterror) { fprintf(stderr, "Error: '%c' is not allowed as first character in line %s.\n", *cut_line, cut_line); controlled_exit(EXIT_BAD); } else { if (!check_ch) { - fprintf(stderr, "Warning: Unusual leading characters like '%c' or others out of '= [] ? () & %% $\"!:,;\\f'\n", *cut_line); + fprintf(stderr, "Warning: Unusual leading characters like '%c' or others out of '= [] ? () & %% $\"!:,\\f'\n", *cut_line); fprintf(stderr, " in netlist or included files, will be replaced with '*'.\n"); fprintf(stderr, " Check line no %d: %s\n\n", card->linenum_orig, cut_line); check_ch = 1; /* just one warning */ @@ -8035,6 +8364,10 @@ static void inp_check_syntax(struct card *deck) *cut_line = '*'; } } + /* leading end-of-line delimiter ';' silently change to '*' */ + else if (*cut_line == ';') { + *cut_line = '*'; + } // check for .control ... .endc if (ciprefix(".control", cut_line)) { if (check_control > 0) { @@ -8092,7 +8425,17 @@ static void inp_check_syntax(struct card *deck) /* check for missing ac in voltage or current source */ if (check_control == 0 && strchr("VvIi", *cut_line)) { int err = 0; - char* acline = search_plain_identifier(cut_line, "ac"); + char* acline; + /* skip instance name and nodes */ + acline = nexttok(cut_line); + acline = nexttok(acline); + acline = nexttok(acline); + if (!acline) { + fprintf(stderr, "Error in line %s\n", cut_line); + fprintf(stderr, " Not enough parameters\n"); + controlled_exit(EXIT_BAD); + } + acline = search_plain_identifier(acline, "ac"); if (acline == NULL) continue; /* skip ac */ @@ -8109,17 +8452,20 @@ static void inp_check_syntax(struct card *deck) char* nnacline = nacline; /* get first token after ac */ char* numtok = gettok_node(&nnacline); - char* numtokfree = numtok; - /* Check if token is a parameter, to be filled in later */ - if (*numtok == '\'' || *numtok == '{') { - err = 0; + if (numtok) { + char* numtokfree = numtok; + /* Check if token is a parameter, to be filled in later */ + if (*numtok == '\'' || *numtok == '{') { + err = 0; + } + else { + /* check if token is a valid number */ + INPevaluate(&numtok, &err, 0); + } + tfree(numtokfree); } - else { - /* check if token is a valid number */ - INPevaluate(&numtok, &err, 0); - } - - tfree(numtokfree); + else + err = 1; } /* if no number, replace 'ac' by 'ac 1 0' */ if (err){ @@ -8672,7 +9018,7 @@ utf8_syntax_check(struct card *deck) s = utf8_check((unsigned char*)curr_line); if (s) { - fprintf(stderr, "Error: UTF-8 syntax error in line %d at %s\n", card->linenum_orig, s); + fprintf(stderr, "Error: UTF-8 syntax error in input deck,\n line %d at token/word %s\n", card->linenum_orig, s); controlled_exit(1); } } diff --git a/src/frontend/measure.c b/src/frontend/measure.c index 9ca735a3f..c91715a11 100644 --- a/src/frontend/measure.c +++ b/src/frontend/measure.c @@ -283,6 +283,22 @@ do_measure( resname = gettok(&line); meastype = gettok(&line); + if (!an_type){ + fprintf(cp_err, "\nWarning: Incomplete measurement statement in line\n %s\nignored!\n", meas_card->line); + continue; + } + if (!resname){ + fprintf(cp_err, "\nWarning: Incomplete measurement statement in line\n %s\nignored!\n", meas_card->line); + tfree(an_type); + continue; + } + if (!meastype) { + fprintf(cp_err, "\nWarning: Incomplete measurement statement in line\n %s\nignored!\n", meas_card->line); + tfree(an_type); + tfree(resname); + continue; + } + if (chkAnalysisType(an_type) != TRUE) { if (!chk_only) { fprintf(cp_err, "Error: unrecognized analysis type '%s' for the following .meas statement on line %d:\n", an_type, meas_card->linenum); @@ -399,6 +415,20 @@ do_measure( resname = gettok(&line); meastype = gettok(&line); + if (!an_type) { + /* Warnings have already been issued in first pass */ + continue; + } + if (!resname) { + tfree(an_type); + continue; + } + if (!meastype) { + tfree(an_type); + tfree(resname); + continue; + } + if (chkAnalysisType(an_type) != TRUE) { if (!chk_only) { fprintf(cp_err, "Error: unrecognized analysis type '%s' for the following .meas statement on line %d:\n", an_type, meas_card->linenum); diff --git a/src/frontend/numparam/xpressn.c b/src/frontend/numparam/xpressn.c index a8ac9b6f5..7df535340 100644 --- a/src/frontend/numparam/xpressn.c +++ b/src/frontend/numparam/xpressn.c @@ -1611,8 +1611,12 @@ nupa_subcktcall(dico_t *dico, const char *s, const char *x, jp = getexpress(dico, NULL, &ustr, jp); } else { jp++; - if ((unsigned char) (*kp) > ' ') - message(dico, "Subckt call, symbol %c not understood\n", *kp); + if ((unsigned char)(*kp) > ' ') { + fprintf(stderr, "Error in line: %s\n", x); + fprintf(stderr, " near %s\n", kp); + message(dico, "Subckt call, symbol %c not understood\n\n", *kp); + + } } /* Substitute the parameter for one of the '$' characters diff --git a/src/frontend/outitf.c b/src/frontend/outitf.c index 6bae09b34..2ed33d5d4 100644 --- a/src/frontend/outitf.c +++ b/src/frontend/outitf.c @@ -627,7 +627,7 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr) if (!orflag && !ft_norefprint) { currclock = clock(); if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) { - fprintf(stderr, " Reference value : % 12.5e\r", + fprintf(stdout, " Reference value : % 12.5e\r", refValue->cValue.real); lastclock = currclock; } @@ -640,7 +640,7 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr) if (!orflag && !ft_norefprint) { currclock = clock(); if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) { - fprintf(stderr, " Reference value : % 12.5e\r", + fprintf(stdout, " Reference value : % 12.5e\r", refValue->rValue); lastclock = currclock; } @@ -735,10 +735,10 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr) currclock = clock(); if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) { if (run->isComplex) { - fprintf(stderr, " Reference value : % 12.5e\r", + fprintf(stdout, " Reference value : % 12.5e\r", refValue ? refValue->cValue.real : NAN); } else { - fprintf(stderr, " Reference value : % 12.5e\r", + fprintf(stdout, " Reference value : % 12.5e\r", refValue ? refValue->rValue : NAN); } lastclock = currclock; @@ -1506,7 +1506,7 @@ InterpFileAdd(runDesc *run, IFvalue *refValue, IFvalue *valuePtr) if (!orflag && !ft_norefprint) { currclock = clock(); if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) { - fprintf(stderr, " Reference value : % 12.5e\r", + fprintf(stdout, " Reference value : % 12.5e\r", refValue->rValue); lastclock = currclock; } @@ -1670,7 +1670,7 @@ InterpPlotAdd(runDesc *run, IFvalue *refValue, IFvalue *valuePtr) if (!orflag && !ft_norefprint) { currclock = clock(); if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) { - fprintf(stderr, " Reference value : % 12.5e\r", + fprintf(stdout, " Reference value : % 12.5e\r", refValue->rValue); lastclock = currclock; } diff --git a/src/frontend/parse.c b/src/frontend/parse.c index 16666a1bc..ebe22d309 100644 --- a/src/frontend/parse.c +++ b/src/frontend/parse.c @@ -360,6 +360,7 @@ struct func ft_funcs[] = { { "avg", cx_avg }, /* A.Roldan 03/06/05 incremental average new function */ { "group_delay", (cx_function_t*)(void *) cx_group_delay }, /* A.Roldan 10/06/05 group delay new function */ { "vector", cx_vector }, + { "cvector", cx_cvector }, { "unitvec", cx_unitvec }, { "length", cx_length }, { "vecmin", cx_min }, diff --git a/src/frontend/parser/cshpar.c b/src/frontend/parser/cshpar.c index 35a31c9e9..b4cfa7fc8 100644 --- a/src/frontend/parser/cshpar.c +++ b/src/frontend/parser/cshpar.c @@ -37,8 +37,8 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group #include #endif - -bool cp_no_histsubst = FALSE; /* perform history substitution by default */ +/* perform history substitution only when variable 'histsubst' is set */ +bool cp_no_histsubst = TRUE; /* Things go as follows: * (1) Read the line and do some initial quoting (by setting the 8th bit), diff --git a/src/frontend/plotting/graf.c b/src/frontend/plotting/graf.c index 929a6e5fb..33e7187ae 100644 --- a/src/frontend/plotting/graf.c +++ b/src/frontend/plotting/graf.c @@ -32,8 +32,7 @@ Author: 1988 Jeffrey M. Hsu static void gr_start_internal(struct dvec *dv, bool copyvec); -static int iplot(struct plot *pl, int id); -static void set(struct plot *plot, struct dbcomm *db, bool unset, short mode); +static void set(struct plot *plot, struct dbcomm *db, bool value, short mode); static char *getitright(char *buf, double num); /* for legends, set in gr_start, reset in gr_iplot and gr_init */ @@ -844,28 +843,31 @@ void gr_restoretext(GRAPH *graph) * XXX Or maybe even something more drastic ?? * It would be better to associate a color with an instance using a * vector than the vector itself, for which color is something artificial. */ -static int iplot(struct plot *pl, int id) +static int iplot(struct plot *pl, struct dbcomm *db) { - int len = pl->pl_scale->v_length; + double window; + int len = pl->pl_scale->v_length; if (ft_grdb) { fprintf(cp_err, "Entering iplot, len = %d\n", len); } /* Do simple check for exit first */ - if (len < IPOINTMIN) { /* Nothing yet */ + + window = db->db_value1; + if (len < 2 || (window == 0.0 && len < IPOINTMIN)) { /* Nothing yet */ return 0; } - struct dvec *v, *xs = pl->pl_scale; - double *lims, dy; - double start, stop, step; - bool changed = FALSE; - int yt; - double xlims[2], ylims[2]; + struct dvec *v, *xs = pl->pl_scale; + double *lims, dy; + double start, stop, step; + bool changed = FALSE; + int id, yt; + double xlims[2], ylims[2]; static REQUEST reqst = { checkup_option, NULL }; - int inited = 0; - int n_vec_plot = 0; + int inited = 0; + int n_vec_plot = 0; /* Exit if nothing is being plotted */ for (v = pl->pl_dvecs; v; v = v->v_next) { @@ -878,7 +880,8 @@ static int iplot(struct plot *pl, int id) return 0; } - if (len == IPOINTMIN || !id) { /* Do initialization */ + id = db->db_graphid; + if (!id) { /* Do initialization */ unsigned int index, node_len; char commandline[4196]; @@ -889,6 +892,14 @@ static int iplot(struct plot *pl, int id) lims = ft_minmax(xs, TRUE); xlims[0] = lims[0]; xlims[1] = lims[1]; + if (window) { + if (xlims[1] - xlims[0] > window) { + xlims[1] += window / 3.0; // Assume increasing scale. + xlims[0] = xlims[1] - window; + } else { + xlims[1] = xlims[0] + window; + } + } ylims[0] = HUGE; ylims[1] = -ylims[0]; for (v = pl->pl_dvecs; v; v = v->v_next) { @@ -918,7 +929,7 @@ static int iplot(struct plot *pl, int id) if (ft_grdb) { fprintf(cp_err, - "iplot: after 5, xlims = %G, %G, ylims = %G, %G\n", + "iplot: at start xlims = %G, %G, ylims = %G, %G\n", xlims[0], xlims[1], ylims[0], ylims[1]); } @@ -943,9 +954,9 @@ static int iplot(struct plot *pl, int id) } inited = 1; - } - else { + } else { /* plot the last points and resize if needed */ + Input(&reqst, NULL); /* Window was closed? */ @@ -954,6 +965,7 @@ static int iplot(struct plot *pl, int id) return 0; /* First see if we have to make the screen bigger */ + dy = (isreal(xs) ? xs->v_realdata[len - 1] : realpart(xs->v_compdata[len - 1])); if (ft_grdb) { @@ -964,8 +976,10 @@ static int iplot(struct plot *pl, int id) stop = HUGE; start = - stop; } + /* checking for x lo */ - while (dy < currentgraph->data.xmin) { + + if (dy < currentgraph->data.xmin) { changed = TRUE; if (ft_grdb) { fprintf(cp_err, "resize: xlo %G -> %G\n", @@ -974,20 +988,25 @@ static int iplot(struct plot *pl, int id) (currentgraph->data.xmax - currentgraph->data.xmin) * XFACTOR); } + /* set the new x lo value */ - currentgraph->data.xmin -= - (currentgraph->data.xmax - currentgraph->data.xmin) - * XFACTOR; - if (currentgraph->data.xmin < start) { - currentgraph->data.xmin = start; - break; + + if (window) { + currentgraph->data.xmin = dy - (window / 3.0); + } else { + currentgraph->data.xmin -= + (currentgraph->data.xmax - currentgraph->data.xmin) * + XFACTOR; } + if (currentgraph->data.xmin < start) + currentgraph->data.xmin = start; } - if (currentgraph->data.xmax < currentgraph->data.xmin) { - currentgraph->data.xmax = currentgraph->data.xmin; - } + /* checking for x hi */ - while (dy > currentgraph->data.xmax) { + + if (window && changed) { + currentgraph->data.xmax = currentgraph->data.xmin + window; + } else if (dy > currentgraph->data.xmax) { changed = TRUE; if (ft_grdb) { fprintf(cp_err, "resize: xhi %G -> %G\n", @@ -996,16 +1015,26 @@ static int iplot(struct plot *pl, int id) (currentgraph->data.xmax - currentgraph->data.xmin) * XFACTOR); } + /* set the new x hi value */ - currentgraph->data.xmax += - (currentgraph->data.xmax - currentgraph->data.xmin) * - XFACTOR; - if (currentgraph->data.xmax > stop) { - currentgraph->data.xmax = stop; - break; + + if (window) { + currentgraph->data.xmax = dy + (window / 3.0); + currentgraph->data.xmin = currentgraph->data.xmax - window; + } else { + currentgraph->data.xmax += + (currentgraph->data.xmax - currentgraph->data.xmin) * + XFACTOR; } + if (currentgraph->data.xmax > stop) + currentgraph->data.xmax = stop; } + + if (currentgraph->data.xmax < currentgraph->data.xmin) + currentgraph->data.xmax = currentgraph->data.xmin; + /* checking for all y values */ + for (v = pl->pl_dvecs; v; v = v->v_next) { if (!(v->v_flags & VF_PLOT)) { continue; @@ -1034,10 +1063,9 @@ static int iplot(struct plot *pl, int id) /* currentgraph->data.ymin = dy; currentgraph->data.ymin *= (1 + YFACTOR); */ } - if (currentgraph->data.ymax < currentgraph->data.ymin) { - currentgraph->data.ymax = currentgraph->data.ymin; - } + /* checking for y hi */ + while (dy > currentgraph->data.ymax) { changed = TRUE; if (ft_grdb) { @@ -1049,8 +1077,8 @@ static int iplot(struct plot *pl, int id) } /* set the new y hi value */ currentgraph->data.ymax += - (currentgraph->data.ymax - currentgraph->data.ymin) - * YFACTOR; + (currentgraph->data.ymax - currentgraph->data.ymin) * + YFACTOR; /* currentgraph->data.ymax += (dy - currentgraph->data.ymax) * YFACTOR;*/ /* currentgraph->data.ymax = dy; @@ -1058,6 +1086,9 @@ static int iplot(struct plot *pl, int id) } } + if (currentgraph->data.ymax < currentgraph->data.ymin) + currentgraph->data.ymax = currentgraph->data.ymin; + if (changed) { /* Redraw everything. */ gr_pmsg("Resizing screen"); @@ -1094,17 +1125,17 @@ static int iplot(struct plot *pl, int id) } -static void set(struct plot *plot, struct dbcomm *db, bool unset, short mode) +static void set(struct plot *plot, struct dbcomm *db, bool value, short mode) { struct dvec *v; struct dbcomm *dc; if (db->db_type == DB_IPLOTALL || db->db_type == DB_TRACEALL) { for (v = plot->pl_dvecs; v; v = v->v_next) - if (unset) - v->v_flags &= (short) ~mode; - else + if (value) v->v_flags |= mode; + else + v->v_flags &= (short) ~mode; return; } @@ -1113,17 +1144,17 @@ static void set(struct plot *plot, struct dbcomm *db, bool unset, short mode) continue; v = vec_fromplot(dc->db_nodename1, plot); if (!v || v->v_plot != plot) { - if (!eq(dc->db_nodename1, "0") && !unset) { + if (!eq(dc->db_nodename1, "0") && value) { fprintf(cp_err, "Warning: node %s non-existent in %s.\n", dc->db_nodename1, plot->pl_name); /* note: XXX remove it from dbs, so won't get further errors */ } continue; } - if (unset) - v->v_flags &= (short) ~mode; - else + if (value) v->v_flags |= mode; + else + v->v_flags &= (short) ~mode; } } @@ -1176,16 +1207,18 @@ void gr_iplot(struct plot *plot) PushGraphContext(gr); } - set(plot, db, FALSE, VF_PLOT); + /* Temporarily set plot flag on matching vector. */ + + set(plot, db, TRUE, VF_PLOT); dontpop = 0; - if (iplot(plot, db->db_graphid)) { + if (iplot(plot, db)) { /* graph just assigned */ db->db_graphid = currentgraph->graphid; dontpop = 1; } - set(plot, db, TRUE, VF_PLOT); + set(plot, db, FALSE, VF_PLOT); if (!dontpop && db->db_graphid) PopGraphContext(); @@ -1195,7 +1228,7 @@ void gr_iplot(struct plot *plot) struct dvec *v, *u; int len; - set(plot, db, FALSE, VF_PRINT); + set(plot, db, TRUE, VF_PRINT); len = plot->pl_scale->v_length; @@ -1251,7 +1284,7 @@ void gr_iplot(struct plot *plot) printf("\n"); } } - set(plot, db, TRUE, VF_PRINT); + set(plot, db, FALSE, VF_PRINT); } } } diff --git a/src/frontend/subckt.c b/src/frontend/subckt.c index 9cd9db8d3..6de79afd8 100644 --- a/src/frontend/subckt.c +++ b/src/frontend/subckt.c @@ -1147,7 +1147,9 @@ translate(struct card *deck, char *formal, int flen, char *actual, char *scname, char *next_name, *name, *t, *nametofree, *paren_ptr; int nnodes, i, dim; int rtn = 0; - +#ifdef XSPICE + bool got_vnam = FALSE; +#endif bxx_init(&buffer); /* settrans builds the table holding the translated netnames. */ @@ -1165,7 +1167,6 @@ translate(struct card *deck, char *formal, int flen, char *actual, char *scname, } for (c = deck; c; c = c->nextcard) { - bool got_vnam = FALSE; char *s = c->line; char dev_type = tolower_c(s[0]); diff --git a/src/include/ngspice/fteext.h b/src/include/ngspice/fteext.h index 7c8a383b7..4f2ce0c35 100644 --- a/src/include/ngspice/fteext.h +++ b/src/include/ngspice/fteext.h @@ -93,6 +93,7 @@ extern void *cx_mean(void *, short int , int , int *, short int *); extern void *cx_stddev(void *, short int , int , int *, short int *); extern void *cx_length(void *, short int , int , int *, short int *); extern void *cx_vector(void *, short int , int , int *, short int *); +extern void *cx_cvector(void *, short int , int , int *, short int *); extern void *cx_unitvec(void *, short int , int , int *, short int *); extern void *cx_plus(void *, void *, short int , short int , int ); extern void *cx_minus(void *, void *, short int , short int , int ); diff --git a/src/include/ngspice/iferrmsg.h b/src/include/ngspice/iferrmsg.h index c5532bdd4..1d5a53adb 100644 --- a/src/include/ngspice/iferrmsg.h +++ b/src/include/ngspice/iferrmsg.h @@ -34,7 +34,8 @@ Author: 1986 Thomas L. Quarles #define E_NOCHANGE 13 /* simulator can't tolerate any more topology changes */ #define E_NOTFOUND 14 /* simulator can't find something it was looking for */ #define E_BAD_DOMAIN 15 /* output interface begin/end domain calls mismatched */ - +#define E_EXISTS_BAD 16 /* error - attempt to create duplicate */ + /* instance or model. Bail out. */ #define E_PRIVATE 100 /* messages above this number are private to */ /* the simulator and MUST be accompanied by */ diff --git a/src/include/ngspice/osdiitf.h b/src/include/ngspice/osdiitf.h index 5c84ed0ad..4f93d6c28 100644 --- a/src/include/ngspice/osdiitf.h +++ b/src/include/ngspice/osdiitf.h @@ -19,6 +19,7 @@ typedef struct OsdiRegistryEntry { uint32_t inst_offset; uint32_t dt; uint32_t temp; + bool has_m; } OsdiRegistryEntry; typedef struct OsdiObjectFile { diff --git a/src/maths/cmaths/cmath2.c b/src/maths/cmaths/cmath2.c index 888c15a44..6dc37b6b1 100644 --- a/src/maths/cmaths/cmath2.c +++ b/src/maths/cmaths/cmath2.c @@ -4,7 +4,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group **********/ /** \file cmath2.c - \brief functions for the control language parser: norm, uminus, rnd, sunif, sgauss, poisson, exponential, mean, stddev, length, vector, unitvec, plus, minus, times, mod, max, min, d, avg, floor, ceil, nint + \brief functions for the control language parser: norm, uminus, rnd, sunif, sgauss, poisson, exponential, mean, stddev, length, vector, cvector, unitvec, plus, minus, times, mod, max, min, d, avg, floor, ceil, nint Routines to do complex mathematical functions. These routines require the -lm libraries. We sacrifice a lot of space to be able @@ -479,7 +479,7 @@ cx_length(void *data, short int type, int length, int *newlength, short int *new /* Return a vector from 0 to the magnitude of the argument. Length of the - * argument is irrelevent. + * argument is irrelevant. */ void * @@ -506,6 +506,38 @@ cx_vector(void *data, short int type, int length, int *newlength, short int *new return ((void *) d); } +/* Return a complex vector. Argument sets the length of the vector. +The real part ranges from 0 to the magnitude of the argument. The imaginary +part is set to 0. + */ + +void* +cx_cvector(void* data, short int type, int length, int* newlength, short int* newtype) +{ + ngcomplex_t* cc = (ngcomplex_t*)data; + double* dd = (double*)data; + int i, len; + ngcomplex_t* d; + + NG_IGNORE(length); + + if (type == VF_REAL) + len = (int)fabs(*dd); + else + len = (int)cmag(*cc); + if (len == 0) + len = 1; + d = alloc_c(len); + *newlength = len; + *newtype = VF_COMPLEX; + for (i = 0; i < len; i++) { + realpart(d[i]) = i; + imagpart(d[i]) = 0; + } + return ((void*)d); +} + + /* Create a vector of the given length composed of all ones. */ diff --git a/src/maths/ni/nidest.c b/src/maths/ni/nidest.c index 06827285c..0982e60f1 100644 --- a/src/maths/ni/nidest.c +++ b/src/maths/ni/nidest.c @@ -16,7 +16,6 @@ Author: 1985 Thomas L. Quarles void NIdestroy(CKTcircuit *ckt) { - int i; if (ckt->CKTmatrix) SMPdestroy(ckt->CKTmatrix); ckt->CKTmatrix = NULL; @@ -36,7 +35,7 @@ NIdestroy(CKTcircuit *ckt) #endif #ifdef PREDICTOR if(ckt->CKTpred) FREE(ckt->CKTpred); - for( i=0;i<8;i++) { + for(int i=0;i<8;i++) { if(ckt->CKTsols[i]) FREE(ckt->CKTsols[i]); } #endif diff --git a/src/maths/ni/niiter.c b/src/maths/ni/niiter.c index fd7966dc9..4979f0901 100644 --- a/src/maths/ni/niiter.c +++ b/src/maths/ni/niiter.c @@ -22,7 +22,6 @@ Modified: 2001 AlansFixes /* Limit the number of 'singular matrix' warnings */ static int msgcount = 0; -void NIresetwarnmsg(void); /* NIiter() - return value is non-zero for convergence failure */ diff --git a/src/osdi/osdiinit.c b/src/osdi/osdiinit.c index 7d83b5dfe..f74867d74 100644 --- a/src/osdi/osdiinit.c +++ b/src/osdi/osdiinit.c @@ -32,7 +32,7 @@ * descr->param_opvar to the internal ngspice representation (IFparm). */ static int write_param_info(IFparm **dst, const OsdiDescriptor *descr, - uint32_t start, uint32_t end) { + uint32_t start, uint32_t end, bool has_m) { for (uint32_t i = start; i < end; i++) { OsdiParamOpvar *para = &descr->param_opvar[i]; uint32_t num_names = para->num_alias + 1; @@ -68,12 +68,23 @@ static int write_param_info(IFparm **dst, const OsdiDescriptor *descr, dataType |= IF_UNINTERESTING; } char *para_name = copy(para->name[j]); + if (para_name[0] == '$') { + para_name[0] = '_'; + } strtolower(para_name); (*dst)[j] = (IFparm){.keyword = para_name, .id = (int)i, .description = para->description, .dataType = dataType}; } + if (!has_m && !strcmp(para->name[0], "$mfactor")) { + (*dst)[num_names] = (IFparm){.keyword = "m", + .id = (int)i, + .description = para->description, + .dataType = dataType}; + *dst += 1; + } + *dst += num_names; } @@ -110,6 +121,10 @@ extern SPICEdev *osdi_create_spicedev(const OsdiRegistryEntry *entry) { *num_instance_para_names += 1; } + if (!entry->has_m) { + *num_instance_para_names += 1; + } + IFparm *instance_para_names = TMALLOC(IFparm, *num_instance_para_names); IFparm *dst = instance_para_names; @@ -124,9 +139,9 @@ extern SPICEdev *osdi_create_spicedev(const OsdiRegistryEntry *entry) { "Instance temperature"}; dst += 1; } - write_param_info(&dst, descr, 0, descr->num_instance_params); + write_param_info(&dst, descr, 0, descr->num_instance_params, entry->has_m); write_param_info(&dst, descr, descr->num_params, - descr->num_params + descr->num_opvars); + descr->num_params + descr->num_opvars, true); // allocate and fill model params int *num_model_para_names = TMALLOC(int, 1); @@ -135,7 +150,8 @@ extern SPICEdev *osdi_create_spicedev(const OsdiRegistryEntry *entry) { } IFparm *model_para_names = TMALLOC(IFparm, *num_model_para_names); dst = model_para_names; - write_param_info(&dst, descr, descr->num_instance_params, descr->num_params); + write_param_info(&dst, descr, descr->num_instance_params, descr->num_params, + true); // Allocate SPICE device SPICEdev *OSDIinfo = TMALLOC(SPICEdev, 1); @@ -181,7 +197,5 @@ extern SPICEdev *osdi_create_spicedev(const OsdiRegistryEntry *entry) { OSDIinfo->DEVpzLoad = OSDIpzLoad; OSDIinfo->DEVtrunc = OSDItrunc; - - return OSDIinfo; } diff --git a/src/osdi/osdiregistry.c b/src/osdi/osdiregistry.c index e3362fa38..36d989b3e 100644 --- a/src/osdi/osdiregistry.c +++ b/src/osdi/osdiregistry.c @@ -358,12 +358,15 @@ extern OsdiObjectFile load_object_file(const char *input) { const OsdiDescriptor *descr = &OSDI_DESCRIPTORS[i]; uint32_t dt = descr->num_params + descr->num_opvars; + bool has_m = false; uint32_t temp = descr->num_params + descr->num_opvars + 1; for (uint32_t param_id = 0; param_id < descr->num_params; param_id++) { OsdiParamOpvar *param = &descr->param_opvar[param_id]; for (uint32_t j = 0; j < 1 + param->num_alias; j++) { char *name = param->name[j]; - if (!strcmp(name, "dt")) { + if (!strcmp(name, "m")) { + has_m = true; + } else if (!strcmp(name, "dt")) { dt = UINT32_MAX; } else if (!strcasecmp(name, "dtemp") || !strcasecmp(name, "dt")) { dt = param_id; @@ -382,6 +385,7 @@ extern OsdiObjectFile load_object_file(const char *input) { .inst_offset = (uint32_t)inst_off, .dt = dt, .temp = temp, + .has_m = has_m, }; } diff --git a/src/osdi/osdisetup.c b/src/osdi/osdisetup.c index 9699fd509..c3504cc38 100644 --- a/src/osdi/osdisetup.c +++ b/src/osdi/osdisetup.c @@ -186,7 +186,7 @@ int OSDIsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, OsdiInitInfo init_info; OsdiNgspiceHandle handle; GENmodel *gen_model; - int res; + int res = (OK); int error; CKTnode *tmp; GENinstance *gen_inst; @@ -304,7 +304,7 @@ extern int OSDItemp(GENmodel *inModel, CKTcircuit *ckt) { OsdiInitInfo init_info; OsdiNgspiceHandle handle; GENmodel *gen_model; - int res; + int res = (OK); GENinstance *gen_inst; OsdiRegistryEntry *entry = osdi_reg_entry_model(inModel); diff --git a/src/spicelib/analysis/cktsetup.c b/src/spicelib/analysis/cktsetup.c index 3242944e1..902f9a356 100644 --- a/src/spicelib/analysis/cktsetup.c +++ b/src/spicelib/analysis/cktsetup.c @@ -14,6 +14,7 @@ Author: 1985 Thomas L. Quarles #include "ngspice/cktdefs.h" #include "ngspice/devdefs.h" #include "ngspice/sperror.h" +#include "ngspice/fteext.h" #ifdef XSPICE #include "ngspice/enh.h" @@ -43,6 +44,20 @@ CKTsetup(CKTcircuit *ckt) /* gtri - end - Setup for adding rshunt option resistors */ #endif SMPmatrix *matrix; + + if (!ckt->CKThead) { + fprintf(stderr, "Error: No model list found, device setup not possible!\n"); + if (ft_stricterror) + controlled_exit(EXIT_BAD); + return E_PANIC; + } + if (!DEVices) { + fprintf(stderr, "Error: No device list found, device setup not possible!\n"); + if (ft_stricterror) + controlled_exit(EXIT_BAD); + return E_PANIC; + } + ckt->CKTnumStates=0; #ifdef WANT_SENSE2 @@ -57,7 +72,9 @@ CKTsetup(CKTcircuit *ckt) return E_NOCHANGE; error = NIinit(ckt); - if (error) return(error); + if (error) + return(error); + ckt->CKTisSetup = 1; matrix = ckt->CKTmatrix; diff --git a/src/spicelib/analysis/dcpss.c b/src/spicelib/analysis/dcpss.c index d20fbf3db..61350383c 100644 --- a/src/spicelib/analysis/dcpss.c +++ b/src/spicelib/analysis/dcpss.c @@ -194,7 +194,7 @@ DCpss(CKTcircuit *ckt, else maxstepsize = ckt->CKTmaxStep; - ckt->CKTsizeIncr = 10; + ckt->CKTsizeIncr = 100; ckt->CKTtimeIndex = -1; /* before the DC soln has been stored */ ckt->CKTtimeListSize = (int)(1 / ckt->CKTguessedFreq / maxstepsize + 0.5); ltra_num = CKTtypelook("LTRA"); diff --git a/src/spicelib/analysis/dctran.c b/src/spicelib/analysis/dctran.c index 5f63a80f9..5f7d66c60 100644 --- a/src/spicelib/analysis/dctran.c +++ b/src/spicelib/analysis/dctran.c @@ -123,7 +123,7 @@ DCtran(CKTcircuit *ckt, else maxstepsize = ckt->CKTmaxStep; - ckt->CKTsizeIncr = 10; + ckt->CKTsizeIncr = 100; ckt->CKTtimeIndex = -1; /* before the DC soln has been stored */ ckt->CKTtimeListSize = (int) ceil( ckt->CKTfinalTime / maxstepsize ); ltra_num = CKTtypelook("LTRA"); diff --git a/src/spicelib/analysis/noisean.c b/src/spicelib/analysis/noisean.c index ec5d0c281..3032858ee 100644 --- a/src/spicelib/analysis/noisean.c +++ b/src/spicelib/analysis/noisean.c @@ -232,16 +232,16 @@ NOISEan(CKTcircuit* ckt, int restart) error = CKTload(ckt); if (error) return(error); - error = CKTnames(ckt, &numNames, &nameList); - if (error) return(error); - if (ckt->CKTkeepOpInfo) { + error = CKTnames(ckt, &numNames, &nameList); + if (error) return(error); /* Dump operating point. */ error = SPfrontEnd->OUTpBeginPlot(ckt, ckt->CKTcurJob, "NOISE Operating Point", NULL, IF_REAL, numNames, nameList, IF_REAL, &plot); + txfree(nameList); if (error) return(error); CKTdump(ckt, 0.0, plot); SPfrontEnd->OUTendPlot(plot); diff --git a/src/spicelib/analysis/optran.c b/src/spicelib/analysis/optran.c index aceddbc2c..8aba4e1a9 100644 --- a/src/spicelib/analysis/optran.c +++ b/src/spicelib/analysis/optran.c @@ -100,6 +100,11 @@ void com_optran(wordlist* wl) { getdata = TRUE; } + if (!getdata && !ft_curckt) { + /* no circuit, but optran already set */ + return; + } + int saved = errno; errno = 0; nooptran = FALSE; @@ -159,14 +164,14 @@ void com_optran(wordlist* wl) { if (err || (*stpstr != '\0')) goto bugquit; if (opstepsize > opfinaltime) { - fprintf(stderr, "Error: Step size larger than final time.\n"); + fprintf(stderr, "Error: Optran step size larger than final time.\n"); goto bugquit; } if (opstepsize > opfinaltime/50.) { - fprintf(stderr, "Warning: Step size potentially too small.\n"); + fprintf(stderr, "Warning: Optran step size potentially too large.\n"); } if (opramptime > opfinaltime) { - fprintf(stderr, "Error: Ramp time larger than final time.\n"); + fprintf(stderr, "Error: Optran ramp time larger than final time.\n"); goto bugquit; } /* optran deselected by setting opstepsize to 0 */ @@ -362,7 +367,7 @@ OPtran(CKTcircuit *ckt, int oldconverged) else maxstepsize = ckt->CKTmaxStep; - ckt->CKTsizeIncr = 10; + ckt->CKTsizeIncr = 100; ckt->CKTtimeIndex = -1; /* before the DC soln has been stored */ ckt->CKTtimeListSize = (int) ceil( opfinaltime / maxstepsize ); ltra_num = CKTtypelook("LTRA"); @@ -657,7 +662,7 @@ resume: /* supply ramping, when opramptime > 0 */ if (opramptime > 0) - ckt->CKTsrcFact = MIN(1., optime / opramptime); + ckt->CKTsrcFact = 0.5 * (1 - cos(M_PI * optime / opramptime)); ckt->CKTdeltaOld[0]=ckt->CKTdelta; NIcomCof(ckt); diff --git a/src/spicelib/devices/cktcrte.c b/src/spicelib/devices/cktcrte.c index 1f5b9578d..77715604b 100644 --- a/src/spicelib/devices/cktcrte.c +++ b/src/spicelib/devices/cktcrte.c @@ -32,7 +32,7 @@ CKTcrtElt(CKTcircuit *ckt, GENmodel *modPtr, GENinstance **inInstPtr, IFuid name if (instPtr) { if (inInstPtr) *inInstPtr = instPtr; - return E_EXISTS; + return E_EXISTS_BAD; } type = modPtr->GENmodType; diff --git a/src/spicelib/devices/cktinit.c b/src/spicelib/devices/cktinit.c index 7fde41af6..92e83093b 100644 --- a/src/spicelib/devices/cktinit.c +++ b/src/spicelib/devices/cktinit.c @@ -29,16 +29,13 @@ CKTinit(CKTcircuit **ckt) /* new circuit to create */ CKTcircuit *sckt = TMALLOC(CKTcircuit, 1); *ckt = sckt; if (sckt == NULL) - return(E_NOMEM); -/* gtri - begin - dynamically allocate the array of model lists */ -/* CKThead used to be statically sized in CKTdefs.h, but has been changed */ -/* to a ** pointer */ + return(E_NOMEM); + + /* dynamically allocate the array of model lists */ sckt->CKThead = TMALLOC(GENmodel *, DEVmaxnum); - if(sckt->CKThead == NULL) return(E_NOMEM); -/* gtri - end - dynamically allocate the array of model lists */ + if(sckt->CKThead == NULL) + return(E_NOMEM); - - for (i = 0; i < DEVmaxnum; i++) sckt->CKThead[i] = NULL; diff --git a/src/spicelib/devices/ltra/ltraacct.c b/src/spicelib/devices/ltra/ltraacct.c index 2615100e7..6a169b0d6 100644 --- a/src/spicelib/devices/ltra/ltraacct.c +++ b/src/spicelib/devices/ltra/ltraacct.c @@ -10,285 +10,283 @@ Author: 1990 Jaijeet S. Roychowdhury #include "ngspice/suffix.h" int -LTRAaccept(CKTcircuit *ckt, GENmodel *inModel) +LTRAaccept(CKTcircuit* ckt, GENmodel* inModel) { - LTRAmodel *model = (LTRAmodel *) inModel; - LTRAinstance *here; - double v1, v2, v3, v4; - double v5, v6, d1, d2, d3, d4; - int tmp_test; - int error; - int compact = 1; + LTRAmodel* model = (LTRAmodel*)inModel; + LTRAinstance* here; + double v1, v2, v3, v4; + double v5, v6, d1, d2, d3, d4; + int tmp_test; + int error; + int compact = 1; - /* loop through all the transmission line models */ - for (; model != NULL; model = LTRAnextModel(model)) { + /* loop through all the transmission line models */ + for (; model != NULL; model = LTRAnextModel(model)) { - if (ckt->CKTmode & MODEINITTRAN) { + if (ckt->CKTmode & MODEINITTRAN) { #define LTRAmemMANAGE(a,b) \ - if ( a != NULL) FREE(a);\ - a = TMALLOC(double, b); + if ( a != NULL) FREE(a);\ + a = TMALLOC(double, b); - model->LTRAmodelListSize = 10; + model->LTRAmodelListSize = 100; + LTRAmemMANAGE(model->LTRAh1dashCoeffs, model->LTRAmodelListSize) + LTRAmemMANAGE(model->LTRAh2Coeffs, model->LTRAmodelListSize) + LTRAmemMANAGE(model->LTRAh3dashCoeffs, model->LTRAmodelListSize) + } + if (ckt->CKTtimeIndex >= model->LTRAmodelListSize) { /* need more space */ + model->LTRAmodelListSize += ckt->CKTsizeIncr; - LTRAmemMANAGE(model->LTRAh1dashCoeffs, model->LTRAmodelListSize) - LTRAmemMANAGE(model->LTRAh2Coeffs, model->LTRAmodelListSize) - LTRAmemMANAGE(model->LTRAh3dashCoeffs, model->LTRAmodelListSize) - } - if (ckt->CKTtimeIndex >= model->LTRAmodelListSize) { /* need more space */ - model->LTRAmodelListSize += ckt->CKTsizeIncr; + model->LTRAh1dashCoeffs = TREALLOC(double, model->LTRAh1dashCoeffs, model->LTRAmodelListSize); + model->LTRAh2Coeffs = TREALLOC(double, model->LTRAh2Coeffs, model->LTRAmodelListSize); + model->LTRAh3dashCoeffs = TREALLOC(double, model->LTRAh3dashCoeffs, model->LTRAmodelListSize); + } + /* loop through all the instances of the model */ + for (here = LTRAinstances(model); here != NULL; + here = LTRAnextInstance(here)) { + if (ckt->CKTmode & MODEINITTRAN) { + here->LTRAinstListSize = (int)MAX(10, ckt->CKTtimeListSize); - model->LTRAh1dashCoeffs = TREALLOC(double, model->LTRAh1dashCoeffs, model->LTRAmodelListSize); - model->LTRAh2Coeffs = TREALLOC(double, model->LTRAh2Coeffs, model->LTRAmodelListSize); - model->LTRAh3dashCoeffs = TREALLOC(double, model->LTRAh3dashCoeffs, model->LTRAmodelListSize); - } - /* loop through all the instances of the model */ - for (here = LTRAinstances(model); here != NULL; - here = LTRAnextInstance(here)) { + LTRAmemMANAGE(here->LTRAv1, here->LTRAinstListSize) + LTRAmemMANAGE(here->LTRAi1, here->LTRAinstListSize) + LTRAmemMANAGE(here->LTRAv2, here->LTRAinstListSize) + LTRAmemMANAGE(here->LTRAi2, here->LTRAinstListSize) + } + /* + * why is this here? ask TQ + * + * if (ckt->CKTtimeIndex == 0? 1: (ckt->CKTtime- + * (ckt->CKTtimePoints+ckt->CKTtimeIndex-1) > ckt->CKTminBreak)) { + * + */ + if (ckt->CKTtimeIndex >= here->LTRAinstListSize) { /* need more space */ + here->LTRAinstListSize += ckt->CKTsizeIncr; - if (ckt->CKTmode & MODEINITTRAN) { - here->LTRAinstListSize = 10; + here->LTRAv1 = TREALLOC(double, here->LTRAv1, here->LTRAinstListSize); + here->LTRAi1 = TREALLOC(double, here->LTRAi1, here->LTRAinstListSize); + here->LTRAi2 = TREALLOC(double, here->LTRAi2, here->LTRAinstListSize); + here->LTRAv2 = TREALLOC(double, here->LTRAv2, here->LTRAinstListSize); + } + *(here->LTRAv1 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + + here->LTRAposNode1) - *(ckt->CKTrhsOld + + here->LTRAnegNode1); + *(here->LTRAv2 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + + here->LTRAposNode2) - *(ckt->CKTrhsOld + + here->LTRAnegNode2); + *(here->LTRAi1 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + + here->LTRAbrEq1); + *(here->LTRAi2 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + + here->LTRAbrEq2); - LTRAmemMANAGE(here->LTRAv1, here->LTRAinstListSize) - LTRAmemMANAGE(here->LTRAi1, here->LTRAinstListSize) - LTRAmemMANAGE(here->LTRAv2, here->LTRAinstListSize) - LTRAmemMANAGE(here->LTRAi2, here->LTRAinstListSize) - } - /* - * why is this here? ask TQ - * - * if (ckt->CKTtimeIndex == 0? 1: (ckt->CKTtime- - * (ckt->CKTtimePoints+ckt->CKTtimeIndex-1) > ckt->CKTminBreak)) { - * - */ - if (ckt->CKTtimeIndex >= here->LTRAinstListSize) { /* need more space */ - here->LTRAinstListSize += ckt->CKTsizeIncr; + if (ckt->CKTtryToCompact && (ckt->CKTtimeIndex >= 2)) { - here->LTRAv1 = TREALLOC(double, here->LTRAv1, here->LTRAinstListSize); - here->LTRAi1 = TREALLOC(double, here->LTRAi1, here->LTRAinstListSize); - here->LTRAi2 = TREALLOC(double, here->LTRAi2, here->LTRAinstListSize); - here->LTRAv2 = TREALLOC(double, here->LTRAv2, here->LTRAinstListSize); - } - *(here->LTRAv1 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + - here->LTRAposNode1) - *(ckt->CKTrhsOld + - here->LTRAnegNode1); - *(here->LTRAv2 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + - here->LTRAposNode2) - *(ckt->CKTrhsOld + - here->LTRAnegNode2); - *(here->LTRAi1 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + - here->LTRAbrEq1); - *(here->LTRAi2 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + - here->LTRAbrEq2); + /* + * figure out if the last 3 points lie on a st. line for all the + * terminal variables + */ + { + double t1, t2, t3; - if (ckt->CKTtryToCompact && (ckt->CKTtimeIndex >= 2)) { + t1 = *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 2); + t2 = *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1); + t3 = *(ckt->CKTtimePoints + ckt->CKTtimeIndex); - /* - * figure out if the last 3 points lie on a st. line for all the - * terminal variables - */ - { - double t1, t2, t3; - - t1 = *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 2); - t2 = *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1); - t3 = *(ckt->CKTtimePoints + ckt->CKTtimeIndex); - - if (compact) { - compact = LTRAstraightLineCheck(t1, - *(here->LTRAv1 + ckt->CKTtimeIndex - 2), - t2, *(here->LTRAv1 + ckt->CKTtimeIndex - 1), - t3, *(here->LTRAv1 + ckt->CKTtimeIndex), - model->LTRAstLineReltol, model->LTRAstLineAbstol); - } - if (compact) { - compact = LTRAstraightLineCheck(t1, - *(here->LTRAv2 + ckt->CKTtimeIndex - 2), - t2, *(here->LTRAv2 + ckt->CKTtimeIndex - 1), - t3, *(here->LTRAv2 + ckt->CKTtimeIndex), - model->LTRAstLineReltol, model->LTRAstLineAbstol); - } - if (compact) { - compact = LTRAstraightLineCheck(t1, - *(here->LTRAi1 + ckt->CKTtimeIndex - 2), - t2, *(here->LTRAi1 + ckt->CKTtimeIndex - 1), - t3, *(here->LTRAi1 + ckt->CKTtimeIndex), - model->LTRAstLineReltol, model->LTRAstLineAbstol); - } - if (compact) { - compact = LTRAstraightLineCheck(t1, - *(here->LTRAi2 + ckt->CKTtimeIndex - 2), - t2, *(here->LTRAi2 + ckt->CKTtimeIndex - 1), - t3, *(here->LTRAi2 + ckt->CKTtimeIndex), - model->LTRAstLineReltol, model->LTRAstLineAbstol); - } - } - } - if (ckt->CKTtimeIndex > 0) { + if (compact) { + compact = LTRAstraightLineCheck(t1, + *(here->LTRAv1 + ckt->CKTtimeIndex - 2), + t2, *(here->LTRAv1 + ckt->CKTtimeIndex - 1), + t3, *(here->LTRAv1 + ckt->CKTtimeIndex), + model->LTRAstLineReltol, model->LTRAstLineAbstol); + } + if (compact) { + compact = LTRAstraightLineCheck(t1, + *(here->LTRAv2 + ckt->CKTtimeIndex - 2), + t2, *(here->LTRAv2 + ckt->CKTtimeIndex - 1), + t3, *(here->LTRAv2 + ckt->CKTtimeIndex), + model->LTRAstLineReltol, model->LTRAstLineAbstol); + } + if (compact) { + compact = LTRAstraightLineCheck(t1, + *(here->LTRAi1 + ckt->CKTtimeIndex - 2), + t2, *(here->LTRAi1 + ckt->CKTtimeIndex - 1), + t3, *(here->LTRAi1 + ckt->CKTtimeIndex), + model->LTRAstLineReltol, model->LTRAstLineAbstol); + } + if (compact) { + compact = LTRAstraightLineCheck(t1, + *(here->LTRAi2 + ckt->CKTtimeIndex - 2), + t2, *(here->LTRAi2 + ckt->CKTtimeIndex - 1), + t3, *(here->LTRAi2 + ckt->CKTtimeIndex), + model->LTRAstLineReltol, model->LTRAstLineAbstol); + } + } + } + if (ckt->CKTtimeIndex > 0) { #ifdef NOTDEF - v1 = (*(here->LTRAv1 + ckt->CKTtimeIndex) + - *(here->LTRAi1 + ckt->CKTtimeIndex) * - model->LTRAimped) * model->LTRAattenuation; - v2 = (*(here->LTRAv1 + ckt->CKTtimeIndex - 1) + - *(here->LTRAi1 + ckt->CKTtimeIndex - 1) - * model->LTRAimped) * model->LTRAattenuation; - v3 = (*(here->LTRAv2 + ckt->CKTtimeIndex) + - *(here->LTRAi2 + ckt->CKTtimeIndex) * - model->LTRAimped) * model->LTRAattenuation; - v4 = (*(here->LTRAv2 + ckt->CKTtimeIndex - 1) + - *(here->LTRAi2 + ckt->CKTtimeIndex - 1) * - model->LTRAimped) * model->LTRAattenuation; - if ((fabs(v1 - v2) >= 50 * ckt->CKTreltol * - MAX(fabs(v1), fabs(v2)) + 50 * ckt->CKTvoltTol) || - (fabs(v3 - v4) >= 50 * ckt->CKTreltol * - MAX(fabs(v3), fabs(v4)) + 50 * ckt->CKTvoltTol)) { - /* changing - need to schedule after delay */ - /* - * don't really need this error = - * CKTsetBreak(ckt,ckt->CKTtime+model->LTRAtd); if(error) - * return(error); - */ - /* the PREVIOUS point is the real breakpoint */ - error = CKTsetBreak(ckt, - *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) + - model->LTRAtd); - CKTbreakDump(ckt); - if (error) - return (error); - } + v1 = (*(here->LTRAv1 + ckt->CKTtimeIndex) + + *(here->LTRAi1 + ckt->CKTtimeIndex) * + model->LTRAimped) * model->LTRAattenuation; + v2 = (*(here->LTRAv1 + ckt->CKTtimeIndex - 1) + + *(here->LTRAi1 + ckt->CKTtimeIndex - 1) + * model->LTRAimped) * model->LTRAattenuation; + v3 = (*(here->LTRAv2 + ckt->CKTtimeIndex) + + *(here->LTRAi2 + ckt->CKTtimeIndex) * + model->LTRAimped) * model->LTRAattenuation; + v4 = (*(here->LTRAv2 + ckt->CKTtimeIndex - 1) + + *(here->LTRAi2 + ckt->CKTtimeIndex - 1) * + model->LTRAimped) * model->LTRAattenuation; + if ((fabs(v1 - v2) >= 50 * ckt->CKTreltol * + MAX(fabs(v1), fabs(v2)) + 50 * ckt->CKTvoltTol) || + (fabs(v3 - v4) >= 50 * ckt->CKTreltol * + MAX(fabs(v3), fabs(v4)) + 50 * ckt->CKTvoltTol)) { + /* changing - need to schedule after delay */ + /* + * don't really need this error = + * CKTsetBreak(ckt,ckt->CKTtime+model->LTRAtd); if(error) + * return(error); + */ + /* the PREVIOUS point is the real breakpoint */ + error = CKTsetBreak(ckt, + *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) + + model->LTRAtd); + CKTbreakDump(ckt); + if (error) + return (error); + } #else - /* - * remove the hack here - store the total inputs for the last 2 or 3 - * timesteps - */ + /* + * remove the hack here - store the total inputs for the last 2 or 3 + * timesteps + */ - v1 = (*(here->LTRAv1 + ckt->CKTtimeIndex) + - *(here->LTRAi1 + ckt->CKTtimeIndex) * - model->LTRAimped) * model->LTRAattenuation; - v2 = (*(here->LTRAv1 + ckt->CKTtimeIndex - 1) + - *(here->LTRAi1 + ckt->CKTtimeIndex - 1) * - model->LTRAimped) * model->LTRAattenuation; - v3 = ckt->CKTtimeIndex < 2 ? v2 : (*(here->LTRAv1 + ckt->CKTtimeIndex - 2) + - *(here->LTRAi1 + ckt->CKTtimeIndex - 2) * - model->LTRAimped) * model->LTRAattenuation; - v4 = (*(here->LTRAv2 + ckt->CKTtimeIndex) + - *(here->LTRAi2 + ckt->CKTtimeIndex) * - model->LTRAimped) * model->LTRAattenuation; - v5 = (*(here->LTRAv2 + ckt->CKTtimeIndex - 1) + - *(here->LTRAi2 + ckt->CKTtimeIndex - 1) * - model->LTRAimped) * model->LTRAattenuation; - v6 = ckt->CKTtimeIndex < 2 ? v5 : (*(here->LTRAv2 + ckt->CKTtimeIndex - 2) + - *(here->LTRAi2 + ckt->CKTtimeIndex - 2) * - model->LTRAimped) * model->LTRAattenuation; + v1 = (*(here->LTRAv1 + ckt->CKTtimeIndex) + + *(here->LTRAi1 + ckt->CKTtimeIndex) * + model->LTRAimped) * model->LTRAattenuation; + v2 = (*(here->LTRAv1 + ckt->CKTtimeIndex - 1) + + *(here->LTRAi1 + ckt->CKTtimeIndex - 1) * + model->LTRAimped) * model->LTRAattenuation; + v3 = ckt->CKTtimeIndex < 2 ? v2 : (*(here->LTRAv1 + ckt->CKTtimeIndex - 2) + + *(here->LTRAi1 + ckt->CKTtimeIndex - 2) * + model->LTRAimped) * model->LTRAattenuation; + v4 = (*(here->LTRAv2 + ckt->CKTtimeIndex) + + *(here->LTRAi2 + ckt->CKTtimeIndex) * + model->LTRAimped) * model->LTRAattenuation; + v5 = (*(here->LTRAv2 + ckt->CKTtimeIndex - 1) + + *(here->LTRAi2 + ckt->CKTtimeIndex - 1) * + model->LTRAimped) * model->LTRAattenuation; + v6 = ckt->CKTtimeIndex < 2 ? v5 : (*(here->LTRAv2 + ckt->CKTtimeIndex - 2) + + *(here->LTRAi2 + ckt->CKTtimeIndex - 2) * + model->LTRAimped) * model->LTRAattenuation; - d1 = (v1 - v2) / (*(ckt->CKTtimePoints + ckt->CKTtimeIndex) - - *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1)); - d2 = (ckt->CKTtimeIndex < 2) - ? 0 - : (v2 - v3) / (*(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) - - *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 2)); - d3 = (v4 - v5) / (*(ckt->CKTtimePoints + ckt->CKTtimeIndex) - - *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1)); - d4 = (ckt->CKTtimeIndex < 2) - ? 0 - : (v5 - v6) / (*(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) - - *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 2)); + d1 = (v1 - v2) / (*(ckt->CKTtimePoints + ckt->CKTtimeIndex) - + *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1)); + d2 = (ckt->CKTtimeIndex < 2) + ? 0 + : (v2 - v3) / (*(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) - + *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 2)); + d3 = (v4 - v5) / (*(ckt->CKTtimePoints + ckt->CKTtimeIndex) - + *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1)); + d4 = (ckt->CKTtimeIndex < 2) + ? 0 + : (v5 - v6) / (*(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) - + *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 2)); - /* - * here we have a big problem with the scheme boxed by the *s below. - * Note the following: if LTRAreltol == 1, (assuming LTRAabstol==0) - * then breakpoints are set if and only if d1 and d2 have opposite - * signs or one is zero. If LTRAreltol > 2, breakpoints are never - * set. The problem is that when the waveform is steady at a value, - * small random numerical inaccuracies may produce derivatives of - * opposite sign, and breakpoints get set. This can, in practice, get - * quite killing... To alleviate this, we try to determine if the - * waveform is actually steady using the following tests: 1. Check if - * the maximum difference between v1,v2 and v3 is less than - * 50*CKTreltol*(the average of v1,v2,and v3) + 50*ckt->CKTabstol - * (the 50 has been taken from the NOTDEF section above, reason - * unknown - hopefully there is a good reason for it - ask TQ) - * - * 2. Criterion 1 may be satisfied by a legitimate breakpoint. To - * further check, find one more derivative one timepoint ago and see - * if that is close to d2. If not, then the likelihood of numerical - * inaccuracies is greater... - */ + /* + * here we have a big problem with the scheme boxed by the *s below. + * Note the following: if LTRAreltol == 1, (assuming LTRAabstol==0) + * then breakpoints are set if and only if d1 and d2 have opposite + * signs or one is zero. If LTRAreltol > 2, breakpoints are never + * set. The problem is that when the waveform is steady at a value, + * small random numerical inaccuracies may produce derivatives of + * opposite sign, and breakpoints get set. This can, in practice, get + * quite killing... To alleviate this, we try to determine if the + * waveform is actually steady using the following tests: 1. Check if + * the maximum difference between v1,v2 and v3 is less than + * 50*CKTreltol*(the average of v1,v2,and v3) + 50*ckt->CKTabstol + * (the 50 has been taken from the NOTDEF section above, reason + * unknown - hopefully there is a good reason for it - ask TQ) + * + * 2. Criterion 1 may be satisfied by a legitimate breakpoint. To + * further check, find one more derivative one timepoint ago and see + * if that is close to d2. If not, then the likelihood of numerical + * inaccuracies is greater... + */ - /********************************************************************* - if( (fabs(d1-d2) >= model->LTRAreltol*MAX(fabs(d1),fabs(d2))+ - model->LTRAabstol) || - (fabs(d3-d4) >= model->LTRAreltol*MAX(fabs(d3),fabs(d4))+ - model->LTRAabstol) ) { - *********************************************************************/ + /********************************************************************* + if( (fabs(d1-d2) >= model->LTRAreltol*MAX(fabs(d1),fabs(d2))+ + model->LTRAabstol) || + (fabs(d3-d4) >= model->LTRAreltol*MAX(fabs(d3),fabs(d4))+ + model->LTRAabstol) ) { + *********************************************************************/ #define CHECK(a,b,c) (MAX(MAX(a,b),c)-MIN(MIN(a,b),c) >= \ - fabs(50.0*(ckt->CKTreltol/3.0*(a+b+c) +\ - ckt->CKTabstol))) + fabs(50.0*(ckt->CKTreltol/3.0*(a+b+c) +\ + ckt->CKTabstol))) - tmp_test = (fabs(d1 - d2) - >= model->LTRAreltol * MAX(fabs(d1), fabs(d2)) + - model->LTRAabstol) - && CHECK(v1, v2, v3); - if (tmp_test || ((fabs(d3 - d4) - >= model->LTRAreltol * MAX(fabs(d3), fabs(d4)) + - model->LTRAabstol) - && CHECK(v4, v5, v6))) { - /* criterion 2 not implemented yet... */ - error = CKTsetBreak(ckt, - *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) + - model->LTRAtd); - /* - * this is not necessary - the previous timepoint was the - * breakpoint error = CKTsetBreak(ckt, ckt->CKTtime + - * model->LTRAtd); - */ + tmp_test = (fabs(d1 - d2) + >= model->LTRAreltol * MAX(fabs(d1), fabs(d2)) + + model->LTRAabstol) + && CHECK(v1, v2, v3); + if (tmp_test || ((fabs(d3 - d4) + >= model->LTRAreltol * MAX(fabs(d3), fabs(d4)) + + model->LTRAabstol) + && CHECK(v4, v5, v6))) { + /* criterion 2 not implemented yet... */ + error = CKTsetBreak(ckt, + *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) + + model->LTRAtd); + /* + * this is not necessary - the previous timepoint was the + * breakpoint error = CKTsetBreak(ckt, ckt->CKTtime + + * model->LTRAtd); + */ #ifdef LTRADEBUG - fprintf(stdout, "\nbreakpoints set at %14.14g at %14.14g at time %14.14g\n", ckt->CKTtime + model->LTRAtd, *(ckt->CKTtimePoints + ckt->CKTtimeIndex - - 1) + model->LTRAtd, ckt->CKTtime); - fprintf(stdout, "d1 through d4 are %14.14g %14.14g %14.14g %14.14g\n\n", d1, d2, d3, d4); + fprintf(stdout, "\nbreakpoints set at %14.14g at %14.14g at time %14.14g\n", ckt->CKTtime + model->LTRAtd, *(ckt->CKTtimePoints + ckt->CKTtimeIndex + - 1) + model->LTRAtd, ckt->CKTtime); + fprintf(stdout, "d1 through d4 are %14.14g %14.14g %14.14g %14.14g\n\n", d1, d2, d3, d4); #endif - if (error) - return (error); - } - /* } */ + if (error) + return (error); + } + /* } */ #endif /* NOTDEF */ - } - /* ask TQ } */ + } + /* ask TQ } */ - } /* instance */ - } /* model */ + } /* instance */ + } /* model */ - if (ckt->CKTtryToCompact && compact && (ckt->CKTtimeIndex >= 2)) { + if (ckt->CKTtryToCompact && compact && (ckt->CKTtimeIndex >= 2)) { - /* - * last three timepoints have variables lying on a straight line, do a - * compaction - */ + /* + * last three timepoints have variables lying on a straight line, do a + * compaction + */ - model = (LTRAmodel *) inModel; - for (; model != NULL; model = LTRAnextModel(model)) { - for (here = LTRAinstances(model); here != NULL; - here = LTRAnextInstance(here)) { - *(here->LTRAv1 + ckt->CKTtimeIndex - 1) = *(here->LTRAv1 + - ckt->CKTtimeIndex); - *(here->LTRAv2 + ckt->CKTtimeIndex - 1) = *(here->LTRAv2 + - ckt->CKTtimeIndex); - *(here->LTRAi1 + ckt->CKTtimeIndex - 1) = *(here->LTRAi1 + - ckt->CKTtimeIndex); - *(here->LTRAi2 + ckt->CKTtimeIndex - 1) = *(here->LTRAi2 + - ckt->CKTtimeIndex); - } - } - *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) = - *(ckt->CKTtimePoints + ckt->CKTtimeIndex); - ckt->CKTtimeIndex--; + model = (LTRAmodel*)inModel; + for (; model != NULL; model = LTRAnextModel(model)) { + for (here = LTRAinstances(model); here != NULL; + here = LTRAnextInstance(here)) { + *(here->LTRAv1 + ckt->CKTtimeIndex - 1) = *(here->LTRAv1 + + ckt->CKTtimeIndex); + *(here->LTRAv2 + ckt->CKTtimeIndex - 1) = *(here->LTRAv2 + + ckt->CKTtimeIndex); + *(here->LTRAi1 + ckt->CKTtimeIndex - 1) = *(here->LTRAi1 + + ckt->CKTtimeIndex); + *(here->LTRAi2 + ckt->CKTtimeIndex - 1) = *(here->LTRAi2 + + ckt->CKTtimeIndex); + } + } + *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) = + *(ckt->CKTtimePoints + ckt->CKTtimeIndex); + ckt->CKTtimeIndex--; #ifdef LTRADEBUG - fprintf(stdout, "compacted at time=%g\n", *(ckt->CKTtimePoints + ckt->CKTtimeIndex)); - fflush(stdout); + fprintf(stdout, "compacted at time=%g\n", *(ckt->CKTtimePoints + ckt->CKTtimeIndex)); + fflush(stdout); #endif - } - return (OK); + } + return (OK); } diff --git a/src/spicelib/devices/vbic/vbicacld.c b/src/spicelib/devices/vbic/vbicacld.c index 0844fccd0..3faed1866 100644 --- a/src/spicelib/devices/vbic/vbicacld.c +++ b/src/spicelib/devices/vbic/vbicacld.c @@ -30,7 +30,7 @@ VBICacLoad(GENmodel *inModel, CKTcircuit *ckt) ,Ibcp_Vbcp,Iccp_Vbep,Irs_Vrs,Iccp_Vbci,Iccp_Vbcp; double XQbe_Vbei, XQbe_Vbci, XQbex_Vbex, XQbc_Vbci, XQbcx_Vbcx, XQbep_Vbep, XQbep_Vbci, - XQbcp_Vbcp; + XQbcp_Vbcp, XQbeo_Vbe, XQbco_Vbc; /* loop through all the models */ for( ; model != NULL; model = VBICnextModel(model)) { @@ -229,6 +229,8 @@ c The complex part XQbep_Vbep = *(ckt->CKTstate0 + here->VBICcqbep) * ckt->CKTomega; XQbep_Vbci = *(ckt->CKTstate0 + here->VBICcqbepci) * ckt->CKTomega; XQbcp_Vbcp = *(ckt->CKTstate0 + here->VBICcqbcp) * ckt->CKTomega; + XQbeo_Vbe = *(ckt->CKTstate0 + here->VBICcqbeo) * ckt->CKTomega; + XQbco_Vbc = *(ckt->CKTstate0 + here->VBICcqbco) * ckt->CKTomega; /* c Stamp element: Qbe */ @@ -279,6 +281,21 @@ c Stamp element: Qbcp *(here->VBICsubsSIBaseBPPtr + 1) += -XQbcp_Vbcp; *(here->VBICbaseBPSubsSIPtr + 1) += -XQbcp_Vbcp; *(here->VBICbaseBPBaseBPPtr + 1) += XQbcp_Vbcp; +/* +c Stamp element: Qbeo +*/ + *(here->VBICbaseBasePtr + 1) += XQbeo_Vbe; + *(here->VBICemitEmitPtr + 1) += XQbeo_Vbe; + *(here->VBICbaseEmitPtr + 1) += -XQbeo_Vbe; + *(here->VBICemitBasePtr + 1) += -XQbeo_Vbe; +/* +c Stamp element: Qbco +*/ + *(here->VBICbaseBasePtr + 1) += XQbco_Vbc; + *(here->VBICcollCollPtr + 1) += XQbco_Vbc; + *(here->VBICbaseCollPtr + 1) += -XQbco_Vbc; + *(here->VBICcollBasePtr + 1) += -XQbco_Vbc; + } } diff --git a/src/spicelib/devices/vbic/vbicload.c b/src/spicelib/devices/vbic/vbicload.c index af723c4b8..b0c7efff4 100644 --- a/src/spicelib/devices/vbic/vbicload.c +++ b/src/spicelib/devices/vbic/vbicload.c @@ -75,8 +75,8 @@ VBICload(GENmodel *inModel, CKTcircuit *ckt) ,Iccp_Vbci,Iccp_Vbcp,Irs,Irs_Vrs,Irs_Vrth=0.0,Qbcp,Qbcp_Vrth ,Qbcp_Vbcp,Irth,Irth_Vrth=0.0,Ith=0.0,Ith_Vrth=0.0,Ith_Vbei=0.0,Ith_Vbci=0.0 ,Ith_Vcei=0.0,Ith_Vbex=0.0,Ith_Vbep=0.0,Ith_Vrs=0.0,Ith_Vbcp=0.0,Ith_Vcep=0.0,Ith_Vrcx=0.0 - ,Ith_Vrci=0.0,Ith_Vbcx=0.0,Ith_Vrbx=0.0,Ith_Vrbi=0.0,Ith_Vre=0.0,Ith_Vrbp=0.0,Qcth - ,Qcth_Vrth,SCALE; + ,Ith_Vrci=0.0,Ith_Vbcx=0.0,Ith_Vrbx=0.0,Ith_Vrbi=0.0,Ith_Vre=0.0,Ith_Vrbp=0.0,Qcth=0.0 + ,Qcth_Vrth=0.0,SCALE; int iret; double vce; #ifndef PREDICTOR @@ -129,7 +129,7 @@ VBICload(GENmodel *inModel, CKTcircuit *ckt) /* * model parameters */ - memcpy (&p, &model->VBICtnom, 108*8); + memcpy (&p, &model->VBICtnom, sizeof(p)); p[0] = here->VBICtemp - CONSTCtoK + p[105]; /* temperature dependent parameter are already calculated */ @@ -714,7 +714,8 @@ VBICload(GENmodel *inModel, CKTcircuit *ckt) here->VBICcapbcx = Qbcx_Vbcx; here->VBICcapbep = Qbep_Vbep; here->VBICcapbcp = Qbcp_Vbcp; - here->VBICcapcth = Qcth_Vrth; + if (here->VBIC_selfheat) + here->VBICcapcth = Qcth_Vrth; /* * store small-signal parameters @@ -894,9 +895,11 @@ VBICload(GENmodel *inModel, CKTcircuit *ckt) *(ckt->CKTstate0 + here->VBICirbx_Vrbx) = Irbx_Vrbx; *(ckt->CKTstate0 + here->VBICirs_Vrs) = Irs_Vrs; *(ckt->CKTstate0 + here->VBICire_Vre) = Ire_Vre; - *(ckt->CKTstate0 + here->VBICcqcth) = Icth; - *(ckt->CKTstate0 + here->VBICicth_Vrth) = Icth_Vrth; - + if (here->VBIC_selfheat) + { + *(ckt->CKTstate0 + here->VBICcqcth) = Icth; + *(ckt->CKTstate0 + here->VBICicth_Vrth) = Icth_Vrth; + } load: /* * load current excitation vector and matrix diff --git a/src/spicelib/devices/vbic/vbicsetup.c b/src/spicelib/devices/vbic/vbicsetup.c index c82f36871..f40a59988 100644 --- a/src/spicelib/devices/vbic/vbicsetup.c +++ b/src/spicelib/devices/vbic/vbicsetup.c @@ -469,7 +469,7 @@ VBICsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) } if(model->VBICselftGiven) - if(model->VBICselft == 1) + if((model->VBICselft == 1) && (model->VBICthermalResistGiven) && (model->VBICthermalResist > 0.0)) here->VBIC_selfheat = 1; else here->VBIC_selfheat = 0; diff --git a/src/spicelib/devices/vbic/vbictemp.c b/src/spicelib/devices/vbic/vbictemp.c index 84cb2121b..97126bbde 100644 --- a/src/spicelib/devices/vbic/vbictemp.c +++ b/src/spicelib/devices/vbic/vbictemp.c @@ -42,7 +42,7 @@ VBICtemp(GENmodel *inModel, CKTcircuit *ckt) TAMB = here->VBICtemp - CONSTCtoK; - memcpy (&pnom, &model->VBICtnom, 108*8); + memcpy (&pnom, &model->VBICtnom, sizeof(pnom)); iret = vbic_4T_et_cf_t(p,pnom,&TAMB); diff --git a/src/spicelib/devices/vsrc/vsrcacct.c b/src/spicelib/devices/vsrc/vsrcacct.c index 1ec386681..0be45f8e2 100644 --- a/src/spicelib/devices/vsrc/vsrcacct.c +++ b/src/spicelib/devices/vsrc/vsrcacct.c @@ -19,9 +19,6 @@ extern void fftFree(void); extern bool ft_ngdebug; /* some additional debug info printed */ -#define SAMETIME(a,b) (fabs((a)-(b))<= TIMETOL * PW) -#define TIMETOL 1e-7 - int VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) /* set up the breakpoint table. */ @@ -51,7 +48,6 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) case PULSE: { double TD, TR, TF, PW, PER; - double tshift; double time = 0.; double basetime = 0; double tmax = 1e99; @@ -79,7 +75,6 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) /* offset time by delay */ time = ckt->CKTtime - TD; - tshift = TD; if (newcompat.xs) { /* normalize phase to 0 - 360° */ @@ -90,71 +85,55 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) while (deltat > 0) deltat -= PER; time += deltat; - tshift = TD - deltat; - } - else if (PHASE > 0.0) { + } else if (PHASE > 0.0) { tmax = PHASE * PER; + if (time > tmax) + break; } - if (!newcompat.xs && time > tmax) { - /* Do nothing */ - } - else { + if (ckt->CKTtime >= here->VSRCbreak_time) { + double wait; + if (time >= PER) { - /* repeating signal - figure out where we are */ - /* in period */ + /* Repeating signal: where in period are we? */ + basetime = PER * floor(time / PER); time -= basetime; } - if (time <= 0.0 || time >= TR + PW + TF) { - if (ckt->CKTbreak && SAMETIME(time, 0.0)) { - error = CKTsetBreak(ckt, basetime + TR + tshift); - if (error) return(error); - } - else if (ckt->CKTbreak && SAMETIME(TR + PW + TF, time)) { - error = CKTsetBreak(ckt, basetime + PER + tshift); - if (error) return(error); - } - else if (ckt->CKTbreak && (time == -tshift)) { - error = CKTsetBreak(ckt, basetime + tshift); - if (error) return(error); - } - else if (ckt->CKTbreak && SAMETIME(PER, time)) { - error = CKTsetBreak(ckt, basetime + tshift + TR + PER); - if (error) return(error); - } - } - else if (time >= TR && time <= TR + PW) { - if (ckt->CKTbreak && SAMETIME(time, TR)) { - error = CKTsetBreak(ckt, basetime + tshift + TR + PW); - if (error) return(error); - } - else if (ckt->CKTbreak && SAMETIME(TR + PW, time)) { - error = CKTsetBreak(ckt, basetime + tshift + TR + PW + TF); - if (error) return(error); - } - } - else if (time > 0 && time < TR) { - if (ckt->CKTbreak && SAMETIME(time, 0)) { - error = CKTsetBreak(ckt, basetime + tshift + TR); - if (error) return(error); - } - else if (ckt->CKTbreak && SAMETIME(time, TR)) { - error = CKTsetBreak(ckt, basetime + tshift + TR + PW); - if (error) return(error); - } - } - else { /* time > TR + PW && < TR + PW + TF */ - if (ckt->CKTbreak && SAMETIME(time, TR + PW)) { - error = CKTsetBreak(ckt, basetime + tshift + TR + PW + TF); - if (error) return(error); - } - else if (ckt->CKTbreak && SAMETIME(time, TR + PW + TF)) { - error = CKTsetBreak(ckt, basetime + tshift + PER); - if (error) return(error); - } + /* Set next breakpoint. */ + + if (time < 0.0) { + /* Await first pulse */ + + wait = -time; + } else if (time < TR) { + /* Wait for end of rise. */ + + wait = TR - time; + } else if (time < TR + PW) { + /* Wait for fall. */ + + wait = TR + PW - time; + } else if (time < TR + PW + TF) { + /* Wait for end of fall. */ + + wait = TR + PW + TF - time; + } else { + /* Wait for next pulse. */ + wait = PER - time; } + here->VSRCbreak_time = ckt->CKTtime + wait; + error = CKTsetBreak(ckt, here->VSRCbreak_time); + if (error) + return error; + + /* If a timestep ends just before the break time, + * the break request may be ignored. + * Set threshold for requesting following break. + */ + + here->VSRCbreak_time -= ckt->CKTminBreak; } } break; @@ -179,25 +158,46 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) } break; - case PWL: { - int i; - if(ckt->CKTtime < *(here->VSRCcoeffs)) { - if(ckt->CKTbreak) { - error = CKTsetBreak(ckt,*(here->VSRCcoeffs)); - break; + case PWL: + if (ckt->CKTtime >= here->VSRCbreak_time) { + double time, end, period; + int i; + + time = ckt->CKTtime - here->VSRCrdelay; + end = + here->VSRCcoeffs[here->VSRCfunctionOrder - 2]; + if (time > end) { + if (here->VSRCrGiven) { + /* Repeating. */ + + period = end - + here->VSRCcoeffs[here->VSRCrBreakpt]; + time -= period * floor(time / period); + } else { + here->VSRCbreak_time = ckt->CKTfinalTime; + break; + } } - } - for(i=0;i<(here->VSRCfunctionOrder/2)-1;i++) { - if ( ckt->CKTbreak && AlmostEqualUlps(*(here->VSRCcoeffs+2*i), ckt->CKTtime, 3 ) ) { - error = CKTsetBreak(ckt, *(here->VSRCcoeffs+2*i+2)); - if(error) return(error); - goto bkptset; + + for (i = 0; + i < here->VSRCfunctionOrder; + i += 2) { + if (here->VSRCcoeffs[i] > time) { + here->VSRCbreak_time = + ckt->CKTtime + + here->VSRCcoeffs[i] - time; + error = CKTsetBreak(ckt, + here->VSRCbreak_time); + if (error) + return error; + here->VSRCbreak_time -= ckt->CKTminBreak; + break; + } } } break; - } - /**** tansient noise routines: + /**** transient noise routines: VNoi2 2 0 DC 0 TRNOISE(10n 0.5n 0 0n) : generate gaussian distributed noise rms value, time step, 0 0 VNoi1 1 0 DC 0 TRNOISE(0n 0.5n 1 10n) : generate 1/f noise @@ -205,6 +205,7 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) */ case TRNOISE: { + struct trnoise_state *state = here -> VSRCtrnoise_state; double TS = state -> TS; double RTSAM = state ->RTSAM; @@ -220,61 +221,55 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) fftFree(); } #endif - - if(ckt->CKTbreak) { - - int n = (int) floor(ckt->CKTtime / TS + 0.5); - volatile double nearest = n * TS; - - if(AlmostEqualUlps(nearest, ckt->CKTtime, 3)) { - /* carefull calculate `next' - * make sure it is really identical - * with the next calculated `nearest' value - */ - volatile double next = (n+1) * TS; - error = CKTsetBreak(ckt, next); - if(error) - return(error); - } + if (TS > 0 && ckt->CKTtime >= here->VSRCbreak_time) { + if (here->VSRCbreak_time < 0.0) + here->VSRCbreak_time = TS; + else + here->VSRCbreak_time += TS; + error = CKTsetBreak(ckt, here->VSRCbreak_time); + if (error) + return(error); + here->VSRCbreak_time -= ckt->CKTminBreak; } - if (RTSAM > 0) { - double RTScapTime = state->RTScapTime; - double RTSemTime = state->RTSemTime; - double RTSCAPT = state->RTSCAPT; - double RTSEMT = state->RTSEMT; + if (RTSAM <= 0) + break; /* No shot noise. */ - if (ckt->CKTtime == 0) { - /* initialzing here again needed for repeated calls to tran command */ - state->RTScapTime = RTScapTime = exprand(RTSCAPT); - state->RTSemTime = RTSemTime = RTScapTime + exprand(RTSEMT); + if (ckt->CKTtime == 0) { + /* initialzing here again needed for repeated calls to tran command */ + state->RTScapTime = exprand(state->RTSCAPT); + state->RTSemTime = + state->RTScapTime + exprand(state->RTSEMT); + error = CKTsetBreak(ckt, state->RTScapTime); + if(error) + return(error); + break; + } - if (ckt->CKTbreak) { - error = CKTsetBreak(ckt, RTScapTime); - if(error) - return(error); - } - } + /* Break handling code ends a timestep close to + * the requested time. + */ - if(AlmostEqualUlps(RTScapTime, ckt->CKTtime, 3)) { - if (ckt->CKTbreak) { - error = CKTsetBreak(ckt, RTSemTime); - if(error) - return(error); - } - } + if (ckt->CKTtime >= + state->RTScapTime - ckt->CKTminBreak && + ckt->CKTtime <= + state->RTScapTime + ckt->CKTminBreak) { + error = CKTsetBreak(ckt, state->RTSemTime); + if(error) + return(error); + } - if(AlmostEqualUlps(RTSemTime, ckt->CKTtime, 3)) { - /* new values */ - RTScapTime = here -> VSRCtrnoise_state ->RTScapTime = ckt->CKTtime + exprand(RTSCAPT); - here -> VSRCtrnoise_state ->RTSemTime = RTScapTime + exprand(RTSEMT); + if (ckt->CKTtime >= + state->RTSemTime - ckt->CKTminBreak) { + /* new values */ - if (ckt->CKTbreak) { - error = CKTsetBreak(ckt, RTScapTime); - if(error) - return(error); - } - } + state->RTScapTime = + ckt->CKTtime + exprand(state->RTSCAPT); + state->RTSemTime = + state->RTScapTime + exprand(state->RTSEMT); + error = CKTsetBreak(ckt, state->RTScapTime); + if(error) + return(error); } } break; @@ -286,30 +281,22 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) if (ckt->CKTtime == 0 && TD > 0) { error = CKTsetBreak(ckt, TD); + here->VSRCbreak_time = TD; if (error) return(error); + break; } - double time = ckt->CKTtime - TD; - - if (time < 0) break; - - if(ckt->CKTbreak) { - - int n = (int) floor(time / TS + 0.5); - volatile double nearest = n * TS; - - if(AlmostEqualUlps(nearest, time, 10)) { - /* carefully calculate `next' - * make sure it is really identical - * with the next calculated `nearest' value - */ - volatile double next = (n+1) * TS + TD; - error = CKTsetBreak(ckt, next); - if(error) - return(error); - state->value = trrandom_state_get(state); - } + if (ckt->CKTtime >= here->VSRCbreak_time) { + if (here->VSRCbreak_time < 0.0) + here->VSRCbreak_time = TS; + else + here->VSRCbreak_time += TS; + error = CKTsetBreak(ckt, here->VSRCbreak_time); + if (error) + return(error); + here->VSRCbreak_time -= ckt->CKTminBreak; + state->value = trrandom_state_get(state); } } break; @@ -323,7 +310,6 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) } // switch } // if ... else -bkptset: ; } // for } // for diff --git a/src/spicelib/devices/vsrc/vsrcdefs.h b/src/spicelib/devices/vsrc/vsrcdefs.h index 15c8b6951..346e75552 100644 --- a/src/spicelib/devices/vsrc/vsrcdefs.h +++ b/src/spicelib/devices/vsrc/vsrcdefs.h @@ -50,6 +50,7 @@ typedef struct sVSRCinstance { int VSRCfunctionType; /* code number of function type for source */ int VSRCfunctionOrder; /* order of the function for the source */ int VSRCrBreakpt; /* pwl repeat breakpoint index */ + double VSRCbreak_time; /* time of most-recent breakpoint */ double *VSRCcoeffs; /* pointer to array of coefficients */ double VSRCdcValue; /* DC and TRANSIENT value of source */ diff --git a/src/spicelib/devices/vsrc/vsrcload.c b/src/spicelib/devices/vsrc/vsrcload.c index beee1c99c..a24bacc31 100644 --- a/src/spicelib/devices/vsrc/vsrcload.c +++ b/src/spicelib/devices/vsrc/vsrcload.c @@ -298,43 +298,48 @@ VSRCload(GENmodel *inModel, CKTcircuit *ckt) break; case PWL: { - int i = 0, num_repeat = 0, ii = 0; - double foo, repeat_time = 0, end_time, breakpt_time, itime; + int i; + double end_time, itime; time -= here->VSRCrdelay; - - if(time < *(here->VSRCcoeffs)) { - foo = *(here->VSRCcoeffs + 1) ; - value = foo; - goto loadDone; + if (time < here->VSRCcoeffs[0]) { + value = here->VSRCcoeffs[1]; + value = value; + break; } - do { - for(i=ii ; i<(here->VSRCfunctionOrder/2)-1; i++ ) { - itime = *(here->VSRCcoeffs+2*i); - if ( AlmostEqualUlps(itime+repeat_time, time, 3 )) { - foo = *(here->VSRCcoeffs+2*i+1); - value = foo; - goto loadDone; - } else if ( (*(here->VSRCcoeffs+2*i)+repeat_time < time) - && (*(here->VSRCcoeffs+2*(i+1))+repeat_time > time) ) { - foo = *(here->VSRCcoeffs+2*i+1) + (((time-(*(here->VSRCcoeffs+2*i)+repeat_time))/ - (*(here->VSRCcoeffs+2*(i+1)) - *(here->VSRCcoeffs+2*i))) * - (*(here->VSRCcoeffs+2*i+3) - *(here->VSRCcoeffs+2*i+1))); - value = foo; - goto loadDone; - } + end_time = + here->VSRCcoeffs[here->VSRCfunctionOrder - 2]; + if (time > end_time) { + double period; + + if (here->VSRCrGiven) { + /* Repeating. */ + + period = end_time - + here->VSRCcoeffs[here->VSRCrBreakpt]; + time -= period * floor(time / period); + time += here->VSRCcoeffs[here->VSRCrBreakpt]; + } else { + value = + here->VSRCcoeffs[here->VSRCfunctionOrder - 1]; + break; } - foo = *(here->VSRCcoeffs+ here->VSRCfunctionOrder-1) ; - value = foo; + } - if ( !here->VSRCrGiven ) goto loadDone; - - end_time = *(here->VSRCcoeffs + here->VSRCfunctionOrder-2); - breakpt_time = *(here->VSRCcoeffs + here->VSRCrBreakpt); - repeat_time = end_time + (end_time - breakpt_time)*num_repeat++ - breakpt_time; - ii = here->VSRCrBreakpt/2; - } while ( here->VSRCrGiven ); + for (i = 2; i < here->VSRCfunctionOrder; i += 2) { + itime = here->VSRCcoeffs[i]; + if (itime >= time) { + time -= here->VSRCcoeffs[i - 2]; + time /= here->VSRCcoeffs[i] - + here->VSRCcoeffs[i - 2]; + value = here->VSRCcoeffs[i - 1]; + value += time * + ( here->VSRCcoeffs[i + 1] - + here->VSRCcoeffs[i - 1]); + break; + } + } break; } @@ -418,7 +423,6 @@ VNoi3 3 0 DC 0 TRNOISE(0 0 0 0 15m 22u 50u) : generate RTS noise } // switch } // else (line 48) -loadDone: /* gtri - begin - wbk - modify for supply ramping option */ #ifdef XSPICE_EXP diff --git a/src/spicelib/devices/vsrc/vsrcpar.c b/src/spicelib/devices/vsrc/vsrcpar.c index 19686293f..27bed7c4f 100644 --- a/src/spicelib/devices/vsrc/vsrcpar.c +++ b/src/spicelib/devices/vsrc/vsrcpar.c @@ -131,6 +131,13 @@ VSRCparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select) here->VSRCrGiven = FALSE; break; } + + /* buggy input? r is not a repetition coefficient */ + if (!here->VSRCcoeffs || here->VSRCfunctionOrder < 2) { + here->VSRCrGiven = FALSE; + break; + } + here->VSRCr = value->rValue; here->VSRCrGiven = TRUE; @@ -140,7 +147,7 @@ VSRCparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select) } end_time = *(here->VSRCcoeffs + here->VSRCfunctionOrder-2); - if ( here->VSRCr > end_time ) { + if ( here->VSRCr >= end_time ) { fprintf(stderr, "ERROR: repeat start time value %g for pwl voltage source must be smaller than final time point given!\n", here->VSRCr ); return ( E_PARMVAL ); } diff --git a/src/spicelib/devices/vsrc/vsrcset.c b/src/spicelib/devices/vsrc/vsrcset.c index 18d7764b7..3659e9755 100644 --- a/src/spicelib/devices/vsrc/vsrcset.c +++ b/src/spicelib/devices/vsrc/vsrcset.c @@ -31,6 +31,7 @@ VSRCsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *state) for (here = VSRCinstances(model); here != NULL ; here=VSRCnextInstance(here)) { + here->VSRCbreak_time = -1.0; // To set initial breakpoint if(here->VSRCposNode == here->VSRCnegNode) { SPfrontEnd->IFerrorf (ERR_FATAL, "instance %s is a shorted VSRC", here->VSRCname); diff --git a/src/spicelib/parser/inpgmod.c b/src/spicelib/parser/inpgmod.c index 8892343b7..6450abf6d 100644 --- a/src/spicelib/parser/inpgmod.c +++ b/src/spicelib/parser/inpgmod.c @@ -462,8 +462,10 @@ INPparseNumMod(CKTcircuit *ckt, INPmodel *model, INPtables *tab, char **errMessa /* Add card structure to model */ info = INPcardTab[lastType]; error = info->newCard(&tmpCard, model->INPmodfast); - if (error) + if (error) { + FREE(cardName); return error; + } /* Handle parameter-less cards */ } else if (cinprefix(cardName, "title", 3)) { /* Do nothing */ @@ -472,6 +474,7 @@ INPparseNumMod(CKTcircuit *ckt, INPmodel *model, INPtables *tab, char **errMessa } else if (cinprefix(cardName, "end", 3)) { /* Terminate parsing */ *errMessage = err; + FREE(cardName); return 0; } else { /* Error */ @@ -479,6 +482,7 @@ INPparseNumMod(CKTcircuit *ckt, INPmodel *model, INPtables *tab, char **errMessa tprintf("Error on card %d : unrecognized name (%s) - ignored", cardNum, cardName)); } + FREE(cardName); } } @@ -525,6 +529,8 @@ INPparseNumMod(CKTcircuit *ckt, INPmodel *model, INPtables *tab, char **errMessa } error = info->setCardParm(info->cardParms[idx].id, value, tmpCard); + if (info->cardParms[idx].dataType & IF_STRING) + FREE(value->sValue); if (error) return error; } diff --git a/src/spicelib/parser/inpgval.c b/src/spicelib/parser/inpgval.c index 1f5d9acaa..f9f84ad14 100644 --- a/src/spicelib/parser/inpgval.c +++ b/src/spicelib/parser/inpgval.c @@ -53,7 +53,8 @@ INPgetValue(CKTcircuit *ckt, char **line, int type, INPtables *tab) list[temp.v.numValue - 1] = tmp; tmp = INPevaluate(line, &error, 1); } - if (error && ft_ngdebug && !eq(*line, "") && !prefix(")", *line)) { + if (error && ft_ngdebug && !eq(*line, "") && !prefix(")", *line) && + temp.v.numValue > 1) { fprintf(stderr, "\nWarning: Reading a vector without limiting parens may be dangerous\n%s\nat\n", compline); fprintf(stderr, "%*s%s\n", (int)(*line - compline)," ", *line); } @@ -76,7 +77,8 @@ INPgetValue(CKTcircuit *ckt, char **line, int type, INPtables *tab) ilist[temp.v.numValue - 1] = (int) floor(0.5 + tmp); tmp = INPevaluate(line, &error, 1); } - if (error && ft_ngdebug && !eq(*line, "") && !prefix(")", *line)) { + if (error && ft_ngdebug && !eq(*line, "") && !prefix(")", *line) && + temp.v.numValue > 1) { fprintf(stderr, "\nWarning: Reading a vector without limiting parens may be dangerous\n%s\nat\n", compline); fprintf(stderr, "%*s%s\n", (int)(*line - compline), " ", *line); } diff --git a/src/spicelib/parser/inppas3.c b/src/spicelib/parser/inppas3.c index d1eaf6b13..f1d97b7b8 100644 --- a/src/spicelib/parser/inppas3.c +++ b/src/spicelib/parser/inppas3.c @@ -148,6 +148,8 @@ INPpas3(CKTcircuit *ckt, struct card *data, INPtables *tab, TSKtask *task, FREE(name); /* Gobble the rest of the token */ line = nexttok(line); + if (!line) + break; continue; } ptemp.rValue = INPevaluate(&line,&error,1); diff --git a/src/spicelib/parser/inpptree.c b/src/spicelib/parser/inpptree.c index 1f97cf082..398771048 100644 --- a/src/spicelib/parser/inpptree.c +++ b/src/spicelib/parser/inpptree.c @@ -1107,8 +1107,19 @@ INPparseNode *PT_mkfnode(const char *fname, INPparseNode * arg) INPparseNode *p; char buf[128]; + if (!fname) { + fprintf(stderr, "Error: bogus function name \n"); + return mkfirst(NULL, arg); + } + + if (!arg) { + fprintf(stderr, "Error: bad function arguments \n"); + return mkfirst(NULL, arg); + } + /* Make sure the case is ok. */ - (void) strcpy(buf, fname); + (void)strncpy(buf, fname, 127); + buf[127] = 0; strtolower(buf); if(!strcmp("ternary_fcn", buf)) { @@ -1142,7 +1153,6 @@ INPparseNode *PT_mkfnode(const char *fname, INPparseNode * arg) fprintf(stderr, "Error: no such function '%s'\n", buf); if (ft_stricterror) controlled_exit(EXIT_BAD); - return mkfirst(NULL, arg); } @@ -1250,7 +1260,8 @@ INPparseNode *PT_mksnode(const char *string, void *ckt) INPparseNode *p; /* Make sure the case is ok. */ - (void) strcpy(buf, string); + (void) strncpy(buf, string, 127); + buf[127] = 0; strtolower(buf); p = TMALLOC(INPparseNode, 1); diff --git a/src/spicelib/parser/sperror.c b/src/spicelib/parser/sperror.c index 1ada7e7d7..915afc79c 100644 --- a/src/spicelib/parser/sperror.c +++ b/src/spicelib/parser/sperror.c @@ -29,7 +29,10 @@ const char *SPerror(int type) case E_EXISTS: msg = "device already exists, existing one being used"; break; - case E_NODEV: + case E_EXISTS_BAD: + msg = "device already exists, bail out"; + break; + case E_NODEV: msg = "no such device"; break; case E_NOMOD: diff --git a/src/xspice/evt/evtbackup.c b/src/xspice/evt/evtbackup.c index f857c6816..52ce11b97 100644 --- a/src/xspice/evt/evtbackup.c +++ b/src/xspice/evt/evtbackup.c @@ -479,17 +479,26 @@ static void EVTbackup_inst_queue( } inst_queue->next_time = next_time; - /* Update the modified list by looking for any queued events */ - /* with posted time > last_time */ + /* Update the modified list by looking for events that were processed + * or queued in the current timestep. + */ + for(i = 0, j = 0; i < num_modified; i++) { inst_index = inst_queue->modified_index[i]; inst = *(inst_queue->last_step[inst_index]); - while(inst) { - if(inst->posted_time > inst_queue->last_time) - break; - inst = inst->next; + if (inst_queue->current[inst_index] == + inst_queue->last_step[inst_index]) { + /* Nothing now removed from the queue, + * but it may have been modified by an addition. + */ + + while (inst) { + if (inst->posted_time > inst_queue->last_time) + break; + inst = inst->next; + } } if(! inst) { diff --git a/src/xspice/evt/evtplot.c b/src/xspice/evt/evtplot.c index 7b1106f5f..af5c50792 100644 --- a/src/xspice/evt/evtplot.c +++ b/src/xspice/evt/evtplot.c @@ -88,11 +88,13 @@ struct dvec *EVTfindvec( int udn_index; int num_events; - Mif_Boolean_t found; + Mif_Boolean_t found; + Evt_Ckt_Data_t *evt; + CKTcircuit *ckt; Evt_Node_Info_t **node_table; - Evt_Node_t *head; - Evt_Node_t *event; - + Evt_Node_t *head; + Evt_Node_t *event; + double *anal_point_vec; double *value_vec; double value = 0; @@ -102,13 +104,16 @@ struct dvec *EVTfindvec( /* Exit immediately if event-driven stuff not allocated yet, */ /* or if number of event nodes is zero. */ - if(! g_mif_info.ckt) + + ckt = g_mif_info.ckt; + if(! ckt) return(NULL); - if(! g_mif_info.ckt->evt) + evt = ckt->evt; + if(! evt) return(NULL); - if(! g_mif_info.ckt->evt->info.node_table) + if(! evt->info.node_table) return(NULL); - if(g_mif_info.ckt->evt->counts.num_nodes == 0) + if(evt->counts.num_nodes == 0) return(NULL); /* Make a copy of the node name. */ @@ -134,8 +139,8 @@ struct dvec *EVTfindvec( } /* Look for node name in the event-driven node list */ - num_nodes = g_mif_info.ckt->evt->counts.num_nodes; - node_table = g_mif_info.ckt->evt->info.node_table; + num_nodes = evt->counts.num_nodes; + node_table = evt->info.node_table; for(i = 0, found = MIF_FALSE; i < num_nodes; i++) { if(cieq(name, node_table[i]->name)) { @@ -152,14 +157,14 @@ struct dvec *EVTfindvec( /* Get the UDN type index */ udn_index = node_table[i]->udn_index; - if (!g_mif_info.ckt->evt->data.node) { + if (!evt->data.node) { // fprintf(stderr, "Warning: No event data available! \n Simulation not yet run?\n"); tfree(name); return(NULL); } /* Count the number of events */ - head = g_mif_info.ckt->evt->data.node->head[i]; + head = evt->data.node->head[i]; for(event = head, num_events = 0; event; event = event->next) num_events++; @@ -170,8 +175,7 @@ struct dvec *EVTfindvec( /* Iterate through the events and fill the arrays. */ /* Note that we create vertical segments every time an event occurs. */ - /* Need to modify this in the future to complete the vector out to the */ - /* last analysis point... */ + for(i = 0, event = head; event; event = event->next) { /* If not first point, put the second value of the horizontal line in the vectors */ @@ -194,6 +198,11 @@ struct dvec *EVTfindvec( } + /* Add one more point so that the line will extend to the end of the plot. */ + + anal_point_vec[i] = ckt->CKTtime; + value_vec[i++] = value; + /* Allocate dvec structures and assign the vectors into them. */ /* See FTE/OUTinterface.c:plotInit() for initialization example. */ diff --git a/src/xspice/icm/analog/modpath.lst b/src/xspice/icm/analog/modpath.lst index 481162718..acf24b33f 100644 --- a/src/xspice/icm/analog/modpath.lst +++ b/src/xspice/icm/analog/modpath.lst @@ -14,6 +14,7 @@ sine slew square summer +xfer s_xfer triangle file_source diff --git a/src/xspice/icm/analog/xfer/cfunc.mod b/src/xspice/icm/analog/xfer/cfunc.mod new file mode 100644 index 000000000..e57cbeaa8 --- /dev/null +++ b/src/xspice/icm/analog/xfer/cfunc.mod @@ -0,0 +1,130 @@ +/* Transfer function block for AC simulation, based on s_xfer code model. */ + +#include + +#define PI 3.141592653589793238462643383279502884197 + +/* How the table information is stored internally. */ + +struct data_pt { + double f; /* Frequency, radians/sec. */ + Mif_Complex_t s; /* The S-parameter. */ +}; + +static void cleanup(ARGS, Mif_Callback_Reason_t reason) +{ + struct data_pt *table; + + switch (reason) { + case MIF_CB_DESTROY: + table = (struct data_pt *)STATIC_VAR(table); + if (table) { + free(table); + STATIC_VAR(table) = NULL; + } + break; + } +} + +void cm_xfer(ARGS) /* structure holding parms, inputs, outputs, etc. */ +{ + struct data_pt *table; + Mif_Complex_t ac_gain; + double factor; + int span, size, i; + + span = PARAM(span); + if (INIT) { + Mif_Boolean_t ri, db, rad; + int offset, bad = 0, j; + + /* Validate table. */ + + offset = PARAM(offset); + size = PARAM_SIZE(table); + bad = size % span; + if (!bad) { + for (i = 0; i < size - span; i += span) { + if (PARAM(table[i]) < 0 || + PARAM(table[i + span]) < PARAM(table[i])) { + bad = 1; + break; + } + } + } + if (bad) { + cm_message_send("Warning: badly formed table."); + return; + } + + /* Allocate the internal table. */ + + size /= span; + table = (struct data_pt *)calloc(size, sizeof(struct data_pt)); + STATIC_VAR(table) = table; + CALLBACK = cleanup; + + /* Fill it. */ + + ri = PARAM(r_i); + db = PARAM(db); + rad = PARAM(rad); + for (i = 0, j = 0; i < size; i++, j += span) { + table[i].f = PARAM(table[j]) * 2.0 * PI; + if (ri) { + table[i].s.real = PARAM(table[j + offset]); + table[i].s.imag = PARAM(table[j + offset + 1]); + } else { + double phase, mag; + + mag = PARAM(table[j + offset]); + if (db) + mag = pow(10, mag / 20); + phase = PARAM(table[j + offset + 1]); + if (!rad) + phase *= 2 * PI / 360; + table[i].s.real = mag * cos(phase); + table[i].s.imag = mag * sin(phase); + } + } + } + + table = (struct data_pt *)STATIC_VAR(table); + if (!table) + return; + if (ANALYSIS == MIF_AC) { + double rv; + + size = PARAM_SIZE(table) / span; + rv = RAD_FREQ; + if (rv <= table[0].f) { + ac_gain = table[0].s; + } else if (rv >= table[size - 1].f) { + ac_gain = table[size - 1].s; + } else { + for (i = 0; i < size; i++) { + if (table[i].f > rv) + break; + } + + /* Linear interpolation. */ + + factor = (rv - table[i - 1].f) / (table[i].f - table[i - 1].f); + ac_gain.real = table[i - 1].s.real + + factor * (table[i].s.real - table[i - 1].s.real); + ac_gain.imag = table[i - 1].s.imag + + factor * (table[i].s.imag - table[i - 1].s.imag); + } + AC_GAIN(out, in) = ac_gain; + } else { /* DC, transient ... */ + if (ANALYSIS == MIF_TRAN) { + if (!STATIC_VAR(warned)) { + STATIC_VAR(warned) = 1; + cm_message_send("The xfer code model does not support " + "transient analysis."); + } + } + OUTPUT(out) = table[0].s.real * INPUT(in); + } +} + diff --git a/src/xspice/icm/analog/xfer/ifspec.ifs b/src/xspice/icm/analog/xfer/ifspec.ifs new file mode 100644 index 000000000..41f2ac177 --- /dev/null +++ b/src/xspice/icm/analog/xfer/ifspec.ifs @@ -0,0 +1,91 @@ +/* Interface specification for PWL transfer function code model. */ + +NAME_TABLE: + +Spice_Model_Name: xfer +C_Function_Name: cm_xfer +Description: "AC transfer function block" + + +PORT_TABLE: + +Port_Name: in out +Description: "input" "output" +Direction: in out +Default_Type: v v +Allowed_Types: [v,vd,i,id] [v,vd,i,id] +Vector: no no +Vector_Bounds: - - +Null_Allowed: no no + +PARAMETER_TABLE: + +Parameter_Name: table +Description: "PWL table: frequency/magnitude/phase" +Data_Type: real +Default_Value: - +Limits: - +Vector: yes +Vector_Bounds: [3 -] +Null_Allowed: no + +PARAMETER_TABLE: + +Parameter_Name: r_i +Description: "table is in real/imaginary format" +Data_Type: boolean +Default_Value: false +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: + +Parameter_Name: db +Description: "table is in magnitude(dB)/phase format" +Data_Type: boolean +Default_Value: true +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: + +Parameter_Name: rad +Description: "phase in radians, not degrees" +Data_Type: boolean +Default_Value: false +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: + +Parameter_Name: span offset +Description: "Length of table rows" "Offset within row" +Data_Type: int int +Default_Value: 3 1 +Limits: [ 3 - ] [ 1 - ] +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + +/* This is used internally to store the table in compact complex form. */ + +STATIC_VAR_TABLE: + +Static_Var_Name: table +Description: "Internal copy of data" +Data_Type: pointer + +/* Only warn once about use in transient analysis. */ + +STATIC_VAR_TABLE: + +Static_Var_Name: warned +Description: "Warning indicator" +Data_Type: int + diff --git a/src/xspice/icm/digital/d_pwm/cfunc.mod b/src/xspice/icm/digital/d_pwm/cfunc.mod index 4aa5ec6be..8ed3930b1 100644 --- a/src/xspice/icm/digital/d_pwm/cfunc.mod +++ b/src/xspice/icm/digital/d_pwm/cfunc.mod @@ -404,6 +404,8 @@ void cm_d_pwm(ARGS) *t3 = T(1) + (1 - dphase)/frequency; } + cm_analog_set_temp_bkpt(*t1); + cm_analog_set_temp_bkpt(*t3); } break; diff --git a/visualc/vngspice-fftw.vcxproj b/visualc/vngspice-fftw.vcxproj index d44b3c013..10bb37c03 100644 --- a/visualc/vngspice-fftw.vcxproj +++ b/visualc/vngspice-fftw.vcxproj @@ -935,7 +935,6 @@ 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 f767965c8..3d14b4ed2 100644 --- a/visualc/vngspice.vcxproj +++ b/visualc/vngspice.vcxproj @@ -942,7 +942,6 @@ - diff --git a/visualc/xspice/analog.vcxproj b/visualc/xspice/analog.vcxproj index 39ec8381d..fd8097bc4 100644 --- a/visualc/xspice/analog.vcxproj +++ b/visualc/xspice/analog.vcxproj @@ -254,6 +254,8 @@ + + @@ -297,6 +299,8 @@ + +