From 82c620304b3178748c3d8a46ffa31917651e424f Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 5 Sep 2025 23:59:05 +0200 Subject: [PATCH 001/161] Fixing bug 804. Using function get_windows_canonical_path() may neglect the ngspice file search sequence, as an absolute path is returned also for relative input paths. ngspice however searches a file not only relative to the current directory, as inforced by this function, but for example also in the directory of the previous input file. So restrict this function to paths longer than MAX_PATH, which would fail otherwise. --- src/frontend/inpcom.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index ff9bb8072..71a3bdeaf 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -9844,6 +9844,10 @@ static void inp_meas_control(struct card* card) * might need to add the prefix separately if using the result in APIs * that require it for long path support. * + * Using this function however may neglect the ngspice file search sequence, + * as an absolute path is returned also for relative paths. + * So restrict this function to paths longer than MAX_PATH. + * * @param input_path The input path string (UTF-8 encoded). Can be relative or * absolute, may contain '.' or '..'. * @return char* A newly allocated UTF-8 string containing the canonical absolute @@ -9869,6 +9873,10 @@ char* get_windows_canonical_path(const char* input_path) { inputLenMB = (int)strlen(input_path); + /* If path length is less than MAX_PATH, just copy and return path. */ + if (inputLenMB < MAX_PATH) + return copy(input_path); + if (inputLenMB == 0) { inputLenW = 1; } From 724dc77b9153dc75eaec474b1f7a44f1fcf5f362 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 5 Sep 2025 23:59:35 +0200 Subject: [PATCH 002/161] Prepare bug-fix release ngspice-45.2. --- NEWS | 6 ++++++ configure.ac | 4 ++-- src/include/ngspice/sharedspice.h | 2 +- visualc/src/include/ngspice/config.h | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index a9b487200..f0816b363 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,9 @@ +Ngspice-45.2, Sept. 5th, 2025 +============ +- Bug-fix release + + A bug in the MS Windows version has been fixed + (bug no. 804, see https://sourceforge.net/p/ngspice/bugs/804/) + Ngspice-45, August 17th, 2025 ============ - New features: diff --git a/configure.ac b/configure.ac index 4432702bd..cf78f5acd 100644 --- a/configure.ac +++ b/configure.ac @@ -16,7 +16,7 @@ # problem to the user. AC_PREREQ([2.70]) -m4_define([ngspice_major_version], [45]) +m4_define([ngspice_major_version], [45.2]) m4_define([ngspice_minor_version], [0]) m4_define([ngspice_version], [ngspice_major_version]) @@ -117,7 +117,7 @@ LT_INIT([shared static]) # --> Set 'LT_NGSPICE_AGE' to 0. LT_NGSPICE_CURRENT=0 -LT_NGSPICE_REVISION=13 +LT_NGSPICE_REVISION=14 LT_NGSPICE_AGE=0 LIBNGSPICE_SO_VERSION=$LT_NGSPICE_CURRENT.$LT_NGSPICE_REVISION.$LT_NGSPICE_AGE diff --git a/src/include/ngspice/sharedspice.h b/src/include/ngspice/sharedspice.h index 04ff01bfb..c16455058 100644 --- a/src/include/ngspice/sharedspice.h +++ b/src/include/ngspice/sharedspice.h @@ -124,7 +124,7 @@ are of type bool if sharedspice.h is used externally. */ #ifndef NGSPICE_PACKAGE_VERSION -#define NGSPICE_PACKAGE_VERSION "45" +#define NGSPICE_PACKAGE_VERSION "45.2" #endif /* we have NG_BOOL instead of BOOL */ #ifndef HAS_NG_BOOL diff --git a/visualc/src/include/ngspice/config.h b/visualc/src/include/ngspice/config.h index 384b5a9e6..586b2deb8 100644 --- a/visualc/src/include/ngspice/config.h +++ b/visualc/src/include/ngspice/config.h @@ -15,7 +15,7 @@ #define PACKAGE "ngspice" /* Version number of package */ -#define VERSION "45" +#define VERSION "45.2" /* Define the directory for executables */ #define NGSPICEBINDIR "../bin" From 11ee1796394e7a66f3132ab50afe46d6c214fedb Mon Sep 17 00:00:00 2001 From: dwarning Date: Tue, 2 Sep 2025 09:44:16 +0200 Subject: [PATCH 003/161] adapt instance parameter extension to new bsim4 multiplier concept --- src/spicelib/devices/bsim4/b4ask.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/spicelib/devices/bsim4/b4ask.c b/src/spicelib/devices/bsim4/b4ask.c index 51913e7ed..76874bf73 100644 --- a/src/spicelib/devices/bsim4/b4ask.c +++ b/src/spicelib/devices/bsim4/b4ask.c @@ -421,15 +421,15 @@ BSIM4instance *here = (BSIM4instance*)inst; return(OK); case BSIM4_CGSO: value->rValue = here->BSIM4cgso; - value->rValue *= here->BSIM4m; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_CGDO: value->rValue = here->BSIM4cgdo; - value->rValue *= here->BSIM4m; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_CGBO: value->rValue = here->pParam->BSIM4cgbo; - value->rValue *= here->BSIM4m; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_WEFF: value->rValue = here->pParam->BSIM4weff; From 94b193ad9115f3c3b0028658e3d10a384f1c4ddf Mon Sep 17 00:00:00 2001 From: dwarning Date: Tue, 2 Sep 2025 09:50:20 +0200 Subject: [PATCH 004/161] prevent warning if NOBYPASS is not defined --- src/spicelib/devices/bsim4/b4ld.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/spicelib/devices/bsim4/b4ld.c b/src/spicelib/devices/bsim4/b4ld.c index a9c0ad47c..dcc991d22 100644 --- a/src/spicelib/devices/bsim4/b4ld.c +++ b/src/spicelib/devices/bsim4/b4ld.c @@ -4180,8 +4180,9 @@ finished: here->BSIM4cgso = cgso; here->BSIM4qgso = qgso; - +#ifndef NOBYPASS line755: +#endif ag0 = ckt->CKTag[0]; if (here->BSIM4mode > 0) { if (here->BSIM4trnqsMod == 0) From 2c9c2c20c49055593d98971f1ebb9f9070bb7bfe Mon Sep 17 00:00:00 2001 From: dwarning Date: Tue, 2 Sep 2025 10:10:33 +0200 Subject: [PATCH 005/161] reply commit e5c162f1: dc sweep fails after transient sim --- src/spicelib/devices/bsim4/b4ld.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/spicelib/devices/bsim4/b4ld.c b/src/spicelib/devices/bsim4/b4ld.c index dcc991d22..da408eaef 100644 --- a/src/spicelib/devices/bsim4/b4ld.c +++ b/src/spicelib/devices/bsim4/b4ld.c @@ -4604,6 +4604,10 @@ line755: if (!ChargeComputationNeeded) goto line850; + /* no integration, if dc sweep, but keep evaluating capacitances */ + if (ckt->CKTmode & MODEDCTRANCURVE) + goto line850; + if (ckt->CKTmode & MODEINITTRAN) { *(ckt->CKTstate1 + here->BSIM4qb) = *(ckt->CKTstate0 + here->BSIM4qb); From 50bfc214ab56b7772ff57f8545e8ded7b81214cb Mon Sep 17 00:00:00 2001 From: dwarning Date: Tue, 2 Sep 2025 11:15:38 +0200 Subject: [PATCH 006/161] bsim4: reimplement mobility and binning extension --- src/spicelib/devices/bsim4/b4.c | 3 ++- src/spicelib/devices/bsim4/b4ask.c | 6 ++++++ src/spicelib/devices/bsim4/b4par.c | 8 ++++++++ src/spicelib/devices/bsim4/b4set.c | 2 ++ src/spicelib/devices/bsim4/b4temp.c | 3 +++ src/spicelib/devices/bsim4/bsim4def.h | 20 +++++++++++++------- 6 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/spicelib/devices/bsim4/b4.c b/src/spicelib/devices/bsim4/b4.c index d0fddd8b3..b39901f32 100644 --- a/src/spicelib/devices/bsim4/b4.c +++ b/src/spicelib/devices/bsim4/b4.c @@ -55,9 +55,10 @@ IOP( "rbps", BSIM4_RBPS, IF_REAL , "Body resistance"), IOP( "rbpd", BSIM4_RBPD, IF_REAL , "Body resistance"), IOP( "delvto", BSIM4_DELVTO, IF_REAL , "Zero bias threshold voltage variation"), IOPR("delvt0", BSIM4_DELVTO, IF_REAL , "Zero bias threshold voltage variation"), +IOP( "mulu0", BSIM4_MULU0, IF_REAL, "Low field mobility multiplier"), IOP( "xgw", BSIM4_XGW, IF_REAL, "Distance from gate contact center to device edge"), IOP( "ngcon", BSIM4_NGCON, IF_REAL, "Number of gate contacts"), - +IOP( "wnflag", BSIM4_WNFLAG, IF_INTEGER, "W/NF device flag for bin selection"), IOP( "trnqsmod", BSIM4_TRNQSMOD, IF_INTEGER, "Transient NQS model selector"), IOP( "acnqsmod", BSIM4_ACNQSMOD, IF_INTEGER, "AC NQS model selector"), diff --git a/src/spicelib/devices/bsim4/b4ask.c b/src/spicelib/devices/bsim4/b4ask.c index 76874bf73..c0f843e95 100644 --- a/src/spicelib/devices/bsim4/b4ask.c +++ b/src/spicelib/devices/bsim4/b4ask.c @@ -129,6 +129,12 @@ BSIM4instance *here = (BSIM4instance*)inst; case BSIM4_DELVTO: value->rValue = here->BSIM4delvto; return(OK); + case BSIM4_MULU0: + value->rValue = here->BSIM4mulu0; + return(OK); + case BSIM4_WNFLAG: + value->iValue = here->BSIM4wnflag; + return(OK); case BSIM4_XGW: value->rValue = here->BSIM4xgw; return(OK); diff --git a/src/spicelib/devices/bsim4/b4par.c b/src/spicelib/devices/bsim4/b4par.c index 1ecd4af88..ac4a274c5 100644 --- a/src/spicelib/devices/bsim4/b4par.c +++ b/src/spicelib/devices/bsim4/b4par.c @@ -157,6 +157,14 @@ IFvalue *select) here->BSIM4delvto = value->rValue; here->BSIM4delvtoGiven = TRUE; break; + case BSIM4_MULU0: + here->BSIM4mulu0 = value->rValue; + here->BSIM4mulu0Given = TRUE; + break; + case BSIM4_WNFLAG: + here->BSIM4wnflag = value->iValue; + here->BSIM4wnflagGiven = TRUE; + break; case BSIM4_XGW: here->BSIM4xgw = value->rValue; here->BSIM4xgwGiven = TRUE; diff --git a/src/spicelib/devices/bsim4/b4set.c b/src/spicelib/devices/bsim4/b4set.c index 05185af03..0637be32e 100644 --- a/src/spicelib/devices/bsim4/b4set.c +++ b/src/spicelib/devices/bsim4/b4set.c @@ -2354,6 +2354,8 @@ BSIM4instance **InstArray; here->BSIM4rbpd = model->BSIM4rbpd; if (!here->BSIM4delvtoGiven) here->BSIM4delvto = 0.0; + if (!here->BSIM4mulu0Given) + here->BSIM4mulu0 = 1.0; if (!here->BSIM4xgwGiven) here->BSIM4xgw = model->BSIM4xgw; if (!here->BSIM4ngconGiven) diff --git a/src/spicelib/devices/bsim4/b4temp.c b/src/spicelib/devices/bsim4/b4temp.c index 172bb74ad..b9a0434c7 100644 --- a/src/spicelib/devices/bsim4/b4temp.c +++ b/src/spicelib/devices/bsim4/b4temp.c @@ -1768,6 +1768,9 @@ int Fatal_Flag = 0; here->BSIM4vth0 += here->BSIM4delvto; here->BSIM4vfb = pParam->BSIM4vfb + model->BSIM4type * here->BSIM4delvto; + /* low field mobility multiplier */ + here->BSIM4u0temp = pParam->BSIM4u0temp * here->BSIM4mulu0; + /* Instance variables calculation */ T3 = model->BSIM4type * here->BSIM4vth0 - here->BSIM4vfb - pParam->BSIM4phi; diff --git a/src/spicelib/devices/bsim4/bsim4def.h b/src/spicelib/devices/bsim4/bsim4def.h index 59d82ceab..a2bff4121 100644 --- a/src/spicelib/devices/bsim4/bsim4def.h +++ b/src/spicelib/devices/bsim4/bsim4def.h @@ -117,6 +117,8 @@ typedef struct sBSIM4instance double BSIM4rbpd; double BSIM4delvto; + double BSIM4mulu0; + int BSIM4wnflag; double BSIM4xgw; double BSIM4ngcon; @@ -310,6 +312,8 @@ typedef struct sBSIM4instance unsigned BSIM4rbpdGiven :1; unsigned BSIM4rbpsGiven :1; unsigned BSIM4delvtoGiven :1; + unsigned BSIM4mulu0Given :1; + unsigned BSIM4wnflagGiven :1; unsigned BSIM4xgwGiven :1; unsigned BSIM4ngconGiven :1; unsigned BSIM4icVDSGiven :1; @@ -2864,14 +2868,16 @@ typedef struct sBSIM4model #define BSIM4_SCC 36 #define BSIM4_SC 37 #define BSIM4_M 38 +#define BSIM4_MULU0 39 +#define BSIM4_WNFLAG 40 -#define BSIM4_VGSTEFF 40 -#define BSIM4_VDSEFF 41 -#define BSIM4_CGSO 42 -#define BSIM4_CGDO 43 -#define BSIM4_CGBO 44 -#define BSIM4_WEFF 45 -#define BSIM4_LEFF 46 +#define BSIM4_VGSTEFF 41 +#define BSIM4_VDSEFF 42 +#define BSIM4_CGSO 43 +#define BSIM4_CGDO 44 +#define BSIM4_CGBO 45 +#define BSIM4_WEFF 46 +#define BSIM4_LEFF 47 /* Global parameters */ #define BSIM4_MOD_TEMPEOT 66 From ce55f05e1b9ad4e4369968213fc5ac84984b17b8 Mon Sep 17 00:00:00 2001 From: dwarning Date: Tue, 2 Sep 2025 11:40:11 +0200 Subject: [PATCH 007/161] bsim4: unify error printout --- src/spicelib/devices/bsim4/b4temp.c | 56 ++++++++++++----------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/src/spicelib/devices/bsim4/b4temp.c b/src/spicelib/devices/bsim4/b4temp.c index b9a0434c7..3c9796db6 100644 --- a/src/spicelib/devices/bsim4/b4temp.c +++ b/src/spicelib/devices/bsim4/b4temp.c @@ -435,12 +435,12 @@ int Fatal_Flag = 0; Wdrn = here->BSIM4w / here->BSIM4nf; if (Size_Not_Found) - { pParam = (struct bsim4SizeDependParam *)malloc( - sizeof(struct bsim4SizeDependParam)); + { pParam = TMALLOC(struct bsim4SizeDependParam, 1); + if (pLastKnot == NULL) - model->pSizeDependParamKnot = pParam; + model->pSizeDependParamKnot = pParam; else - pLastKnot->pNext = pParam; + pLastKnot->pNext = pParam; pParam->pNext = NULL; here->pParam = pParam; @@ -471,56 +471,46 @@ int Fatal_Flag = 0; pParam->BSIM4leff = Lnew - 2.0 * pParam->BSIM4dl; if (pParam->BSIM4leff <= 0.0) - { IFuid namarray[2]; - namarray[0] = model->BSIM4modName; - namarray[1] = here->BSIM4name; - (*(SPfrontEnd->IFerror))(ERR_FATAL, + { + SPfrontEnd->IFerrorf(ERR_FATAL, "BSIM4: mosfet %s, model %s: Effective channel length <= 0", - namarray); + model->BSIM4modName, here->BSIM4name); return(E_BADPARM); } pParam->BSIM4weff = Wnew - 2.0 * pParam->BSIM4dw; if (pParam->BSIM4weff <= 0.0) - { IFuid namarray[2]; - namarray[0] = model->BSIM4modName; - namarray[1] = here->BSIM4name; - (*(SPfrontEnd->IFerror))(ERR_FATAL, + { + SPfrontEnd->IFerrorf(ERR_FATAL, "BSIM4: mosfet %s, model %s: Effective channel width <= 0", - namarray); + model->BSIM4modName, here->BSIM4name); return(E_BADPARM); } pParam->BSIM4leffCV = Lnew - 2.0 * pParam->BSIM4dlc; if (pParam->BSIM4leffCV <= 0.0) - { IFuid namarray[2]; - namarray[0] = model->BSIM4modName; - namarray[1] = here->BSIM4name; - (*(SPfrontEnd->IFerror))(ERR_FATAL, + { + SPfrontEnd->IFerrorf(ERR_FATAL, "BSIM4: mosfet %s, model %s: Effective channel length for C-V <= 0", - namarray); + model->BSIM4modName, here->BSIM4name); return(E_BADPARM); } pParam->BSIM4weffCV = Wnew - 2.0 * pParam->BSIM4dwc; if (pParam->BSIM4weffCV <= 0.0) - { IFuid namarray[2]; - namarray[0] = model->BSIM4modName; - namarray[1] = here->BSIM4name; - (*(SPfrontEnd->IFerror))(ERR_FATAL, + { + SPfrontEnd->IFerrorf(ERR_FATAL, "BSIM4: mosfet %s, model %s: Effective channel width for C-V <= 0", - namarray); + model->BSIM4modName, here->BSIM4name); return(E_BADPARM); } pParam->BSIM4weffCJ = Wnew - 2.0 * pParam->BSIM4dwj; if (pParam->BSIM4weffCJ <= 0.0) - { IFuid namarray[2]; - namarray[0] = model->BSIM4modName; - namarray[1] = here->BSIM4name; - (*(SPfrontEnd->IFerror))(ERR_FATAL, + { + SPfrontEnd->IFerrorf(ERR_FATAL, "BSIM4: mosfet %s, model %s: Effective channel width for S/D junctions <= 0", - namarray); + model->BSIM4modName, here->BSIM4name); return(E_BADPARM); } @@ -2404,10 +2394,10 @@ int Fatal_Flag = 0; } if (BSIM4checkModel(model, here, ckt)) - { IFuid namarray[2]; - namarray[0] = model->BSIM4modName; - namarray[1] = here->BSIM4name; - (*(SPfrontEnd->IFerror)) (ERR_FATAL, "Fatal error(s) detected during BSIM4.6.0 parameter checking for %s in model %s", namarray); + { + SPfrontEnd->IFerrorf(ERR_FATAL, + "detected during BSIM4.8.3 parameter checking for \n model %s of device instance %s\n", model->BSIM4modName, here->BSIM4name); + return(E_BADPARM); } } /* End instance */ From 49b35ed3fc4f66732271257c272a3970f6bb86c3 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 3 Feb 2026 13:52:36 +0100 Subject: [PATCH 008/161] We are developing towards ngspice-46 --- configure.ac | 2 +- src/include/ngspice/sharedspice.h | 2 +- visualc/src/include/ngspice/config.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index cf78f5acd..d7189937b 100644 --- a/configure.ac +++ b/configure.ac @@ -16,7 +16,7 @@ # problem to the user. AC_PREREQ([2.70]) -m4_define([ngspice_major_version], [45.2]) +m4_define([ngspice_major_version], [45.2+]) m4_define([ngspice_minor_version], [0]) m4_define([ngspice_version], [ngspice_major_version]) diff --git a/src/include/ngspice/sharedspice.h b/src/include/ngspice/sharedspice.h index c16455058..146b8bbe9 100644 --- a/src/include/ngspice/sharedspice.h +++ b/src/include/ngspice/sharedspice.h @@ -124,7 +124,7 @@ are of type bool if sharedspice.h is used externally. */ #ifndef NGSPICE_PACKAGE_VERSION -#define NGSPICE_PACKAGE_VERSION "45.2" +#define NGSPICE_PACKAGE_VERSION "45.2+" #endif /* we have NG_BOOL instead of BOOL */ #ifndef HAS_NG_BOOL diff --git a/visualc/src/include/ngspice/config.h b/visualc/src/include/ngspice/config.h index 586b2deb8..096b80fee 100644 --- a/visualc/src/include/ngspice/config.h +++ b/visualc/src/include/ngspice/config.h @@ -15,7 +15,7 @@ #define PACKAGE "ngspice" /* Version number of package */ -#define VERSION "45.2" +#define VERSION "45.2+" /* Define the directory for executables */ #define NGSPICEBINDIR "../bin" From af28d2416d20b0d2e30c706ba60d2e6f3afc5cc5 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Thu, 4 Sep 2025 00:25:26 +0200 Subject: [PATCH 009/161] free(info.errors) leads to a assertion error on the heap. On Windows it reads: is_block_type_valid(header->_block_use). Memory for info.errors is allocated in the osdi device dll during the call to descr->setup_instance((void *)&handle, inst, model, temp, connected_terminals, sim_params, &init_info); (in fcn OSDIsetup(), line 254 of osdisetup.c). Therefore ngspice is not the owner of this memory and thus cannot free it. Fixes bug no. 803. --- src/osdi/osdisetup.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/osdi/osdisetup.c b/src/osdi/osdisetup.c index 4feb3ec90..46cabceb5 100644 --- a/src/osdi/osdisetup.c +++ b/src/osdi/osdisetup.c @@ -46,7 +46,6 @@ static int handle_init_info(OsdiInitInfo info, const OsdiDescriptor *descr) { printf("Unknown OSDO init error code %d!\n", err->code); } } - free(info.errors); errMsg = tprintf("%i errors occurred during initialization", info.num_errors); return (E_PRIVATE); } From 20561d309d84328382ece50760d88c5789d16d0f Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 7 Sep 2025 18:49:22 +0200 Subject: [PATCH 010/161] Remove files that are remade anyway. Makefile.in prescribed using aclocal 1.16. The fix removes any dependency on the autotool version. Fixing bug 806. --- autogen.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/autogen.sh b/autogen.sh index bd1c3f5a0..2e3b036c7 100755 --- a/autogen.sh +++ b/autogen.sh @@ -115,6 +115,10 @@ fi exit 1 } +echo "Removing files to be remade" +rm -f Makefile.in aclocal.m4 ar-lib config.guess config.sub +rm -f depcomp install-sh ltmain.sh missing ylwrap +rm -r -f autom4te.cache echo "Running $LIBTOOLIZE" $LIBTOOLIZE --copy --force \ From 7af862af3da4bfb9b3c8d4662829063b724b6110 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Wed, 3 Sep 2025 16:56:36 -0700 Subject: [PATCH 011/161] Enable CIDER with KLU for DC, OP, and TRAN analyses. Small signal AC analysis is not yet supported for CIDER complex valued device KLU matrices. The examples/cider testcases produce printed simulation result values which have slight differences between Sparse and KLU. Differences are probably expected and in a few cases are ~1-2%, sometimes a little more. This should be good enough for most CIDER analyses. Francesco did a good piece of work. Runtimes are significantly shorter with KLU. --- examples/cider/surfmob/Tbicmpd1.cir | 111 ++++++++++++ examples/cider/surfmob/Tbicmpd1xy.cir | 111 ++++++++++++ examples/cider/surfmob/Tbicmpu1.cir | 105 ++++++++++++ examples/cider/surfmob/Tbicmpu1xy.cir | 105 ++++++++++++ examples/cider/surfmob/cd4007n_200402idvg.net | 159 ++++++++++++++++++ examples/cider/surfmob/cdxy.net | 159 ++++++++++++++++++ examples/cider/surfmob/runtests.sh | 9 + examples/cider/surfmob/spiceinit | 2 + src/ciderlib/oned/oneadmit.c | 38 ++++- src/ciderlib/twod/twoadmit.c | 45 +++++ src/ciderlib/twod/twocont.c | 3 +- src/ciderlib/twod/twoncont.c | 3 +- src/ciderlib/twod/twopcont.c | 3 +- src/spicelib/devices/nbjt/nbjtset.c | 2 +- src/spicelib/devices/nbjt2/nbt2set.c | 2 +- src/spicelib/devices/numd/numdset.c | 2 +- src/spicelib/devices/numd2/nud2set.c | 2 +- src/spicelib/devices/numos/nummset.c | 2 +- 18 files changed, 854 insertions(+), 9 deletions(-) create mode 100644 examples/cider/surfmob/Tbicmpd1.cir create mode 100644 examples/cider/surfmob/Tbicmpd1xy.cir create mode 100644 examples/cider/surfmob/Tbicmpu1.cir create mode 100644 examples/cider/surfmob/Tbicmpu1xy.cir create mode 100644 examples/cider/surfmob/cd4007n_200402idvg.net create mode 100644 examples/cider/surfmob/cdxy.net create mode 100755 examples/cider/surfmob/runtests.sh create mode 100644 examples/cider/surfmob/spiceinit diff --git a/examples/cider/surfmob/Tbicmpd1.cir b/examples/cider/surfmob/Tbicmpd1.cir new file mode 100644 index 000000000..2da793fbf --- /dev/null +++ b/examples/cider/surfmob/Tbicmpd1.cir @@ -0,0 +1,111 @@ +BiCMOS Pulldown Circuit + +VSS 2 0 0v + +VIN 3 2 0v (PULSE 0.0v 4.2v 0ns 1ns 1ns 9ns 20ns) + +M1 8 3 5 11 M_NMOS_1 W=4u L=1u +VD 4 8 0v +VBK 11 2 0v + +Q1 10 7 9 M_NPN AREA=8 +VC 4 10 0v +VB 5 7 0v +VE 9 2 0v + +CL 4 6 1pF +VL 6 2 0v + +.IC V(10)=5.0v V(7)=0.0v +*.TRAN 0.1ns 5ns 0ns 0.1ns +.TRAN 0.1ns 0.3ns 0ns 0.1ns +.PLOT TRAN I(VIN) + +*.include bicmos.lib +.MODEL M_NPN nbjt level=2 ++ title TWO-DIMENSIONAL NUMERICAL POLYSILICON EMITTER BIPOLAR TRANSISTOR ++ * Since, we are only simulating half of a device, we double the unit width ++ * 1.0 um emitter length ++ options defw=2.0u ++ ++ *x.mesh w=2.5 n=5 ++ x.mesh w=2.0 h.e=0.05 h.m=0.2 r=1.5 ++ x.mesh w=0.5 h.s=0.05 h.m=0.1 r=1.5 ++ ++ y.mesh l=-0.2 n=1 ++ y.mesh l= 0.0 n=5 ++ y.mesh w=0.10 h.e=0.002 h.m=0.01 r=1.5 ++ y.mesh w=0.15 h.s=0.002 h.m=0.01 r=1.5 ++ y.mesh w=0.35 h.s=0.01 h.m=0.2 r=1.5 ++ y.mesh w=0.40 h.e=0.05 h.m=0.2 r=1.5 ++ y.mesh w=0.30 h.s=0.05 h.m=0.1 r=1.5 ++ ++ domain num=1 material=1 x.l=2.0 y.h=0.0 ++ domain num=2 material=2 x.h=2.0 y.h=0.0 ++ domain num=3 material=3 y.l=0.0 ++ material num=1 polysilicon ++ material num=2 oxide ++ material num=3 silicon ++ ++ elec num=1 x.l=0.0 x.h=0.0 y.l=1.1 y.h=1.3 ++ elec num=2 x.l=0.0 x.h=0.5 y.l=0.0 y.h=0.0 ++ elec num=3 x.l=2.0 x.h=3.0 y.l=-0.2 y.h=-0.2 ++ ++ doping gauss n.type conc=3e20 x.l=2.0 x.h=3.0 y.l=-0.2 y.h=0.0 ++ + char.l=0.047 lat.rotate ++ doping gauss p.type conc=1e19 x.l=0.0 x.h=5.0 y.l=-0.2 y.h=0.0 ++ + char.l=0.094 lat.rotate ++ doping unif n.type conc=1e16 x.l=0.0 x.h=5.0 y.l=0.0 y.h=1.3 ++ doping gauss n.type conc=5e19 x.l=0.0 x.h=5.0 y.l=1.3 y.h=1.3 ++ + char.l=0.100 lat.rotate ++ ++ method ac=direct itlim=10 ++ models bgn srh auger conctau concmob fieldmob + +.MODEL M_NMOS_1 numos ++ title 1.0um NMOS Device ++ ++ x.mesh w=0.9 h.e=0.020 h.m=0.2 r=2.0 ++ x.mesh w=0.2 h.e=0.005 h.m=0.02 r=2.0 ++ x.mesh w=0.4 h.s=0.005 h.m=0.1 r=2.0 ++ x.mesh w=0.4 h.e=0.005 h.m=0.1 r=2.0 ++ x.mesh w=0.2 h.e=0.005 h.m=0.02 r=2.0 ++ x.mesh w=0.9 h.s=0.020 h.m=0.2 r=2.0 ++ ++ y.mesh l=-.0200 n=1 ++ y.mesh l=0.0 n=6 ++ y.mesh w=0.15 h.s=0.0001 h.max=.02 r=2.0 ++ y.mesh w=0.45 h.s=0.02 h.max=0.2 r=2.0 ++ y.mesh w=1.40 h.s=0.20 h.max=0.4 r=2.0 ++ ++ region num=1 material=1 y.h=0.0 ++ region num=2 material=2 y.l=0.0 ++ interface dom=2 nei=1 x.l=1.0 x.h=2.0 layer.width=0.0 ++ material num=1 oxide ++ material num=2 silicon ++ ++ elec num=1 x.l=2.5 x.h=3.1 y.l=0.0 y.h=0.0 ++ elec num=2 x.l=1.0 x.h=2.0 iy.l=1 iy.h=1 ++ elec num=3 x.l=-0.1 x.h=0.5 y.l=0.0 y.h=0.0 ++ elec num=4 x.l=-0.1 x.h=3.1 y.l=2.0 y.h=2.0 ++ ++ doping gauss p.type conc=1.0e17 x.l=-0.1 x.h=3.1 y.l=0.0 ++ + char.l=0.30 ++ doping unif p.type conc=5.0e15 x.l=-0.1 x.h=3.1 y.l=0.0 y.h=2.1 ++ doping gauss n.type conc=4e17 x.l=-0.1 x.h=1.0 y.l=0.0 y.h=0.0 ++ + char.l=0.16 lat.rotate ratio=0.65 ++ doping gauss n.type conc=1e20 x.l=-0.1 x.h=0.95 y.l=0.0 y.h=0.08 ++ + char.l=0.03 lat.rotate ratio=0.65 ++ doping gauss n.type conc=4e17 x.l=2.0 x.h=3.1 y.l=0.0 y.h=0.0 ++ + char.l=0.16 lat.rotate ratio=0.65 ++ doping gauss n.type conc=1e20 x.l=2.05 x.h=3.1 y.l=0.0 y.h=0.08 ++ + char.l=0.03 lat.rotate ratio=0.65 ++ ++ contact num=2 workf=4.10 ++ models concmob fieldmob surfmob srh auger conctau bgn ^aval ++ method ac=direct itlim=10 onec + + +* .OPTIONS ACCT BYPASS=1 filetype=ascii +* .OPTIONS filetype=ascii +.END diff --git a/examples/cider/surfmob/Tbicmpd1xy.cir b/examples/cider/surfmob/Tbicmpd1xy.cir new file mode 100644 index 000000000..12fc7541b --- /dev/null +++ b/examples/cider/surfmob/Tbicmpd1xy.cir @@ -0,0 +1,111 @@ +BiCMOS Pulldown Circuit + +VSS 2 0 0v + +VIN 3 2 0v (PULSE 0.0v 4.2v 0ns 1ns 1ns 9ns 20ns) + +M1 8 3 5 11 M_NMOS_1 W=4u L=1u +VD 4 8 0v +VBK 11 2 0v + +Q1 10 7 9 M_NPN AREA=8 +VC 4 10 0v +VB 5 7 0v +VE 9 2 0v + +CL 4 6 1pF +VL 6 2 0v + +.IC V(10)=5.0v V(7)=0.0v +*.TRAN 0.1ns 5ns 0ns 0.1ns +.TRAN 0.1ns 0.3ns 0ns 0.1ns +.PLOT TRAN I(VIN) + +*.include bicmos.lib +.MODEL M_NPN nbjt level=2 ++ title TWO-DIMENSIONAL NUMERICAL POLYSILICON EMITTER BIPOLAR TRANSISTOR ++ * Since, we are only simulating half of a device, we double the unit width ++ * 1.0 um emitter length ++ options defw=2.0u ++ ++ *y.mesh w=2.5 n=5 ++ y.mesh w=2.0 h.e=0.05 h.m=0.2 r=1.5 ++ y.mesh w=0.5 h.s=0.05 h.m=0.1 r=1.5 ++ ++ x.mesh l=-0.2 n=1 ++ x.mesh l= 0.0 n=5 ++ x.mesh w=0.10 h.e=0.002 h.m=0.01 r=1.5 ++ x.mesh w=0.15 h.s=0.002 h.m=0.01 r=1.5 ++ x.mesh w=0.35 h.s=0.01 h.m=0.2 r=1.5 ++ x.mesh w=0.40 h.e=0.05 h.m=0.2 r=1.5 ++ x.mesh w=0.30 h.s=0.05 h.m=0.1 r=1.5 ++ ++ domain num=1 material=1 y.l=2.0 x.h=0.0 ++ domain num=2 material=2 y.h=2.0 x.h=0.0 ++ domain num=3 material=3 x.l=0.0 ++ material num=1 polysilicon ++ material num=2 oxide ++ material num=3 silicon ++ ++ elec num=1 y.l=0.0 y.h=0.0 x.l=1.1 x.h=1.3 ++ elec num=2 y.l=0.0 y.h=0.5 x.l=0.0 x.h=0.0 ++ elec num=3 y.l=2.0 y.h=3.0 x.l=-0.2 x.h=-0.2 ++ ++ doping gauss n.type conc=3e20 y.l=2.0 y.h=3.0 x.l=-0.2 x.h=0.0 ++ + char.l=0.047 lat.rotate ++ doping gauss p.type conc=1e19 y.l=0.0 y.h=5.0 x.l=-0.2 x.h=0.0 ++ + char.l=0.094 lat.rotate ++ doping unif n.type conc=1e16 y.l=0.0 y.h=5.0 x.l=0.0 x.h=1.3 ++ doping gauss n.type conc=5e19 y.l=0.0 y.h=5.0 x.l=1.3 x.h=1.3 ++ + char.l=0.100 lat.rotate ++ ++ method ac=direct itlim=10 ++ models bgn srh auger conctau concmob fieldmob + +.MODEL M_NMOS_1 numos ++ title 1.0um NMOS Device ++ ++ y.mesh w=0.9 h.e=0.020 h.m=0.2 r=2.0 ++ y.mesh w=0.2 h.e=0.005 h.m=0.02 r=2.0 ++ y.mesh w=0.4 h.s=0.005 h.m=0.1 r=2.0 ++ y.mesh w=0.4 h.e=0.005 h.m=0.1 r=2.0 ++ y.mesh w=0.2 h.e=0.005 h.m=0.02 r=2.0 ++ y.mesh w=0.9 h.s=0.020 h.m=0.2 r=2.0 ++ ++ x.mesh l=-.0200 n=1 ++ x.mesh l=0.0 n=6 ++ x.mesh w=0.15 h.s=0.0001 h.max=.02 r=2.0 ++ x.mesh w=0.45 h.s=0.02 h.max=0.2 r=2.0 ++ x.mesh w=1.40 h.s=0.20 h.max=0.4 r=2.0 ++ ++ region num=1 material=1 x.h=0.0 ++ region num=2 material=2 x.l=0.0 ++ interface dom=2 nei=1 y.l=1.0 y.h=2.0 layer.width=0.0 ++ material num=1 oxide ++ material num=2 silicon ++ ++ elec num=1 y.l=2.5 y.h=3.1 x.l=0.0 x.h=0.0 ++ elec num=2 y.l=1.0 y.h=2.0 ix.l=1 ix.h=1 ++ elec num=3 y.l=-0.1 y.h=0.5 x.l=0.0 x.h=0.0 ++ elec num=4 y.l=-0.1 y.h=3.1 x.l=2.0 x.h=2.0 ++ ++ doping gauss p.type conc=1.0e17 y.l=-0.1 y.h=3.1 x.l=0.0 ++ + char.l=0.30 ++ doping unif p.type conc=5.0e15 y.l=-0.1 y.h=3.1 x.l=0.0 x.h=2.1 ++ doping gauss n.type conc=4e17 y.l=-0.1 y.h=1.0 x.l=0.0 x.h=0.0 ++ + char.l=0.16 lat.rotate ratio=0.65 ++ doping gauss n.type conc=1e20 y.l=-0.1 y.h=0.95 x.l=0.0 x.h=0.08 ++ + char.l=0.03 lat.rotate ratio=0.65 ++ doping gauss n.type conc=4e17 y.l=2.0 y.h=3.1 x.l=0.0 x.h=0.0 ++ + char.l=0.16 lat.rotate ratio=0.65 ++ doping gauss n.type conc=1e20 y.l=2.05 y.h=3.1 x.l=0.0 x.h=0.08 ++ + char.l=0.03 lat.rotate ratio=0.65 ++ ++ contact num=2 workf=4.10 ++ models concmob fieldmob surfmob srh auger conctau bgn ^aval ++ method ac=direct itlim=10 onec + + +* .OPTIONS ACCT BYPASS=1 filetype=ascii +* .OPTIONS filetype=ascii +.END diff --git a/examples/cider/surfmob/Tbicmpu1.cir b/examples/cider/surfmob/Tbicmpu1.cir new file mode 100644 index 000000000..d1e381786 --- /dev/null +++ b/examples/cider/surfmob/Tbicmpu1.cir @@ -0,0 +1,105 @@ +BICMOS INVERTER PULLUP CIRCUIT + +VDD 1 0 5.0V +VSS 2 0 0.0V + +VIN 3 0 0.75V + +VC 1 11 0.0V +VB 5 15 0.0V + +Q1 11 15 4 M_NPNS AREA=8 +M1 5 3 1 1 M_PMOS_1 W=10U L=1U + +CL 4 0 5.0PF + +.IC V(4)=0.75V V(5)=0.0V + +.MODEL M_NPNS nbjt level=2 ++ title TWO-DIMENSIONAL NUMERICAL POLYSILICON EMITTER BIPOLAR TRANSISTOR ++ * Since half the device is simulated, double the unit width to get ++ * 1.0 um emitter. Use a small mesh for this model. ++ options defw=2.0u ++ ++ x.mesh w=2.0 h.e=0.02 h.m=0.5 r=2.0 ++ x.mesh w=0.5 h.s=0.02 h.m=0.2 r=2.0 ++ ++ y.mesh l=-0.2 n=1 ++ y.mesh l= 0.0 n=5 ++ y.mesh w=0.10 h.e=0.004 h.m=0.05 r=2.5 ++ y.mesh w=0.15 h.s=0.004 h.m=0.02 r=2.5 ++ y.mesh w=1.05 h.s=0.02 h.m=0.1 r=2.5 ++ ++ domain num=1 material=1 x.l=2.0 y.h=0.0 ++ domain num=2 material=2 x.h=2.0 y.h=0.0 ++ domain num=3 material=3 y.l=0.0 ++ material num=1 polysilicon ++ material num=2 oxide ++ material num=3 silicon ++ ++ elec num=1 x.l=0.0 x.h=0.0 y.l=1.1 y.h=1.3 ++ elec num=2 x.l=0.0 x.h=0.5 y.l=0.0 y.h=0.0 ++ elec num=3 x.l=2.0 x.h=3.0 y.l=-0.2 y.h=-0.2 ++ ++ doping gauss n.type conc=3e20 x.l=2.0 x.h=3.0 y.l=-0.2 y.h=0.0 ++ + char.l=0.047 lat.rotate ++ doping gauss p.type conc=5e18 x.l=0.0 x.h=5.0 y.l=-0.2 y.h=0.0 ++ + char.l=0.100 lat.rotate ++ doping gauss p.type conc=1e20 x.l=0.0 x.h=0.5 y.l=-0.2 y.h=0.0 ++ + char.l=0.100 lat.rotate ratio=0.7 ++ doping unif n.type conc=1e16 x.l=0.0 x.h=5.0 y.l=0.0 y.h=1.3 ++ doping gauss n.type conc=5e19 x.l=0.0 x.h=5.0 y.l=1.3 y.h=1.3 ++ + char.l=0.100 lat.rotate ++ ++ method ac=direct itlim=10 ++ models bgn srh auger conctau concmob fieldmob + +.MODEL M_PMOS_1 numos ++ ++ x.mesh w=0.9 h.e=0.020 h.m=0.2 r=2.0 ++ x.mesh w=0.2 h.e=0.005 h.m=0.02 r=2.0 ++ x.mesh w=0.4 h.s=0.005 h.m=0.1 r=2.0 ++ x.mesh w=0.4 h.e=0.005 h.m=0.1 r=2.0 ++ x.mesh w=0.2 h.e=0.005 h.m=0.02 r=2.0 ++ x.mesh w=0.9 h.s=0.020 h.m=0.2 r=2.0 ++ ++ y.mesh l=-.0200 n=1 ++ y.mesh l=0.0 n=6 ++ y.mesh w=0.15 h.s=0.0001 h.max=.02 r=2.0 ++ y.mesh w=0.45 h.s=0.02 h.max=0.2 r=2.0 ++ y.mesh w=1.40 h.s=0.20 h.max=0.4 r=2.0 ++ ++ region num=1 material=1 y.h=0.0 ++ region num=2 material=2 y.l=0.0 ++ interface dom=2 nei=1 x.l=1 x.h=2 layer.width=0.0 ++ material num=1 oxide ++ material num=2 silicon ++ ++ elec num=1 x.l=2.5 x.h=3.1 y.l=0.0 y.h=0.0 ++ elec num=2 x.l=1 x.h=2 iy.l=1 iy.h=1 ++ elec num=3 x.l=-0.1 x.h=0.5 y.l=0.0 y.h=0.0 ++ elec num=4 x.l=-0.1 x.h=3.1 y.l=2.0 y.h=2.0 ++ ++ doping gauss n.type conc=1.0e17 x.l=-0.1 x.h=3.1 y.l=0.0 ++ + char.l=0.30 ++ doping unif n.type conc=5.0e15 x.l=-0.1 x.h=3.1 y.l=0.0 y.h=2.1 ++ doping gauss p.type conc=4e17 x.l=-0.1 x.h=1 y.l=0.0 y.h=0.0 ++ + char.l=0.16 lat.rotate ratio=0.65 ++ doping gauss p.type conc=1e20 x.l=-0.1 x.h=0.95 y.l=0.0 y.h=0.08 ++ + char.l=0.03 lat.rotate ratio=0.65 ++ doping gauss p.type conc=4e17 x.l=2 x.h=3.1 y.l=0.0 y.h=0.0 ++ + char.l=0.16 lat.rotate ratio=0.65 ++ doping gauss p.type conc=1e20 x.l=2.05 x.h=3.1 y.l=0.0 y.h=0.08 ++ + char.l=0.03 lat.rotate ratio=0.65 ++ ++ contact num=2 workf=5.29 ++ models concmob surfmob transmob fieldmob srh auger conctau bgn ++ method ac=direct itlim=10 onec + + +.TRAN 0.5NS 3.0NS +.PRINT TRAN V(3) V(4) +.PLOT TRAN V(3) V(4) + +* .OPTION ACCT BYPASS=1 +.END diff --git a/examples/cider/surfmob/Tbicmpu1xy.cir b/examples/cider/surfmob/Tbicmpu1xy.cir new file mode 100644 index 000000000..229ea31db --- /dev/null +++ b/examples/cider/surfmob/Tbicmpu1xy.cir @@ -0,0 +1,105 @@ +BICMOS INVERTER PULLUP CIRCUIT + +VDD 1 0 5.0V +VSS 2 0 0.0V + +VIN 3 0 0.75V + +VC 1 11 0.0V +VB 5 15 0.0V + +Q1 11 15 4 M_NPNS AREA=8 +M1 5 3 1 1 M_PMOS_1 W=10U L=1U + +CL 4 0 5.0PF + +.IC V(4)=0.75V V(5)=0.0V + +.MODEL M_NPNS nbjt level=2 ++ title TWO-DIMENSIONAL NUMERICAL POLYSILICON EMITTER BIPOLAR TRANSISTOR ++ * Since half the device is simulated, double the unit width to get ++ * 1.0 um emitter. Use a small mesh for this model. ++ options defw=2.0u ++ ++ x.mesh w=2.0 h.e=0.02 h.m=0.5 r=2.0 ++ x.mesh w=0.5 h.s=0.02 h.m=0.2 r=2.0 ++ ++ y.mesh l=-0.2 n=1 ++ y.mesh l= 0.0 n=5 ++ y.mesh w=0.10 h.e=0.004 h.m=0.05 r=2.5 ++ y.mesh w=0.15 h.s=0.004 h.m=0.02 r=2.5 ++ y.mesh w=1.05 h.s=0.02 h.m=0.1 r=2.5 ++ ++ domain num=1 material=1 x.l=2.0 y.h=0.0 ++ domain num=2 material=2 x.h=2.0 y.h=0.0 ++ domain num=3 material=3 y.l=0.0 ++ material num=1 polysilicon ++ material num=2 oxide ++ material num=3 silicon ++ ++ elec num=1 x.l=0.0 x.h=0.0 y.l=1.1 y.h=1.3 ++ elec num=2 x.l=0.0 x.h=0.5 y.l=0.0 y.h=0.0 ++ elec num=3 x.l=2.0 x.h=3.0 y.l=-0.2 y.h=-0.2 ++ ++ doping gauss n.type conc=3e20 x.l=2.0 x.h=3.0 y.l=-0.2 y.h=0.0 ++ + char.l=0.047 lat.rotate ++ doping gauss p.type conc=5e18 x.l=0.0 x.h=5.0 y.l=-0.2 y.h=0.0 ++ + char.l=0.100 lat.rotate ++ doping gauss p.type conc=1e20 x.l=0.0 x.h=0.5 y.l=-0.2 y.h=0.0 ++ + char.l=0.100 lat.rotate ratio=0.7 ++ doping unif n.type conc=1e16 x.l=0.0 x.h=5.0 y.l=0.0 y.h=1.3 ++ doping gauss n.type conc=5e19 x.l=0.0 x.h=5.0 y.l=1.3 y.h=1.3 ++ + char.l=0.100 lat.rotate ++ ++ method ac=direct itlim=10 ++ models bgn srh auger conctau concmob fieldmob + +.MODEL M_PMOS_1 numos ++ ++ y.mesh w=0.9 h.e=0.020 h.m=0.2 r=2.0 ++ y.mesh w=0.2 h.e=0.005 h.m=0.02 r=2.0 ++ y.mesh w=0.4 h.s=0.005 h.m=0.1 r=2.0 ++ y.mesh w=0.4 h.e=0.005 h.m=0.1 r=2.0 ++ y.mesh w=0.2 h.e=0.005 h.m=0.02 r=2.0 ++ y.mesh w=0.9 h.s=0.020 h.m=0.2 r=2.0 ++ ++ x.mesh l=-.0200 n=1 ++ x.mesh l=0.0 n=6 ++ x.mesh w=0.15 h.s=0.0001 h.max=.02 r=2.0 ++ x.mesh w=0.45 h.s=0.02 h.max=0.2 r=2.0 ++ x.mesh w=1.40 h.s=0.20 h.max=0.4 r=2.0 ++ ++ region num=1 material=1 x.h=0.0 ++ region num=2 material=2 x.l=0.0 ++ interface dom=2 nei=1 y.l=1 y.h=2 layer.width=0.0 ++ material num=1 oxide ++ material num=2 silicon ++ ++ elec num=1 y.l=2.5 y.h=3.1 x.l=0.0 x.h=0.0 ++ elec num=2 y.l=1 y.h=2 ix.l=1 ix.h=1 ++ elec num=3 y.l=-0.1 y.h=0.5 x.l=0.0 x.h=0.0 ++ elec num=4 y.l=-0.1 y.h=3.1 x.l=2.0 x.h=2.0 ++ ++ doping gauss n.type conc=1.0e17 y.l=-0.1 y.h=3.1 x.l=0.0 ++ + char.l=0.30 ++ doping unif n.type conc=5.0e15 y.l=-0.1 y.h=3.1 x.l=0.0 x.h=2.1 ++ doping gauss p.type conc=4e17 y.l=-0.1 y.h=1 x.l=0.0 x.h=0.0 ++ + char.l=0.16 lat.rotate ratio=0.65 ++ doping gauss p.type conc=1e20 y.l=-0.1 y.h=0.95 x.l=0.0 x.h=0.08 ++ + char.l=0.03 lat.rotate ratio=0.65 ++ doping gauss p.type conc=4e17 y.l=2 y.h=3.1 x.l=0.0 x.h=0.0 ++ + char.l=0.16 lat.rotate ratio=0.65 ++ doping gauss p.type conc=1e20 y.l=2.05 y.h=3.1 x.l=0.0 x.h=0.08 ++ + char.l=0.03 lat.rotate ratio=0.65 ++ ++ contact num=2 workf=5.29 ++ models concmob surfmob transmob fieldmob srh auger conctau bgn ++ method ac=direct itlim=10 onec + + +.TRAN 0.5NS 3.0NS +.PRINT TRAN V(3) V(4) +.PLOT TRAN V(3) V(4) + +* .OPTION ACCT BYPASS=1 +.END diff --git a/examples/cider/surfmob/cd4007n_200402idvg.net b/examples/cider/surfmob/cd4007n_200402idvg.net new file mode 100644 index 000000000..6d8c45e1a --- /dev/null +++ b/examples/cider/surfmob/cd4007n_200402idvg.net @@ -0,0 +1,159 @@ +$ CD4007, version: cd4007n_200402idvg +$ Generated using Matlab automation script. + + +$ BEGIN CIDER + +.model CD4007UBENUMOSN numos +$ -- x Grid +$ ---- GOX ++ x.mesh (location = -64.0000e-3) (node = 1) ++ x.mesh (location = -48.0000e-3) (node = 2) ++ x.mesh (location = -32.0000e-3) (node = 3) ++ x.mesh (location = -16.0000e-3) (node = 4) ++ x.mesh (location = 0.0000e-3) (node = 5) +$ ---- Channel and S/D ++ x.mesh (location = 20.0000e-3) (node = 6) ++ x.mesh (location = 48.4511e-3) (node = 7) ++ x.mesh (location = 86.9893e-3) (node = 8) ++ x.mesh (location = 139.1911e-3) (node = 9) ++ x.mesh (location = 209.9008e-3) (node = 10) ++ x.mesh (location = 305.6803e-3) (node = 11) ++ x.mesh (location = 435.4180e-3) (node = 12) ++ x.mesh (location = 611.1537e-3) (node = 13) ++ x.mesh (location = 849.1956e-3) (node = 14) ++ x.mesh (location = 1171.6341e-3) (node = 15) ++ x.mesh (location = 1608.3918e-3) (node = 16) ++ x.mesh (location = 2200.0000e-3) (node = 17) ++ x.mesh (location = 3000.0000e-3) (node = 18) +$ ---- Mid substrate ++ x.mesh (location = 3800.0000e-3) (node = 19) ++ x.mesh (location = 4911.8170e-3) (node = 20) ++ x.mesh (location = 6290.4701e-3) (node = 21) ++ x.mesh (location = 8000.0000e-3) (node = 22) ++ x.mesh (location = 10000.0000e-3) (node = 23) ++ +$ -- y Grid +$ ---- Body well ++ y.mesh (location = -35000.0000e-3) (node = 1) ++ y.mesh (location = -30000.0000e-3) (node = 2) ++ y.mesh (location = -25000.0000e-3) (node = 3) ++ y.mesh (location = -20000.0000e-3) (node = 4) +$ ---- Body-Source ++ y.mesh (location = -17500.0000e-3) (node = 5) ++ y.mesh (location = -15000.0000e-3) (node = 6) ++ y.mesh (location = -12500.0000e-3) (node = 7) ++ y.mesh (location = -10000.0000e-3) (node = 8) +$ ---- Mid source ++ y.mesh (location = -7500.0000e-3) (node = 9) ++ y.mesh (location = -4980.0000e-3) (node = 10) ++ y.mesh (location = -3000.0000e-3) (node = 11) ++ y.mesh (location = -2000.0000e-3) (node = 12) +$ ---- Near source ++ y.mesh (location = -1000.0000e-3) (node = 13) ++ y.mesh (location = -200.0000e-3) (node = 14) ++ y.mesh (location = 0.0000e-3) (node = 15) +$ ---- Channel near source ++ y.mesh (location = 200.0000e-3) (node = 16) ++ y.mesh (location = 442.1759e-3) (node = 17) ++ y.mesh (location = 732.7869e-3) (node = 18) ++ y.mesh (location = 1081.5201e-3) (node = 19) ++ y.mesh (location = 1500.0000e-3) (node = 20) ++ y.mesh (location = 2000.0000e-3) (node = 21) +$ ---- Channel center ++ y.mesh (location = 2500.0000e-3) (node = 22) ++ y.mesh (location = 3000.0000e-3) (node = 23) ++ y.mesh (location = 3500.0000e-3) (node = 24) ++ y.mesh (location = 4000.0000e-3) (node = 25) ++ y.mesh (location = 4500.0000e-3) (node = 26) ++ y.mesh (location = 5000.0000e-3) (node = 27) +$ ---- Channel near drain ++ y.mesh (location = 5500.0000e-3) (node = 28) ++ y.mesh (location = 5961.8362e-3) (node = 29) ++ y.mesh (location = 6376.3046e-3) (node = 30) ++ y.mesh (location = 6748.2634e-3) (node = 31) ++ y.mesh (location = 7082.0725e-3) (node = 32) ++ y.mesh (location = 7381.6449e-3) (node = 33) ++ y.mesh (location = 7650.4919e-3) (node = 34) ++ y.mesh (location = 7891.7648e-3) (node = 35) ++ y.mesh (location = 8108.2918e-3) (node = 36) ++ y.mesh (location = 8302.6109e-3) (node = 37) ++ y.mesh (location = 8476.9998e-3) (node = 38) ++ y.mesh (location = 8633.5027e-3) (node = 39) ++ y.mesh (location = 8773.9540e-3) (node = 40) ++ y.mesh (location = 8900.0000e-3) (node = 41) ++ y.mesh (location = 9000.0000e-3) (node = 42) +$ ---- Near drain ++ y.mesh (location = 9200.0000e-3) (node = 43) ++ y.mesh (location = 9612.8440e-3) (node = 44) ++ y.mesh (location = 10190.8257e-3) (node = 45) ++ y.mesh (location = 11000.0000e-3) (node = 46) ++ y.mesh (location = 12000.0000e-3) (node = 47) +$ ---- Mid drain ++ y.mesh (location = 13000.0000e-3) (node = 48) ++ y.mesh (location = 15500.0000e-3) (node = 49) ++ y.mesh (location = 18000.0000e-3) (node = 50) ++ +$ -- Regions +$ ---- substrate ++ region (num=1 material=1) x.l = 0.0000e-3 +$ ---- GOX ++ region (num=2 material=2) x.h = 0.0000e-3 ++ +$ -- Materials ++ material num=1 silicon ++ mobility material=1 concmod=sg fieldmod=sg ++ Mobility Material=1 elec major MuMax=1200.0 MuMin=200.0 Vsat=3.2e7 ++ Mobility Material=1 elec MuS=600.0 EC.A=3.0e5 ++ mobility material=1 elec minor MuMax=1200.0 MuMin=200.0 ++ mobility material=1 hole major ++ mobility material=1 hole minor ++ material num=2 oxide ++ +$ -- Contacts and workfunction +$ ---- Drain ++ elec num=1 (x.l = 0.0000e-3 x.h = 0.0000e-3) (y.l = 12000.0000e-3 y.h = 16000.0000e-3) +$ ---- Gate contact ++ elec num=2 (x.l = -64.0000e-3 x.h = -64.0000e-3) (y.l = 0.0000e-3 y.h = 9000.0000e-3) +$ ---- Source ++ elec num=3 (x.l = 0.0000e-3 x.h = 0.0000e-3) (y.l = -6000.0000e-3 y.h = -3000.0000e-3) +$ ---- Body ++ elec num=4 (x.l = 0.0000e-3 x.h = 0.0000e-3) (y.l = -30000.0000e-3 y.h = -25000.0000e-3) ++ contact num=1 workf=4.0500 ++ contact num=2 workf=4.0500 ++ contact num=3 workf=4.0500 ++ contact num=4 workf=5.1700 ++ +$ -- Doping profiles +$ ---- p subs ++ doping Domains = 1 Uniform P.Type Conc = 1e16 +$ ---- Threshold Adjustment Diffuse ++ doping Domains = 1 Gaussian Lat.Erfc X.Axis P.Type x.l=0.0 x.h=0.5 y.l=-0 y.h=10 Peak.Conc=2e16 Location=0.1 Char.Length=0.8 Ratio.Lat=0.8 +$ ---- Body Diffuse ++ doping Domains = 1 Gaussian Lat.Erfc X.Axis P.Type x.l=0.0 x.h=3.0 y.l=-30 y.h=-20 Peak.Conc=2e20 Location=0 Char.Length=0.6 Ratio.Lat=0.8 +$ ---- Source Diffuse ++ doping Domains = 1 Gaussian Lat.Erfc X.Axis N.Type x.l=0.0 x.h=3.0 y.l=-10 y.h=0 Peak.Conc=2e20 Location=0 Char.Length=0.6 Ratio.Lat=0.8 +$ ---- Drain Diffuse ++ doping Domains = 1 Gaussian Lat.Erfc X.Axis N.Type x.l=0.0 x.h=3.0 y.l=9.0 y.h=18.0 Peak.Conc=2e20 Location=0 Char.Length=0.6 Ratio.Lat=0.8 ++ ++ models concmob fieldmob ++ method ac=direct ^onec ++ ++ interface domain=1 neighbor=2 y.l=0 y.h=8.0 layer.width=0.5 ++ models surfmob transmob ^matchmob + +$ Total grid points X23 x Y50 = 1150 + +$ END OF CIDER + + +$ PSPICE Schematics Netlist +VId VPP VDD 0 +MN1 VDD VGG 0 0 CD4007UBENUMOSN w=298u +* .save i(VId) * +VVDS VPP 0 DC 0 +VVGS VGG 0 DC 0 +.dc VVGS 0.00 5.00 0.25 VVDS 0.05 0.05 0.50 +$ VGS x VDS sweep points: 51 x 1 = 51 +.print dc VPP VGG VPP +.end diff --git a/examples/cider/surfmob/cdxy.net b/examples/cider/surfmob/cdxy.net new file mode 100644 index 000000000..f420c0c80 --- /dev/null +++ b/examples/cider/surfmob/cdxy.net @@ -0,0 +1,159 @@ +$ CD4007, version: cd4007n_200402idvg +$ Generated using Matlab automation script. + + +$ BEGIN CIDER + +.model CD4007UBENUMOSN numos +$ -- y Grid +$ ---- GOX ++ y.mesh (location = -64.0000e-3) (node = 1) ++ y.mesh (location = -48.0000e-3) (node = 2) ++ y.mesh (location = -32.0000e-3) (node = 3) ++ y.mesh (location = -16.0000e-3) (node = 4) ++ y.mesh (location = 0.0000e-3) (node = 5) +$ ---- Channel and S/D ++ y.mesh (location = 20.0000e-3) (node = 6) ++ y.mesh (location = 48.4511e-3) (node = 7) ++ y.mesh (location = 86.9893e-3) (node = 8) ++ y.mesh (location = 139.1911e-3) (node = 9) ++ y.mesh (location = 209.9008e-3) (node = 10) ++ y.mesh (location = 305.6803e-3) (node = 11) ++ y.mesh (location = 435.4180e-3) (node = 12) ++ y.mesh (location = 611.1537e-3) (node = 13) ++ y.mesh (location = 849.1956e-3) (node = 14) ++ y.mesh (location = 1171.6341e-3) (node = 15) ++ y.mesh (location = 1608.3918e-3) (node = 16) ++ y.mesh (location = 2200.0000e-3) (node = 17) ++ y.mesh (location = 3000.0000e-3) (node = 18) +$ ---- Mid substrate ++ y.mesh (location = 3800.0000e-3) (node = 19) ++ y.mesh (location = 4911.8170e-3) (node = 20) ++ y.mesh (location = 6290.4701e-3) (node = 21) ++ y.mesh (location = 8000.0000e-3) (node = 22) ++ y.mesh (location = 10000.0000e-3) (node = 23) ++ +$ -- x Grid +$ ---- Body well ++ x.mesh (location = -35000.0000e-3) (node = 1) ++ x.mesh (location = -30000.0000e-3) (node = 2) ++ x.mesh (location = -25000.0000e-3) (node = 3) ++ x.mesh (location = -20000.0000e-3) (node = 4) +$ ---- Body-Source ++ x.mesh (location = -17500.0000e-3) (node = 5) ++ x.mesh (location = -15000.0000e-3) (node = 6) ++ x.mesh (location = -12500.0000e-3) (node = 7) ++ x.mesh (location = -10000.0000e-3) (node = 8) +$ ---- Mid source ++ x.mesh (location = -7500.0000e-3) (node = 9) ++ x.mesh (location = -4980.0000e-3) (node = 10) ++ x.mesh (location = -3000.0000e-3) (node = 11) ++ x.mesh (location = -2000.0000e-3) (node = 12) +$ ---- Near source ++ x.mesh (location = -1000.0000e-3) (node = 13) ++ x.mesh (location = -200.0000e-3) (node = 14) ++ x.mesh (location = 0.0000e-3) (node = 15) +$ ---- Channel near source ++ x.mesh (location = 200.0000e-3) (node = 16) ++ x.mesh (location = 442.1759e-3) (node = 17) ++ x.mesh (location = 732.7869e-3) (node = 18) ++ x.mesh (location = 1081.5201e-3) (node = 19) ++ x.mesh (location = 1500.0000e-3) (node = 20) ++ x.mesh (location = 2000.0000e-3) (node = 21) +$ ---- Channel center ++ x.mesh (location = 2500.0000e-3) (node = 22) ++ x.mesh (location = 3000.0000e-3) (node = 23) ++ x.mesh (location = 3500.0000e-3) (node = 24) ++ x.mesh (location = 4000.0000e-3) (node = 25) ++ x.mesh (location = 4500.0000e-3) (node = 26) ++ x.mesh (location = 5000.0000e-3) (node = 27) +$ ---- Channel near drain ++ x.mesh (location = 5500.0000e-3) (node = 28) ++ x.mesh (location = 5961.8362e-3) (node = 29) ++ x.mesh (location = 6376.3046e-3) (node = 30) ++ x.mesh (location = 6748.2634e-3) (node = 31) ++ x.mesh (location = 7082.0725e-3) (node = 32) ++ x.mesh (location = 7381.6449e-3) (node = 33) ++ x.mesh (location = 7650.4919e-3) (node = 34) ++ x.mesh (location = 7891.7648e-3) (node = 35) ++ x.mesh (location = 8108.2918e-3) (node = 36) ++ x.mesh (location = 8302.6109e-3) (node = 37) ++ x.mesh (location = 8476.9998e-3) (node = 38) ++ x.mesh (location = 8633.5027e-3) (node = 39) ++ x.mesh (location = 8773.9540e-3) (node = 40) ++ x.mesh (location = 8900.0000e-3) (node = 41) ++ x.mesh (location = 9000.0000e-3) (node = 42) +$ ---- Near drain ++ x.mesh (location = 9200.0000e-3) (node = 43) ++ x.mesh (location = 9612.8440e-3) (node = 44) ++ x.mesh (location = 10190.8257e-3) (node = 45) ++ x.mesh (location = 11000.0000e-3) (node = 46) ++ x.mesh (location = 12000.0000e-3) (node = 47) +$ ---- Mid drain ++ x.mesh (location = 13000.0000e-3) (node = 48) ++ x.mesh (location = 15500.0000e-3) (node = 49) ++ x.mesh (location = 18000.0000e-3) (node = 50) ++ +$ -- Regions +$ ---- substrate ++ region (num=1 material=1) y.l = 0.0000e-3 +$ ---- GOX ++ region (num=2 material=2) y.h = 0.0000e-3 ++ +$ -- Materials ++ material num=1 silicon ++ mobility material=1 concmod=sg fieldmod=sg ++ Mobility Material=1 elec major MuMax=1200.0 MuMin=200.0 Vsat=3.2e7 ++ Mobility Material=1 elec MuS=600.0 EC.A=3.0e5 ++ mobility material=1 elec minor MuMax=1200.0 MuMin=200.0 ++ mobility material=1 hole major ++ mobility material=1 hole minor ++ material num=2 oxide ++ +$ -- Contacts and workfunction +$ ---- Drain ++ elec num=1 (y.l = 0.0000e-3 y.h = 0.0000e-3) (x.l = 12000.0000e-3 x.h = 16000.0000e-3) +$ ---- Gate contact ++ elec num=2 (y.l = -64.0000e-3 y.h = -64.0000e-3) (x.l = 0.0000e-3 x.h = 9000.0000e-3) +$ ---- Source ++ elec num=3 (y.l = 0.0000e-3 y.h = 0.0000e-3) (x.l = -6000.0000e-3 x.h = -3000.0000e-3) +$ ---- Body ++ elec num=4 (y.l = 0.0000e-3 y.h = 0.0000e-3) (x.l = -30000.0000e-3 x.h = -25000.0000e-3) ++ contact num=1 workf=4.0500 ++ contact num=2 workf=4.0500 ++ contact num=3 workf=4.0500 ++ contact num=4 workf=5.1700 ++ +$ -- Doping profiles +$ ---- p subs ++ doping Domains = 1 Uniform P.Type Conc = 1e16 +$ ---- Threshold Adjustment Diffuse ++ doping Domains = 1 Gaussian Lat.Erfc Y.Axis P.Type y.l=0.0 y.h=0.5 x.l=-0 x.h=10 Peak.Conc=2e16 Location=0.1 Char.Length=0.8 Ratio.Lat=0.8 +$ ---- Body Diffuse ++ doping Domains = 1 Gaussian Lat.Erfc Y.Axis P.Type y.l=0.0 y.h=3.0 x.l=-30 x.h=-20 Peak.Conc=2e20 Location=0 Char.Length=0.6 Ratio.Lat=0.8 +$ ---- Source Diffuse ++ doping Domains = 1 Gaussian Lat.Erfc Y.Axis N.Type y.l=0.0 y.h=3.0 x.l=-10 x.h=0 Peak.Conc=2e20 Location=0 Char.Length=0.6 Ratio.Lat=0.8 +$ ---- Drain Diffuse ++ doping Domains = 1 Gaussian Lat.Erfc Y.Axis N.Type y.l=0.0 y.h=3.0 x.l=9.0 x.h=18.0 Peak.Conc=2e20 Location=0 Char.Length=0.6 Ratio.Lat=0.8 ++ ++ models concmob fieldmob ++ method ac=direct ^onec ++ ++ interface domain=1 neighbor=2 x.l=0 x.h=8.0 layer.width=0.5 ++ models surfmob transmob ^matchmob + +$ Total grid points X23 x Y50 = 1150 + +$ END OF CIDER + + +$ PSPICE Schematics Netlist +VId VPP VDD 0 +MN1 VDD VGG 0 0 CD4007UBENUMOSN w=298u +* .save i(VId) * +VVDS VPP 0 DC 0 +VVGS VGG 0 DC 0 +.dc VVGS 0.00 5.00 0.25 VVDS 0.05 0.05 0.50 +$ VGS x VDS sweep points: 51 x 1 = 51 +.print dc VPP VGG VPP +.end diff --git a/examples/cider/surfmob/runtests.sh b/examples/cider/surfmob/runtests.sh new file mode 100755 index 000000000..b137641c7 --- /dev/null +++ b/examples/cider/surfmob/runtests.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -xv + +ngspice -b cd4007n_200402idvg.net +ngspice -b cdxy.net +ngspice -b Tbicmpd1.cir +ngspice -b Tbicmpd1xy.cir +ngspice -b Tbicmpu1.cir +ngspice -b Tbicmpu1xy.cir diff --git a/examples/cider/surfmob/spiceinit b/examples/cider/surfmob/spiceinit new file mode 100644 index 000000000..d08d85362 --- /dev/null +++ b/examples/cider/surfmob/spiceinit @@ -0,0 +1,2 @@ +option klu +set numdgt=3 diff --git a/src/ciderlib/oned/oneadmit.c b/src/ciderlib/oned/oneadmit.c index 686e96a98..38c251003 100644 --- a/src/ciderlib/oned/oneadmit.c +++ b/src/ciderlib/oned/oneadmit.c @@ -14,6 +14,8 @@ Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group #include "ngspice/complex.h" #include "ngspice/spmatrix.h" #include "ngspice/ifsim.h" +#include "ngspice/cktdefs.h" +#include "ngspice/ftedefs.h" #include "onedext.h" #include "oneddefs.h" @@ -29,7 +31,17 @@ extern IFfrontEnd *SPfrontEnd; */ SPcomplex yAc; - +#ifdef KLU +static void small_signal_check(char *where) +{ + if (ft_curckt->ci_ckt->CKTmode == MODEAC + || ft_curckt->ci_ckt->CKTmode == MODEACNOISE) { + fprintf(stderr, "Error: CIDER %s small signal simulation is not (yet) supported with 'option klu'.\n", where); + fprintf(stderr, " Use 'option sparse' instead.\n"); + controlled_exit(1); + } +} +#endif int NUMDadmittance(ONEdevice *pDevice, double omega, SPcomplex *yd) @@ -45,6 +57,11 @@ NUMDadmittance(ONEdevice *pDevice, double omega, SPcomplex *yd) bool SORFailed; double startTime; +#ifdef KLU + if (pDevice->matrix->CKTkluMODE) { + small_signal_check("NUMDadmittance"); + } +#endif /* Each time we call this counts as one AC iteration. */ pDevice->pStats->numIters[STAT_AC] += 1; @@ -119,6 +136,7 @@ NUMDadmittance(ONEdevice *pDevice, double omega, SPcomplex *yd) #ifdef KLU if (pDevice->matrix->CKTkluMODE) { + // Not implemented pDevice->matrix->SMPkluMatrix->KLUmatrixIsComplex = KLUMatrixComplex ; } else { #endif @@ -196,6 +214,11 @@ NBJTadmittance(ONEdevice *pDevice, double omega, SPcomplex *yIeVce, SPcomplex cOmega, pIeVce, pIcVce, pIeVbe, pIcVbe; double startTime; +#ifdef KLU + if (pDevice->matrix->CKTkluMODE) { + small_signal_check("NBJTadmittance"); + } +#endif /* Each time we call this counts as one AC iteration. */ pDevice->pStats->numIters[STAT_AC] += 1; @@ -315,6 +338,7 @@ NBJTadmittance(ONEdevice *pDevice, double omega, SPcomplex *yIeVce, #ifdef KLU if (pDevice->matrix->CKTkluMODE) { + // Not implemented pDevice->matrix->SMPkluMatrix->KLUmatrixIsComplex = KLUMatrixComplex ; } else { #endif @@ -552,6 +576,11 @@ NUMDys(ONEdevice *pDevice, SPcomplex *s, SPcomplex *yd) SPcomplex *y; +#ifdef KLU + if (pDevice->matrix->CKTkluMODE) { + small_signal_check("NUMDys"); + } +#endif /* * change context names of solution vectors for ac analysis dcDeltaSolution * stores the real part and copiedSolution stores the imaginary part of the @@ -580,6 +609,7 @@ NUMDys(ONEdevice *pDevice, SPcomplex *s, SPcomplex *yd) #ifdef KLU if (pDevice->matrix->CKTkluMODE) { + // Not implemented pDevice->matrix->SMPkluMatrix->KLUmatrixIsComplex = KLUMatrixComplex ; } else { #endif @@ -640,6 +670,11 @@ NBJTys(ONEdevice *pDevice, SPcomplex *s, SPcomplex *yIeVce, SPcomplex temp, cOmega; SPcomplex pIeVce, pIcVce, pIeVbe, pIcVbe; +#ifdef KLU + if (pDevice->matrix->CKTkluMODE) { + small_signal_check("NBJTys"); + } +#endif /* * change context names of solution vectors for ac analysis dcDeltaSolution * stores the real part and copiedSolution stores the imaginary part of the @@ -667,6 +702,7 @@ NBJTys(ONEdevice *pDevice, SPcomplex *s, SPcomplex *yIeVce, #ifdef KLU if (pDevice->matrix->CKTkluMODE) { + // Not implemented pDevice->matrix->SMPkluMatrix->KLUmatrixIsComplex = KLUMatrixComplex ; } else { #endif diff --git a/src/ciderlib/twod/twoadmit.c b/src/ciderlib/twod/twoadmit.c index 8f3a4e1b5..787c10805 100644 --- a/src/ciderlib/twod/twoadmit.c +++ b/src/ciderlib/twod/twoadmit.c @@ -16,6 +16,9 @@ Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group #include "ngspice/bool.h" #include "ngspice/macros.h" #include "ngspice/ifsim.h" +#include "ngspice/cktdefs.h" +#include "ngspice/ftedefs.h" + #include "twoddefs.h" #include "twodext.h" #include "ngspice/cidersupt.h" @@ -28,6 +31,18 @@ extern IFfrontEnd *SPfrontEnd; */ SPcomplex yTotal; +#ifdef KLU +static void small_signal_check(char *where) +{ + if (ft_curckt->ci_ckt->CKTmode == MODEAC + || ft_curckt->ci_ckt->CKTmode == MODEACNOISE) { + fprintf(stderr, "Error: CIDER %s small signal simulation is not (yet) supported with 'option klu'.\n", where); + fprintf(stderr, " Use 'option sparse' instead.\n"); + controlled_exit(1); + } +} +#endif + int NUMD2admittance(TWOdevice *pDevice, double omega, SPcomplex *yd) { @@ -42,6 +57,11 @@ NUMD2admittance(TWOdevice *pDevice, double omega, SPcomplex *yd) bool SORFailed; double startTime; +#ifdef KLU + if (pDevice->matrix->CKTkluMODE) { + small_signal_check("NUMD2admittance"); + } +#endif /* Each time we call this counts as one AC iteration. */ pDevice->pStats->numIters[STAT_AC] += 1; @@ -192,6 +212,11 @@ NBJT2admittance(TWOdevice *pDevice, double omega, SPcomplex *yIeVce, SPcomplex cOmega; double startTime; +#ifdef KLU + if (pDevice->matrix->CKTkluMODE) { + small_signal_check("NBJT2admittance"); + } +#endif /* Each time we call this counts as one AC iteration. */ pDevice->pStats->numIters[STAT_AC] += 1; @@ -416,6 +441,11 @@ NUMOSadmittance(TWOdevice *pDevice, double omega, struct mosAdmittances *yAc) SPcomplex *y, cOmega; double startTime; +#ifdef KLU + if (pDevice->matrix->CKTkluMODE) { + small_signal_check("NUMOSadmittance"); + } +#endif /* Each time we call this counts as one AC iteration. */ pDevice->pStats->numIters[STAT_AC] += 1; @@ -1151,6 +1181,11 @@ NUMD2ys(TWOdevice *pDevice, SPcomplex *s, SPcomplex *yIn) bool deltaVContact = FALSE; SPcomplex temp, cOmega; +#ifdef KLU + if (pDevice->matrix->CKTkluMODE) { + small_signal_check("NUMD2ys"); + } +#endif /* * change context names of solution vectors for ac analysis dcDeltaSolution * stores the real part and copiedSolution stores the imaginary part of the @@ -1252,6 +1287,11 @@ NBJT2ys(TWOdevice *pDevice, SPcomplex *s, SPcomplex *yIeVce, SPcomplex *yIcVce, SPcomplex pIeVce, pIcVce, pIeVbe, pIcVbe; SPcomplex temp, cOmega; +#ifdef KLU + if (pDevice->matrix->CKTkluMODE) { + small_signal_check("NBJT2ys"); + } +#endif pDevice->solverType = SLV_SMSIG; rhsReal = pDevice->rhs; rhsImag = pDevice->rhsImag; @@ -1375,6 +1415,11 @@ NUMOSys(TWOdevice *pDevice, SPcomplex *s, struct mosAdmittances *yAc) SPcomplex *y; SPcomplex temp, cOmega; +#ifdef KLU + if (pDevice->matrix->CKTkluMODE) { + small_signal_check("NUMOSys"); + } +#endif pDevice->solverType = SLV_SMSIG; rhsReal = pDevice->rhs; rhsImag = pDevice->rhsImag; diff --git a/src/ciderlib/twod/twocont.c b/src/ciderlib/twod/twocont.c index 4e79d8415..1fce53439 100644 --- a/src/ciderlib/twod/twocont.c +++ b/src/ciderlib/twod/twocont.c @@ -1149,7 +1149,8 @@ TWObindCSC (TWOdevice *pDevice) } } else { /* Horizontal Slice */ - if ( nIndex <= 1 ) { /* Top Side */ + //if ( nIndex <= 1 ) { /* Top Side */ + if ( nIndex == 0 || nIndex == 3 ) { /* Left (Top?) Side : bug 483 */ CREATE_KLU_BINDING_TABLE_CIDER(fNPsiIn, fNPsiInBinding, nEqn, psiEqnInM) ; CREATE_KLU_BINDING_TABLE_CIDER(fNPsiInP1, fNPsiInP1Binding, nEqn, psiEqnInP) ; diff --git a/src/ciderlib/twod/twoncont.c b/src/ciderlib/twod/twoncont.c index 194339dfe..58c984d00 100644 --- a/src/ciderlib/twod/twoncont.c +++ b/src/ciderlib/twod/twoncont.c @@ -786,7 +786,8 @@ TWONbindCSC (TWOdevice *pDevice) } } else { /* Horizontal Slice */ - if ( nIndex <= 1 ) { /* Top Side */ + //if ( nIndex <= 1 ) { /* Top Side */ + if ( nIndex == 0 || nIndex == 3 ) { /* Left (Top?) Side : bug 483 */ CREATE_KLU_BINDING_TABLE_CIDER(fNPsiIn, fNPsiInBinding, nEqn, psiEqnInM) ; CREATE_KLU_BINDING_TABLE_CIDER(fNPsiInP1, fNPsiInP1Binding, nEqn, psiEqnInP) ; diff --git a/src/ciderlib/twod/twopcont.c b/src/ciderlib/twod/twopcont.c index a3b1e6dd5..41e8811f8 100644 --- a/src/ciderlib/twod/twopcont.c +++ b/src/ciderlib/twod/twopcont.c @@ -786,7 +786,8 @@ TWOPbindCSC (TWOdevice *pDevice) } } else { /* Horizontal Slice */ - if ( nIndex <= 1 ) { /* Top Side */ + //if ( nIndex <= 1 ) { /* Top Side */ + if ( nIndex == 0 || nIndex == 3 ) { /* Left (Top?) Side : bug 483 */ CREATE_KLU_BINDING_TABLE_CIDER(fPPsiIn, fPPsiInBinding, pEqn, psiEqnInM) ; CREATE_KLU_BINDING_TABLE_CIDER(fPPsiInP1, fPPsiInP1Binding, pEqn, psiEqnInP) ; diff --git a/src/spicelib/devices/nbjt/nbjtset.c b/src/spicelib/devices/nbjt/nbjtset.c index 34f62293d..9656ef443 100644 --- a/src/spicelib/devices/nbjt/nbjtset.c +++ b/src/spicelib/devices/nbjt/nbjtset.c @@ -44,7 +44,7 @@ NBJTsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) ONEmaterial *pM, *pMaterial = NULL, *materialList = NULL; double startTime; -#ifdef KLU +#if defined(KLU) && defined(NOT_WITH_CIDER) if (ckt->CKTkluMODE) { fprintf(stderr, "Error: CIDER simulation is not (yet) supported with 'option klu'.\n"); fprintf(stderr, " Use 'option sparse' instead.\n"); diff --git a/src/spicelib/devices/nbjt2/nbt2set.c b/src/spicelib/devices/nbjt2/nbt2set.c index 3164d329f..d700fa2b0 100644 --- a/src/spicelib/devices/nbjt2/nbt2set.c +++ b/src/spicelib/devices/nbjt2/nbt2set.c @@ -47,7 +47,7 @@ NBJT2setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) DOPtable *dopTableList = NULL; double startTime; -#ifdef KLU +#if defined(KLU) && defined(NOT_WITH_CIDER) if (ckt->CKTkluMODE) { fprintf(stderr, "Error: CIDER simulation is not (yet) supported with 'option klu'.\n"); fprintf(stderr, " Use 'option sparse' instead.\n"); diff --git a/src/spicelib/devices/numd/numdset.c b/src/spicelib/devices/numd/numdset.c index 365d290d4..426629062 100644 --- a/src/spicelib/devices/numd/numdset.c +++ b/src/spicelib/devices/numd/numdset.c @@ -46,7 +46,7 @@ NUMDsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) double startTime; -#ifdef KLU +#if defined(KLU) && defined(NOT_WITH_CIDER) if (ckt->CKTkluMODE) { fprintf(stderr, "Error: CIDER simulation is not (yet) supported with 'option klu'.\n"); fprintf(stderr, " Use 'option sparse' instead.\n"); diff --git a/src/spicelib/devices/numd2/nud2set.c b/src/spicelib/devices/numd2/nud2set.c index a35a3132f..79f0e3ddd 100644 --- a/src/spicelib/devices/numd2/nud2set.c +++ b/src/spicelib/devices/numd2/nud2set.c @@ -47,7 +47,7 @@ NUMD2setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) DOPtable *dopTableList = NULL; double startTime; -#ifdef KLU +#if defined(KLU) && defined(NOT_WITH_CIDER) if (ckt->CKTkluMODE) { fprintf(stderr, "Error: CIDER simulation is not (yet) supported with 'option klu'.\n"); fprintf(stderr, " Use 'option sparse' instead.\n"); diff --git a/src/spicelib/devices/numos/nummset.c b/src/spicelib/devices/numos/nummset.c index 7e9838056..bba47089b 100644 --- a/src/spicelib/devices/numos/nummset.c +++ b/src/spicelib/devices/numos/nummset.c @@ -47,7 +47,7 @@ NUMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) DOPtable *dopTableList = NULL; double startTime; -#ifdef KLU +#if defined(KLU) && defined(NOT_WITH_CIDER) if (ckt->CKTkluMODE) { fprintf(stderr, "Error: CIDER simulation is not (yet) supported with 'option klu'.\n"); fprintf(stderr, " Use 'option sparse' instead.\n"); From 0648d5e844f8585c0cabfe7b0127fae67da64885 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 13 Sep 2025 12:18:05 +0200 Subject: [PATCH 012/161] Spelling Found by Lintian, patches provided by C. Schoenert --- ChangeLog | 2 +- src/frontend/options.c | 2 +- src/include/ngspice/klu.h | 2 +- src/xspice/icm/analog/file_source/cfunc.mod | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index b586ca150..491675b42 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13794,7 +13794,7 @@ New include File: 2010-10-09 Robert Larice * src/include/complex.h : !REVERT! remove typedef for _complex, which is used nowhere - this breaks MSVC, currently unkown why, FIXME + this breaks MSVC, currently unknown why, FIXME 2010-10-09 Robert Larice * src/frontend/parse-bison.c , diff --git a/src/frontend/options.c b/src/frontend/options.c index 0b54881ba..7dfe6f97a 100644 --- a/src/frontend/options.c +++ b/src/frontend/options.c @@ -330,7 +330,7 @@ cp_usrset(struct variable *var, bool isset) ft_stricterror = isset; if (ft_ngdebug) fprintf(stdout, "Note: strict_errorhandling is set\n"); - /* Immediately bail out when spinit error has occured */ + /* Immediately bail out when spinit error has occurred */ if (ft_spiniterror) controlled_exit(EXIT_BAD); } else if (eq(var->va_name, "rawfileprec")) { diff --git a/src/include/ngspice/klu.h b/src/include/ngspice/klu.h index 248b9bf64..7e64bcdc5 100644 --- a/src/include/ngspice/klu.h +++ b/src/include/ngspice/klu.h @@ -133,7 +133,7 @@ typedef struct /* 64-bit version (otherwise same as above) */ #define KLU_EMPTY_MATRIX (2) /* Modified by Francesco Lannutti - Case when the matrix is empty */ #define KLU_OUT_OF_MEMORY (-2) #define KLU_INVALID (-3) -#define KLU_TOO_LARGE (-4) /* integer overflow has occured */ +#define KLU_TOO_LARGE (-4) /* integer overflow has occurred */ typedef struct klu_common_struct { diff --git a/src/xspice/icm/analog/file_source/cfunc.mod b/src/xspice/icm/analog/file_source/cfunc.mod index 2190b1a67..73eb12e68 100644 --- a/src/xspice/icm/analog/file_source/cfunc.mod +++ b/src/xspice/icm/analog/file_source/cfunc.mod @@ -336,9 +336,9 @@ void cm_filesource(ARGS) /* structure holding parms, inputs, outputs, etc. loc->timeinterval[1] = loc->indata->datavec[loc->indata->actpointer + stepsize]; if (terr) - cm_message_printf("WARNING: some error occured during reading the time values"); + cm_message_printf("WARNING: some error occurred during reading the time values"); if (derr) - cm_message_printf("WARNING: some error occured during reading the data values"); + cm_message_printf("WARNING: some error occurred during reading the data values"); } loc = STATIC_VAR (locdata); From 71a980f820678f15a450128303cb9ec9a7d66456 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 16 Sep 2025 15:08:34 +0200 Subject: [PATCH 013/161] Improve detection of the number of terminals for bipolar devices. Fixes bug no. 807. --- src/frontend/inpcom.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 71a3bdeaf..031dd9d5b 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -5286,8 +5286,7 @@ int get_number_terminals(char *c) char* comma; name[i] = gettok_instance(&cc); - if (search_plain_identifier(name[i], "off") || - strchr(name[i], '=')) { + if (search_plain_identifier(name[i], "off")) { j++; } #ifdef CIDER @@ -5296,16 +5295,9 @@ int get_number_terminals(char *c) j++; } #endif - /* If we have IC=VBE, VCE instead of IC=VBE,VCE - * we need to increment j. - */ - if ((comma = strchr(name[i], ',')) != NULL && - (*(++comma) == '\0')) - j++; - /* If we have IC=VBE , VCE ("," is a token) we need to inc j - */ - if (eq(name[i], ",")) - j++; + if (strchr(name[i], '=')) { + break; + } } i--; tfree(ccfree); From 5a8b1763780e0fd788114060f63e38a820de3376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81rp=C3=A1d=20B=C5=B1rmen?= Date: Fri, 12 Sep 2025 10:04:29 +0200 Subject: [PATCH 014/161] Fast version checks in BSIM4. --- src/spicelib/devices/bsim4/b4noi.c | 21 ++++++++++++--------- src/spicelib/devices/bsim4/b4set.c | 20 +++++++++++++++++--- src/spicelib/devices/bsim4/b4temp.c | 9 +++++---- src/spicelib/devices/bsim4/bsim4def.h | 7 ++++++- 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/spicelib/devices/bsim4/b4noi.c b/src/spicelib/devices/bsim4/b4noi.c index 473dea60d..faea45ab6 100644 --- a/src/spicelib/devices/bsim4/b4noi.c +++ b/src/spicelib/devices/bsim4/b4noi.c @@ -366,9 +366,10 @@ double mult_i, mult_fn; epsilon = (T7 - T7 * T7 * T7 / 3.0) / (6.0 * T6); T8 = here->BSIM4Vgsteff / here->BSIM4EsatL; T8 *= T8; - if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && (strncmp(model->BSIM4version, "4.8", 3)) && - (strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) && - (strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4))) + // if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && (strncmp(model->BSIM4version, "4.8", 3)) && + // (strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) && + // (strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4))) + if (model->BSIM4v48intVersion<=BSIM4v48V480) { npart_c = model->BSIM4rnoic * (1.0 + T8 * model->BSIM4tnoic * Leff); @@ -420,9 +421,10 @@ double mult_i, mult_fn; } switch(model->BSIM4tnoiMod) { case 0: - if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && (strncmp(model->BSIM4version, "4.8", 3)) && - (strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) && - (strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4))) + // if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && (strncmp(model->BSIM4version, "4.8", 3)) && + // (strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) && + // (strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4))) + if (model->BSIM4v48intVersion<=BSIM4v48V480) { T0 = here->BSIM4ueff * fabs(here->BSIM4qinv); T1 = T0 * tmp + pParam->BSIM4leff @@ -449,9 +451,10 @@ double mult_i, mult_fn; } break; case 1: - if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && (strncmp(model->BSIM4version, "4.8", 3)) && - (strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) && - (strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4))) + // if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && (strncmp(model->BSIM4version, "4.8", 3)) && + // (strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) && + // (strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4))) + if (model->BSIM4v48intVersion<=BSIM4v48V480) { T0 = here->BSIM4gm + here->BSIM4gmbs + here->BSIM4gds; T0 *= T0; diff --git a/src/spicelib/devices/bsim4/b4set.c b/src/spicelib/devices/bsim4/b4set.c index 0637be32e..2135ce9a3 100644 --- a/src/spicelib/devices/bsim4/b4set.c +++ b/src/spicelib/devices/bsim4/b4set.c @@ -203,6 +203,19 @@ BSIM4instance **InstArray; } if (!model->BSIM4versionGiven) model->BSIM4version = copy("4.8.3"); + /* Speed up version checking via integer version number */ + if ((!strcmp(model->BSIM4version, "4.8.3"))||(!strncmp(model->BSIM4version, "4.83", 4))) { + model->BSIM4v48intVersion = BSIM4v48V483; + } else if ((!strcmp(model->BSIM4version, "4.8.2"))||(!strncmp(model->BSIM4version, "4.82", 4))) { + model->BSIM4v48intVersion = BSIM4v48V482; + } else if ((!strcmp(model->BSIM4version, "4.8.1"))||(!strncmp(model->BSIM4version, "4.81", 4))) { + model->BSIM4v48intVersion = BSIM4v48V481; + } else if ((!strcmp(model->BSIM4version, "4.8.0"))||(!strncmp(model->BSIM4version, "4.80", 4))||(!strncmp(model->BSIM4version, "4.8", 3))) { + model->BSIM4v48intVersion = BSIM4v48V480; + } else { + printf("Warning: unknown BSIM4 version. Working now with BSIM4.8.3.\n"); + model->BSIM4v48intVersion = BSIM4v48V483; + } if (!model->BSIM4toxrefGiven) model->BSIM4toxref = 30.0e-10; if (!model->BSIM4eotGiven) @@ -342,9 +355,10 @@ BSIM4instance **InstArray; if (!model->BSIM4ucsGiven) model->BSIM4ucs = (model->BSIM4type == NMOS) ? 1.67 : 1.0; - if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && - (strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) && - (strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4))) + // if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && + // (strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) && + // (strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4))) + if (model->BSIM4v48intVersion<=BSIM4v48V480) { if (!model->BSIM4uaGiven) model->BSIM4ua = ((model->BSIM4mobMod == 2)) ? 1.0e-15 : 1.0e-9; /* unit m/V */ diff --git a/src/spicelib/devices/bsim4/b4temp.c b/src/spicelib/devices/bsim4/b4temp.c index 3c9796db6..3b41db563 100644 --- a/src/spicelib/devices/bsim4/b4temp.c +++ b/src/spicelib/devices/bsim4/b4temp.c @@ -1368,10 +1368,11 @@ int Fatal_Flag = 0; pParam->BSIM4Aechvb = (model->BSIM4type == NMOS) ? 4.97232e-7 : 3.42537e-7; pParam->BSIM4Bechvb = (model->BSIM4type == NMOS) ? 7.45669e11 : 1.16645e12; - if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && - (strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) && - (strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4))) - { + // if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && + // (strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) && + // (strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4))) + // { + if (model->BSIM4v48intVersion<=BSIM4v48V480) { pParam->BSIM4AechvbEdgeS = pParam->BSIM4Aechvb * pParam->BSIM4weff * model->BSIM4dlcig * pParam->BSIM4ToxRatioEdge; pParam->BSIM4AechvbEdgeD = pParam->BSIM4Aechvb * pParam->BSIM4weff diff --git a/src/spicelib/devices/bsim4/bsim4def.h b/src/spicelib/devices/bsim4/bsim4def.h index a2bff4121..6d7d652e8 100644 --- a/src/spicelib/devices/bsim4/bsim4def.h +++ b/src/spicelib/devices/bsim4/bsim4def.h @@ -941,7 +941,12 @@ typedef struct sBSIM4model int BSIM4tempMod; int BSIM4binUnit; int BSIM4paramChk; - char *BSIM4version; + char *BSIM4version; + int BSIM4v48intVersion; +#define BSIM4v48V483 483 /* BSIM4v48 V4.8.3 */ +#define BSIM4v48V482 482 /* BSIM4v48 V4.8.2 */ +#define BSIM4v48V481 481 /* BSIM4v48 V4.8.1 */ +#define BSIM4v48V480 480 /* BSIM4v48 V4.8.0 */ double BSIM4eot; double BSIM4vddeot; double BSIM4tempeot; From 58dfdcec523cb40730b7ea12febe7cf182d2dfc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81rp=C3=A1d=20B=C5=B1rmen?= Date: Fri, 22 Aug 2025 11:20:43 +0200 Subject: [PATCH 015/161] icvgs, icvds, icvbs exposed as BSIM4v8 parameters. --- src/spicelib/devices/bsim4/b4.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/spicelib/devices/bsim4/b4.c b/src/spicelib/devices/bsim4/b4.c index b39901f32..438c1498b 100644 --- a/src/spicelib/devices/bsim4/b4.c +++ b/src/spicelib/devices/bsim4/b4.c @@ -71,6 +71,9 @@ IOP( "mult_i", BSIM4_MULT_I, IF_REAL, "Variability in current"), IOP( "mult_q", BSIM4_MULT_Q, IF_REAL, "Variability in charge"), IOP( "mult_fn", BSIM4_MULT_FN, IF_REAL, "Variability in flicker noise"), IP( "ic", BSIM4_IC, IF_REALVEC , "Vector of DS,GS,BS initial voltages"), +IOP( "icvgs", BSIM4_IC_VGS, IF_REAL , "GS initial voltage"), +IOP( "icvds", BSIM4_IC_VDS, IF_REAL , "DS initial voltage"), +IOP( "icvbs", BSIM4_IC_VBS, IF_REAL , "BS initial voltage"), OP( "gmbs", BSIM4_GMBS, IF_REAL, "Gmb"), OP( "gm", BSIM4_GM, IF_REAL, "Gm"), OP( "gds", BSIM4_GDS, IF_REAL, "Gds"), From 942f8772907eb64ee90661d8f0f262caa7ffd886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81rp=C3=A1d=20B=C5=B1rmen?= Date: Fri, 12 Sep 2025 10:10:48 +0200 Subject: [PATCH 016/161] Check if toxp+dtox!=toxe with double precision tolerance. --- src/spicelib/devices/bsim4/b4temp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/spicelib/devices/bsim4/b4temp.c b/src/spicelib/devices/bsim4/b4temp.c index 3b41db563..f4c76dd65 100644 --- a/src/spicelib/devices/bsim4/b4temp.c +++ b/src/spicelib/devices/bsim4/b4temp.c @@ -122,8 +122,12 @@ int Fatal_Flag = 0; if(model->BSIM4mtrlMod == 0) { + double chktol = fabs(model->BSIM4toxe); + if (fabs(model->BSIM4toxp)>chktol) chktol = fabs(model->BSIM4toxp); + if (fabs(model->BSIM4dtox)>chktol) chktol = fabs(model->BSIM4dtox); + chktol=chktol*1e-14; if ((model->BSIM4toxeGiven) && (model->BSIM4toxpGiven) && (model->BSIM4dtoxGiven) - && (model->BSIM4toxe != (model->BSIM4toxp + model->BSIM4dtox))) + && (fabs(model->BSIM4toxe-(model->BSIM4toxp + model->BSIM4dtox))>chktol)) { printf("Warning: toxe, toxp and dtox all given and toxe != toxp + dtox; dtox ignored.\n"); } else if ((model->BSIM4toxeGiven) && (!model->BSIM4toxpGiven)) From dc58709a37e004eaac43b96e45accb83db7f7e95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81rp=C3=A1d=20B=C5=B1rmen?= Date: Mon, 15 Sep 2025 10:23:11 +0200 Subject: [PATCH 017/161] Fixed a bug causing mult_* factors to get scaled at each setup(). --- src/spicelib/devices/bsim4/b4acld.c | 4 +- src/spicelib/devices/bsim4/b4ask.c | 88 ++++++++++++++--------------- src/spicelib/devices/bsim4/b4ld.c | 6 +- src/spicelib/devices/bsim4/b4noi.c | 4 +- src/spicelib/devices/bsim4/b4pzld.c | 4 +- src/spicelib/devices/bsim4/b4set.c | 7 ++- 6 files changed, 57 insertions(+), 56 deletions(-) diff --git a/src/spicelib/devices/bsim4/b4acld.c b/src/spicelib/devices/bsim4/b4acld.c index 18257423c..c972d6866 100644 --- a/src/spicelib/devices/bsim4/b4acld.c +++ b/src/spicelib/devices/bsim4/b4acld.c @@ -462,8 +462,8 @@ double m, mult_i, mult_q; * Loading AC matrix */ m = here->BSIM4m; - mult_i = here->BSIM4mult_i; - mult_q = here->BSIM4mult_q; + mult_i = here->BSIM4mult_i * here->BSIM4m; + mult_q = here->BSIM4mult_q * here->BSIM4m; if (!model->BSIM4rdsMod) { gdpr = here->BSIM4drainConductance; diff --git a/src/spicelib/devices/bsim4/b4ask.c b/src/spicelib/devices/bsim4/b4ask.c index c0f843e95..d43e1a708 100644 --- a/src/spicelib/devices/bsim4/b4ask.c +++ b/src/spicelib/devices/bsim4/b4ask.c @@ -203,11 +203,11 @@ BSIM4instance *here = (BSIM4instance*)inst; return(OK); case BSIM4_SOURCECONDUCT: value->rValue = here->BSIM4sourceConductance; - value->rValue *= here->BSIM4mult_i; + value->rValue *= here->BSIM4mult_i * here->BSIM4m; return(OK); case BSIM4_DRAINCONDUCT: value->rValue = here->BSIM4drainConductance; - value->rValue *= here->BSIM4mult_i; + value->rValue *= here->BSIM4mult_i * here->BSIM4m; return(OK); case BSIM4_VBD: value->rValue = *(ckt->CKTstate0 + here->BSIM4vbd); @@ -223,67 +223,67 @@ BSIM4instance *here = (BSIM4instance*)inst; return(OK); case BSIM4_CD: value->rValue = here->BSIM4cd; - value->rValue *= here->BSIM4mult_i; + value->rValue *= here->BSIM4mult_i * here->BSIM4m; return(OK); case BSIM4_CBS: value->rValue = here->BSIM4cbs; - value->rValue *= here->BSIM4mult_i; + value->rValue *= here->BSIM4mult_i * here->BSIM4m; return(OK); case BSIM4_CBD: value->rValue = here->BSIM4cbd; - value->rValue *= here->BSIM4mult_i; + value->rValue *= here->BSIM4mult_i * here->BSIM4m; return(OK); case BSIM4_CSUB: value->rValue = here->BSIM4csub; - value->rValue *= here->BSIM4mult_i; + value->rValue *= here->BSIM4mult_i * here->BSIM4m; return(OK); case BSIM4_IGIDL: value->rValue = here->BSIM4Igidl; - value->rValue *= here->BSIM4mult_i; + value->rValue *= here->BSIM4mult_i * here->BSIM4m; return(OK); case BSIM4_IGISL: value->rValue = here->BSIM4Igisl; - value->rValue *= here->BSIM4mult_i; + value->rValue *= here->BSIM4mult_i * here->BSIM4m; return(OK); case BSIM4_IGS: value->rValue = here->BSIM4Igs; - value->rValue *= here->BSIM4mult_i; + value->rValue *= here->BSIM4mult_i * here->BSIM4m; return(OK); case BSIM4_IGD: value->rValue = here->BSIM4Igd; - value->rValue *= here->BSIM4mult_i; + value->rValue *= here->BSIM4mult_i * here->BSIM4m; return(OK); case BSIM4_IGB: value->rValue = here->BSIM4Igb; - value->rValue *= here->BSIM4mult_i; + value->rValue *= here->BSIM4mult_i * here->BSIM4m; return(OK); case BSIM4_IGCS: value->rValue = here->BSIM4Igcs; - value->rValue *= here->BSIM4mult_i; + value->rValue *= here->BSIM4mult_i * here->BSIM4m; return(OK); case BSIM4_IGCD: value->rValue = here->BSIM4Igcd; - value->rValue *= here->BSIM4mult_i; + value->rValue *= here->BSIM4mult_i * here->BSIM4m; return(OK); case BSIM4_GM: value->rValue = here->BSIM4gm; - value->rValue *= here->BSIM4mult_i; + value->rValue *= here->BSIM4mult_i * here->BSIM4m; return(OK); case BSIM4_GDS: value->rValue = here->BSIM4gds; - value->rValue *= here->BSIM4mult_i; + value->rValue *= here->BSIM4mult_i * here->BSIM4m; return(OK); case BSIM4_GMBS: value->rValue = here->BSIM4gmbs; - value->rValue *= here->BSIM4mult_i; + value->rValue *= here->BSIM4mult_i * here->BSIM4m; return(OK); case BSIM4_GBD: value->rValue = here->BSIM4gbd; - value->rValue *= here->BSIM4mult_i; + value->rValue *= here->BSIM4mult_i * here->BSIM4m; return(OK); case BSIM4_GBS: value->rValue = here->BSIM4gbs; - value->rValue *= here->BSIM4mult_i; + value->rValue *= here->BSIM4mult_i * here->BSIM4m; return(OK); /* case BSIM4_QB: value->rValue = *(ckt->CKTstate0 + here->BSIM4qb); @@ -308,19 +308,19 @@ BSIM4instance *here = (BSIM4instance*)inst; return(OK); */ case BSIM4_QB: value->rValue = here->BSIM4qbulk; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_QG: value->rValue = here->BSIM4qgate; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_QS: value->rValue = here->BSIM4qsrc; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_QD: value->rValue = here->BSIM4qdrn; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_QINV: value->rValue = here->BSIM4qinv; @@ -330,82 +330,82 @@ BSIM4instance *here = (BSIM4instance*)inst; return(OK); case BSIM4_GCRG: value->rValue = here->BSIM4gcrg; - value->rValue *= here->BSIM4mult_i; + value->rValue *= here->BSIM4mult_i * here->BSIM4m; return(OK); case BSIM4_GTAU: value->rValue = here->BSIM4gtau; return(OK); case BSIM4_CGGB: value->rValue = here->BSIM4cggb; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_CGDB: value->rValue = here->BSIM4cgdb; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_CGSB: value->rValue = here->BSIM4cgsb; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_CDGB: value->rValue = here->BSIM4cdgb; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_CDDB: value->rValue = here->BSIM4cddb; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_CDSB: value->rValue = here->BSIM4cdsb; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_CBGB: value->rValue = here->BSIM4cbgb; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_CBDB: value->rValue = here->BSIM4cbdb; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_CBSB: value->rValue = here->BSIM4cbsb; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_CSGB: value->rValue = here->BSIM4csgb; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_CSDB: value->rValue = here->BSIM4csdb; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_CSSB: value->rValue = here->BSIM4cssb; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_CGBB: value->rValue = here->BSIM4cgbb; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_CDBB: value->rValue = here->BSIM4cdbb; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_CSBB: value->rValue = here->BSIM4csbb; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_CBBB: value->rValue = here->BSIM4cbbb; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_CAPBD: value->rValue = here->BSIM4capbd; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_CAPBS: value->rValue = here->BSIM4capbs; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_VON: value->rValue = here->BSIM4von; @@ -427,15 +427,15 @@ BSIM4instance *here = (BSIM4instance*)inst; return(OK); case BSIM4_CGSO: value->rValue = here->BSIM4cgso; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_CGDO: value->rValue = here->BSIM4cgdo; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_CGBO: value->rValue = here->pParam->BSIM4cgbo; - value->rValue *= here->BSIM4mult_q; + value->rValue *= here->BSIM4mult_q * here->BSIM4m; return(OK); case BSIM4_WEFF: value->rValue = here->pParam->BSIM4weff; diff --git a/src/spicelib/devices/bsim4/b4ld.c b/src/spicelib/devices/bsim4/b4ld.c index da408eaef..5001e12f3 100644 --- a/src/spicelib/devices/bsim4/b4ld.c +++ b/src/spicelib/devices/bsim4/b4ld.c @@ -4986,9 +4986,9 @@ line900: */ m = here->BSIM4m; - mult_i = here->BSIM4mult_i; - mult_q = here->BSIM4mult_q; - + mult_i = here->BSIM4mult_i * here->BSIM4m; + mult_q = here->BSIM4mult_q * here->BSIM4m; + #ifdef USE_OMP here->BSIM4rhsdPrime = (mult_i * (ceqjd - ceqbd + ceqgdtot - ceqdrn + Idtoteq) - mult_q * ceqqd); diff --git a/src/spicelib/devices/bsim4/b4noi.c b/src/spicelib/devices/bsim4/b4noi.c index faea45ab6..d56b19cb2 100644 --- a/src/spicelib/devices/bsim4/b4noi.c +++ b/src/spicelib/devices/bsim4/b4noi.c @@ -155,8 +155,8 @@ double mult_i, mult_fn; } break; case N_CALC: - mult_i = here->BSIM4mult_i; - mult_fn = here->BSIM4mult_fn; + mult_i = here->BSIM4mult_i * here->BSIM4m; + mult_fn = here->BSIM4mult_fn * here->BSIM4m; switch (mode) { case N_DENS: if (model->BSIM4tnoiMod == 0) diff --git a/src/spicelib/devices/bsim4/b4pzld.c b/src/spicelib/devices/bsim4/b4pzld.c index 970f78889..ff66cf13a 100644 --- a/src/spicelib/devices/bsim4/b4pzld.c +++ b/src/spicelib/devices/bsim4/b4pzld.c @@ -494,8 +494,8 @@ double m, mult_i, mult_q; * Loading PZ matrix */ m = here->BSIM4m; - mult_i = here->BSIM4mult_i; - mult_q = here->BSIM4mult_q; + mult_i = here->BSIM4mult_i * here->BSIM4m; + mult_q = here->BSIM4mult_q * here->BSIM4m; if (!model->BSIM4rdsMod) { gdpr = here->BSIM4drainConductance; diff --git a/src/spicelib/devices/bsim4/b4set.c b/src/spicelib/devices/bsim4/b4set.c index 2135ce9a3..56ae72096 100644 --- a/src/spicelib/devices/bsim4/b4set.c +++ b/src/spicelib/devices/bsim4/b4set.c @@ -2375,9 +2375,10 @@ BSIM4instance **InstArray; if (!here->BSIM4ngconGiven) here->BSIM4ngcon = model->BSIM4ngcon; - here->BSIM4mult_i = here->BSIM4mult_i * here->BSIM4m; - here->BSIM4mult_q = here->BSIM4mult_q * here->BSIM4m; - here->BSIM4mult_fn = here->BSIM4mult_fn * here->BSIM4m; + // Recursive scaling produces incorrect results after second call to setup() + // here->BSIM4mult_i = here->BSIM4mult_i * here->BSIM4m; + // here->BSIM4mult_q = here->BSIM4mult_q * here->BSIM4m; + // here->BSIM4mult_fn = here->BSIM4mult_fn * here->BSIM4m; /* Process instance model selectors, some * may override their global counterparts From 5153d8a4c15f0097d5f22363ad12fa4eb2410ee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81rp=C3=A1d=20B=C5=B1rmen?= Date: Mon, 15 Sep 2025 10:25:08 +0200 Subject: [PATCH 018/161] ceqqjd, ceqqjs should be scaled with mult_q. This fixes erratic simulation behavior when mult_i != mult_q. --- src/spicelib/devices/bsim4/b4ld.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/spicelib/devices/bsim4/b4ld.c b/src/spicelib/devices/bsim4/b4ld.c index 5001e12f3..fa7d56f96 100644 --- a/src/spicelib/devices/bsim4/b4ld.c +++ b/src/spicelib/devices/bsim4/b4ld.c @@ -5006,9 +5006,9 @@ line900: - ceqgstot + Istoteq) + mult_q * (ceqqg + ceqqb + ceqqd + ceqqgmid)); } else - { here->BSIM4rhsdb = mult_i * (ceqjd + ceqqjd); + { here->BSIM4rhsdb = mult_i * (ceqjd /*+ ceqqjd */) + mult_q * ceqqjd); here->BSIM4rhsbPrime = (mult_i * (ceqbd + ceqbs + Ibtoteq) - mult_q * ceqqb); - here->BSIM4rhssb = mult_i * (ceqjs + ceqqjs); + here->BSIM4rhssb = mult_i * (ceqjs /*+ ceqqjs*/) + mult_q * ceqqjs; here->BSIM4rhssPrime = (mult_i * (ceqdrn - ceqbs + ceqjs - ceqgstot + Istoteq) + mult_q * (ceqqd + ceqqg + ceqqb + ceqqjd + ceqqjs + ceqqgmid)); } @@ -5037,9 +5037,9 @@ line900: - ceqgstot + Istoteq) + mult_q * (ceqqg + ceqqb + ceqqd + ceqqgmid))); } else - { (*(ckt->CKTrhs + here->BSIM4dbNode) -= mult_i * (ceqjd + ceqqjd)); + { (*(ckt->CKTrhs + here->BSIM4dbNode) -= mult_i * (ceqjd /*+ ceqqjd*/) + mult_q * ceqqjd); (*(ckt->CKTrhs + here->BSIM4bNodePrime) += (mult_i * (ceqbd + ceqbs + Ibtoteq) - mult_q * ceqqb)); - (*(ckt->CKTrhs + here->BSIM4sbNode) -= mult_i * (ceqjs + ceqqjs)); + (*(ckt->CKTrhs + here->BSIM4sbNode) -= mult_i * (ceqjs /*+ ceqqjs*/) + mult_q * ceqqjs); (*(ckt->CKTrhs + here->BSIM4sNodePrime) += (mult_i * (ceqdrn - ceqbs + ceqjs - ceqgstot + Istoteq) + mult_q * (ceqqd + ceqqg + ceqqb + ceqqjd + ceqqjs + ceqqgmid))); } From e0694629d12aabcc24954a8e6ae6f8e6009299bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81rp=C3=A1d=20B=C5=B1rmen?= Date: Mon, 15 Sep 2025 12:04:44 +0200 Subject: [PATCH 019/161] Scaling of NQS charge deficit with mult_q. --- src/spicelib/devices/bsim4/b4ld.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/spicelib/devices/bsim4/b4ld.c b/src/spicelib/devices/bsim4/b4ld.c index fa7d56f96..9c840e395 100644 --- a/src/spicelib/devices/bsim4/b4ld.c +++ b/src/spicelib/devices/bsim4/b4ld.c @@ -5227,9 +5227,9 @@ line900: here->BSIM4_99 = m * (ggts - gcqsb); here->BSIM4_100 = m * (ggtb - gcqbb); - here->BSIM4_101 = m * dxpart * here->BSIM4gtau; - here->BSIM4_102 = m * sxpart * here->BSIM4gtau; - here->BSIM4_103 = m * here->BSIM4gtau; + here->BSIM4_101 = mult_q * dxpart * here->BSIM4gtau; + here->BSIM4_102 = mult_q * sxpart * here->BSIM4gtau; + here->BSIM4_103 = mult_q * here->BSIM4gtau; } #else if (here->BSIM4rgateMod == 1) @@ -5382,9 +5382,9 @@ line900: (*(here->BSIM4QspPtr) += m * (ggts - gcqsb)); (*(here->BSIM4QbpPtr) += m * (ggtb - gcqbb)); - (*(here->BSIM4DPqPtr) += m * (dxpart * here->BSIM4gtau)); - (*(here->BSIM4SPqPtr) += m * (sxpart * here->BSIM4gtau)); - (*(here->BSIM4GPqPtr) -= m * (here->BSIM4gtau)); + (*(here->BSIM4DPqPtr) += mult_q * (dxpart * here->BSIM4gtau)); + (*(here->BSIM4SPqPtr) += mult_q * (sxpart * here->BSIM4gtau)); + (*(here->BSIM4GPqPtr) -= mult_q * (here->BSIM4gtau)); } #endif From adae811ad2b764f248e5c4552aa17c2125875838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81rp=C3=A1d=20B=C5=B1rmen?= Date: Tue, 16 Sep 2025 13:37:50 +0200 Subject: [PATCH 020/161] BSIM4 version 4.8 is considered to be the latest, i.e. 4.8.3. --- src/spicelib/devices/bsim4/b4set.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spicelib/devices/bsim4/b4set.c b/src/spicelib/devices/bsim4/b4set.c index 56ae72096..72495a636 100644 --- a/src/spicelib/devices/bsim4/b4set.c +++ b/src/spicelib/devices/bsim4/b4set.c @@ -204,13 +204,13 @@ BSIM4instance **InstArray; if (!model->BSIM4versionGiven) model->BSIM4version = copy("4.8.3"); /* Speed up version checking via integer version number */ - if ((!strcmp(model->BSIM4version, "4.8.3"))||(!strncmp(model->BSIM4version, "4.83", 4))) { + if ((!strcmp(model->BSIM4version, "4.8.3"))||(!strncmp(model->BSIM4version, "4.83", 4))||(!strncmp(model->BSIM4version, "4.8", 3))) { model->BSIM4v48intVersion = BSIM4v48V483; } else if ((!strcmp(model->BSIM4version, "4.8.2"))||(!strncmp(model->BSIM4version, "4.82", 4))) { model->BSIM4v48intVersion = BSIM4v48V482; } else if ((!strcmp(model->BSIM4version, "4.8.1"))||(!strncmp(model->BSIM4version, "4.81", 4))) { model->BSIM4v48intVersion = BSIM4v48V481; - } else if ((!strcmp(model->BSIM4version, "4.8.0"))||(!strncmp(model->BSIM4version, "4.80", 4))||(!strncmp(model->BSIM4version, "4.8", 3))) { + } else if ((!strcmp(model->BSIM4version, "4.8.0"))||(!strncmp(model->BSIM4version, "4.80", 4))) { model->BSIM4v48intVersion = BSIM4v48V480; } else { printf("Warning: unknown BSIM4 version. Working now with BSIM4.8.3.\n"); From f1a240e6b1cd6c97ebff3594a709657efa4a209c Mon Sep 17 00:00:00 2001 From: dwarning Date: Tue, 16 Sep 2025 18:33:55 +0200 Subject: [PATCH 021/161] remove old commented strncmp version check code --- src/spicelib/devices/bsim4/b4noi.c | 9 --------- src/spicelib/devices/bsim4/b4set.c | 8 -------- src/spicelib/devices/bsim4/b4temp.c | 4 ---- 3 files changed, 21 deletions(-) diff --git a/src/spicelib/devices/bsim4/b4noi.c b/src/spicelib/devices/bsim4/b4noi.c index d56b19cb2..c6aa87936 100644 --- a/src/spicelib/devices/bsim4/b4noi.c +++ b/src/spicelib/devices/bsim4/b4noi.c @@ -366,9 +366,6 @@ double mult_i, mult_fn; epsilon = (T7 - T7 * T7 * T7 / 3.0) / (6.0 * T6); T8 = here->BSIM4Vgsteff / here->BSIM4EsatL; T8 *= T8; - // if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && (strncmp(model->BSIM4version, "4.8", 3)) && - // (strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) && - // (strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4))) if (model->BSIM4v48intVersion<=BSIM4v48V480) { npart_c = model->BSIM4rnoic * (1.0 + T8 @@ -421,9 +418,6 @@ double mult_i, mult_fn; } switch(model->BSIM4tnoiMod) { case 0: - // if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && (strncmp(model->BSIM4version, "4.8", 3)) && - // (strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) && - // (strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4))) if (model->BSIM4v48intVersion<=BSIM4v48V480) { T0 = here->BSIM4ueff * fabs(here->BSIM4qinv); @@ -451,9 +445,6 @@ double mult_i, mult_fn; } break; case 1: - // if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && (strncmp(model->BSIM4version, "4.8", 3)) && - // (strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) && - // (strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4))) if (model->BSIM4v48intVersion<=BSIM4v48V480) { T0 = here->BSIM4gm + here->BSIM4gmbs + here->BSIM4gds; diff --git a/src/spicelib/devices/bsim4/b4set.c b/src/spicelib/devices/bsim4/b4set.c index 72495a636..71bc75a81 100644 --- a/src/spicelib/devices/bsim4/b4set.c +++ b/src/spicelib/devices/bsim4/b4set.c @@ -355,9 +355,6 @@ BSIM4instance **InstArray; if (!model->BSIM4ucsGiven) model->BSIM4ucs = (model->BSIM4type == NMOS) ? 1.67 : 1.0; - // if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && - // (strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) && - // (strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4))) if (model->BSIM4v48intVersion<=BSIM4v48V480) { if (!model->BSIM4uaGiven) @@ -2375,11 +2372,6 @@ BSIM4instance **InstArray; if (!here->BSIM4ngconGiven) here->BSIM4ngcon = model->BSIM4ngcon; - // Recursive scaling produces incorrect results after second call to setup() - // here->BSIM4mult_i = here->BSIM4mult_i * here->BSIM4m; - // here->BSIM4mult_q = here->BSIM4mult_q * here->BSIM4m; - // here->BSIM4mult_fn = here->BSIM4mult_fn * here->BSIM4m; - /* Process instance model selectors, some * may override their global counterparts */ diff --git a/src/spicelib/devices/bsim4/b4temp.c b/src/spicelib/devices/bsim4/b4temp.c index f4c76dd65..9e786ab3c 100644 --- a/src/spicelib/devices/bsim4/b4temp.c +++ b/src/spicelib/devices/bsim4/b4temp.c @@ -1372,10 +1372,6 @@ int Fatal_Flag = 0; pParam->BSIM4Aechvb = (model->BSIM4type == NMOS) ? 4.97232e-7 : 3.42537e-7; pParam->BSIM4Bechvb = (model->BSIM4type == NMOS) ? 7.45669e11 : 1.16645e12; - // if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && - // (strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) && - // (strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4))) - // { if (model->BSIM4v48intVersion<=BSIM4v48V480) { pParam->BSIM4AechvbEdgeS = pParam->BSIM4Aechvb * pParam->BSIM4weff * model->BSIM4dlcig * pParam->BSIM4ToxRatioEdge; From b57800d4bd9e3f8fdd5c072391b92a92e16717d6 Mon Sep 17 00:00:00 2001 From: dwarning Date: Tue, 16 Sep 2025 18:44:51 +0200 Subject: [PATCH 022/161] remove obsolete bracket --- src/spicelib/devices/bsim4/b4ld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spicelib/devices/bsim4/b4ld.c b/src/spicelib/devices/bsim4/b4ld.c index 9c840e395..af8713ef8 100644 --- a/src/spicelib/devices/bsim4/b4ld.c +++ b/src/spicelib/devices/bsim4/b4ld.c @@ -5006,7 +5006,7 @@ line900: - ceqgstot + Istoteq) + mult_q * (ceqqg + ceqqb + ceqqd + ceqqgmid)); } else - { here->BSIM4rhsdb = mult_i * (ceqjd /*+ ceqqjd */) + mult_q * ceqqjd); + { here->BSIM4rhsdb = mult_i * (ceqjd /*+ ceqqjd */) + mult_q * ceqqjd; here->BSIM4rhsbPrime = (mult_i * (ceqbd + ceqbs + Ibtoteq) - mult_q * ceqqb); here->BSIM4rhssb = mult_i * (ceqjs /*+ ceqqjs*/) + mult_q * ceqqjs; here->BSIM4rhssPrime = (mult_i * (ceqdrn - ceqbs + ceqjs - ceqgstot + Istoteq) + mult_q * (ceqqd From 3d0ab2db8e9c256fe593299b5ce52447a9680a34 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 17 Sep 2025 10:15:42 +0200 Subject: [PATCH 023/161] Enable plain expression instead of only a number for area in bipolr device instances. --- src/frontend/inpcom.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 031dd9d5b..40d1809d6 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -5283,7 +5283,6 @@ int get_number_terminals(char *c) /* required to make m= 1 a single token m=1 */ ccfree = cc = inp_remove_ws(cc); for (i = j = 0; (i < 12) && (*cc != '\0'); ++i) { - char* comma; name[i] = gettok_instance(&cc); if (search_plain_identifier(name[i], "off")) { @@ -5298,6 +5297,10 @@ int get_number_terminals(char *c) if (strchr(name[i], '=')) { break; } + /* an expression for area {...}, (without area={...})*/ + if (*name[i] == '{') { + break; + } } i--; tfree(ccfree); From 85a04c5693346a5f3f19f3118cfb50399e26a3d9 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 17 Sep 2025 14:46:18 +0200 Subject: [PATCH 024/161] Cosmetics: Indentation --- src/spicelib/devices/vsrc/vsrcset.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/spicelib/devices/vsrc/vsrcset.c b/src/spicelib/devices/vsrc/vsrcset.c index e9febf2a7..b539fc493 100644 --- a/src/spicelib/devices/vsrc/vsrcset.c +++ b/src/spicelib/devices/vsrc/vsrcset.c @@ -107,13 +107,13 @@ VSRCunsetup(GENmodel *inModel, CKTcircuit *ckt) VSRCinstance *here; for (model = (VSRCmodel *)inModel; model != NULL; - model = VSRCnextModel(model)) + model = VSRCnextModel(model)) { for (here = VSRCinstances(model); here != NULL; here=VSRCnextInstance(here)) - { - if (here->VSRCbranch > 0) - CKTdltNNum(ckt, here->VSRCbranch); + { + if (here->VSRCbranch > 0) + CKTdltNNum(ckt, here->VSRCbranch); here->VSRCbranch = 0; #ifdef RFSPICE if ((here->VSRCresNode > 0) & (here->VSRCisPort)) @@ -121,7 +121,7 @@ VSRCunsetup(GENmodel *inModel, CKTcircuit *ckt) here->VSRCresNode = 0; #endif - } + } } return OK; } From e25c70b2bbcc98733bec373ca33f4e2128e7ead5 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 19 Sep 2025 16:53:11 +0200 Subject: [PATCH 025/161] add new function gettok_node_br which adds braces { } on its list of ignored characters. --- src/include/ngspice/ngspice.h | 1 + src/misc/string.c | 51 +++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/include/ngspice/ngspice.h b/src/include/ngspice/ngspice.h index e228cf2dd..ecafe3736 100644 --- a/src/include/ngspice/ngspice.h +++ b/src/include/ngspice/ngspice.h @@ -236,6 +236,7 @@ extern FILE *newfopen(const char *fn, const char* md); void findtok_noparen(char **p_str, char **p_token, char **p_token_end); extern char *gettok_noparens(char **s); extern char *gettok_node(char **s); +extern char *gettok_node_br(char **s); extern char *gettok_iv(char **s); extern char *nexttok(const char *s); extern char *nexttok_noparens(const char *s); diff --git a/src/misc/string.c b/src/misc/string.c index 97acd9c92..ac03d3f1e 100644 --- a/src/misc/string.c +++ b/src/misc/string.c @@ -861,6 +861,57 @@ gettok_node(char **s) return copy_substring(token, token_e); } +/*-------------------------------------------------------------------------* + * gettok_node_br acts like gettok_node, including braces { }. + *-------------------------------------------------------------------------*/ + +char* +gettok_node_br(char** s) +{ + char c; + const char* token, * token_e; + + if (*s == NULL) + return NULL; + + while (isspace_c(**s) || + (**s == '(') || + (**s == ')') || + (**s == '{') || + (**s == '}') || + (**s == ',') + ) + (*s)++; /* iterate over whitespace and ( , ) */ + + if (!**s) + return NULL; /* return NULL if we come to end of line */ + + token = *s; + while ((c = **s) != '\0' && + !isspace_c(c) && + (**s != '(') && + (**s != ')') && + (**s != '{') && + (**s != '}') && + (**s != ',') + ) /* collect chars until whitespace or ( , ) */ + (*s)++; + + token_e = *s; + + /* Now iterate up to next non-whitespace char */ + while (isspace_c(**s) || + (**s == '(') || + (**s == ')') || + (**s == '{') || + (**s == '}') || + (**s == ',') + ) + (*s)++; /* iterate over whitespace and ( , ) */ + + return copy_substring(token, token_e); +} + /*-------------------------------------------------------------------------* * get_l_paren iterates the pointer forward in a string until it hits From 5e12a80fb4a21983234df0ef87af0b1c75fdd097 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 19 Sep 2025 16:54:56 +0200 Subject: [PATCH 026/161] Exxx n1 n2 nc1 nc2 TABLE = (x0, y0, x1, y1, x2, y2) is now supported in addition to already existing Exxx n1 n2 TABLE {expression} = (x0, y0) (x1, y1) (x2, y2) --- src/frontend/inpcom.c | 105 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 40d1809d6..9c354356e 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -6119,6 +6119,14 @@ static void inp_compat(struct card *card) y_array=[y0 y1 y2] input_domain=0.1 fraction=TRUE) */ + /* Exxx n1 n2 nc1 nc2 TABLE = (x0, y0, x1, y1, x2, y2) + --> + Exxx n1 n2 Exxx_int1 0 1 + aExxx %vd(nc1 nc2) %v(Exxx_int1) xfer_Exxx + .model xfer_Exxx pwl(x_array=[x0 x1 x2] + y_array=[y0 y1 y2] + input_domain=0.001 fraction=TRUE) + */ if ((str_ptr = search_plain_identifier(curr_line, "table")) != NULL) { char *expression, *firstno, *secondno; DS_CREATE(dxar, 200); @@ -6128,6 +6136,7 @@ static void inp_compat(struct card *card) title_tok = gettok(&cut_line); node1 = gettok(&cut_line); node2 = gettok(&cut_line); + // Exxx n1 n2 int1 0 1 ckt_array[0] = tprintf("%s %s %s %s_int1 0 1", title_tok, node1, node2, title_tok); @@ -6241,6 +6250,89 @@ static void inp_compat(struct card *card) ds_free(&dxar); ds_free(&dyar); } + else { + /* LTSPICE table line + Exxx n+ n- nc+ nc- table=(-5m, 1, 0, 3, 5m, 5) */ + char* node3, * node4; + node3 = gettok(&cut_line); + node4 = gettok(&cut_line); + cut_line = skip_ws(cut_line); + if (ciprefix("table", cut_line)) { + /* a LTSPICE TABLE line */ + cut_line += 6; + ckt_array[1] = tprintf( + "a%s %%vd(%s %s) %%v(%s_int1) xfer_%s", + title_tok, node3, node4, title_tok, title_tok); + /* (x0, y0) (x1, y1) (x2, y2) to x0 x1 x2, y0 y1 y2 */ + int ipairs = 0; + char* pair_line = cut_line; + while (*cut_line != '\0') { + firstno = gettok_node_br(&cut_line); + secondno = gettok_node_br(&cut_line); + if ((!firstno && secondno) || + (firstno && !secondno)) { + fprintf(stderr, + "Error: Missing token in line %s\n" + " line no. %d from file %s\n", + curr_line, card->linenum_orig, card->linesource); + if (ft_stricterror) + controlled_exit(EXIT_FAILURE); + break; + } + else if (!firstno && !secondno) + continue; + sadd(&dxar, firstno); + cadd(&dxar, ' '); + sadd(&dyar, secondno); + cadd(&dyar, ' '); + tfree(firstno); + tfree(secondno); + ipairs++; + } + /* There is a strange usage of the TABLE function: + A single pair (x0, y0) will return a constant voltage y0 */ + if (ipairs == 1) { + tfree(ckt_array[1]); + tfree(ckt_array[2]); + firstno = gettok_node_br(&pair_line); + tfree(firstno); + secondno = gettok_node_br(&pair_line); + ckt_array[1] = tprintf("v%s %s_int1 0 %s", title_tok, + title_tok, secondno); + tfree(secondno); + // comment out current variable e line + *(card->line) = '*'; + // insert new lines immediately after current line + for (i = 0; i < 2; i++) { + card = insert_new_line(card, ckt_array[i], (int)i + 1, currlinenumber, card->linesource); + } + } + else { + ckt_array[2] = tprintf( + ".model xfer_%s pwl(x_array=[%s] y_array=[%s] " + "input_domain=0.001 fraction=TRUE limit=TRUE)", + title_tok, ds_get_buf(&dxar), ds_get_buf(&dyar)); + // comment out current variable e line + *(card->line) = '*'; + // insert new lines immediately after current line + for (i = 0; i < 3; i++) { + card = insert_new_line(card, ckt_array[i], (int)i + 1, currlinenumber, card->linesource); + } + } + tfree(title_tok); + tfree(node1); + tfree(node2); + tfree(node3); + tfree(node4); + ds_free(&dxar); + ds_free(&dyar); + } + else { + fprintf(stderr, "ERROR: mal formed E source instance: %s\n", curr_line); + fprintf(stderr, " in line no. %d of file %s\n", card->linenum_orig, card->linesource); + controlled_exit(EXIT_FAILURE); + } + } } /* Exxx n1 n2 VOL = {equation} @@ -6308,6 +6400,15 @@ static void inp_compat(struct card *card) y_array=[y0 y1 y2] input_domain=0.1 fraction=TRUE) */ + /* FIXME: to be done + Gxxx n1 n2 nc1 nc2 TABLE = (x0, y0, x1, y1, x2, y2) m=1 + --> + Gxxx n1 n2 Gxxx_int1 0 1 m=1 + aGxxx %vd(nc1 nc2) %v(Gxxx_int1) xfer_Gxxx + .model xfer_Gxxx pwl(x_array=[x0 x1 x2] + y_array=[y0 y1 y2] + input_domain=0.001 fraction=TRUE) + */ if ((str_ptr = search_plain_identifier(curr_line, "table")) != NULL) { char *expression, *firstno, *secondno; char *m_ptr, *m_token; @@ -9604,6 +9705,7 @@ static int inp_poly_2g6_compat(struct card* deck) { continue; if (ciprefix("table", curr_line)) continue; + /* for TABLE with 4 nodes see below */ if (ciprefix("laplace", curr_line)) continue; if (ciprefix("cur", curr_line)) @@ -9635,6 +9737,9 @@ static int inp_poly_2g6_compat(struct card* deck) { controlled_exit(EXIT_BAD); return 1; } + /* If we now have 'table', just return */ + if (ciprefix("table", curr_line)) + continue; /* The next token may be a simple text token or an expression enclosed in brackets */ if (*curr_line == '{') { From 63d5e94b9460ac886f0f5d91efdf63c52de3ed99 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 21 Sep 2025 11:55:39 +0200 Subject: [PATCH 027/161] Improve the error message by naming the port --- src/xspice/mif/mif_inp2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/xspice/mif/mif_inp2.c b/src/xspice/mif/mif_inp2.c index 34aba5825..f6b170894 100644 --- a/src/xspice/mif/mif_inp2.c +++ b/src/xspice/mif/mif_inp2.c @@ -769,7 +769,9 @@ MIFget_port_type( } if(! found_type) { - LITERR("Port type is invalid"); + char mesg[32]; + snprintf(mesg, 31, "Port type %s is invalid", temp); + LITERR(mesg); *status = MIF_ERROR; } else { From 65fc0ad8a61be54cced0ca8fc216fce2ce3061de Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 21 Sep 2025 15:52:51 +0200 Subject: [PATCH 028/161] Add analog code model astate. It reports the previous state (delayed by 1 to 3 time steps) of the input node. Single or differential voltage or current. --- examples/xspice/various/astate.cir | 23 +++ examples/xspice/various/astate_pulse.cir | 20 +++ src/xspice/icm/analog/astate/cfunc.mod | 188 +++++++++++++++++++++++ src/xspice/icm/analog/astate/ifspec.ifs | 58 +++++++ src/xspice/icm/analog/modpath.lst | 1 + visualc/xspice/analog.vcxproj | 4 + 6 files changed, 294 insertions(+) create mode 100644 examples/xspice/various/astate.cir create mode 100644 examples/xspice/various/astate_pulse.cir create mode 100644 src/xspice/icm/analog/astate/cfunc.mod create mode 100644 src/xspice/icm/analog/astate/ifspec.ifs diff --git a/examples/xspice/various/astate.cir b/examples/xspice/various/astate.cir new file mode 100644 index 000000000..ae4ec0070 --- /dev/null +++ b/examples/xspice/various/astate.cir @@ -0,0 +1,23 @@ +state test +* transient simulation only +* 0 <= astate_no <= 3 +* out delayed by astate_no accepted time steps +* current or voltage in- and outputs + +Vsin1 in 0 SIN (0 1.5 1k) +Rin in 0 1.5 + +astate1 in out newstate +.model newstate astate(astate_no=2) + +astate2 %vnam(Vsin1) %id(out2+ 0) newstate2 +.model newstate2 astate(astate_no=3) +R2 out2+ 0 0.9 + +.control +tran 10u 2m +set xbrushwidth=2 +plot v(in) v(out) v(out2+) +.endc + +.end diff --git a/examples/xspice/various/astate_pulse.cir b/examples/xspice/various/astate_pulse.cir new file mode 100644 index 000000000..fba10b904 --- /dev/null +++ b/examples/xspice/various/astate_pulse.cir @@ -0,0 +1,20 @@ +state test +* transient simulation only +* 0 <= astate_no <= 3 +* out delayed by astate_no accepted time steps +* current or voltage in- and outputs + + +Iin iin imeas pulse (1 3 0 2u 2u 198u 400u) +Vmeas imeas 0 0 +astate3 %i(iin) %i(iout) newstate3 +.model newstate3 astate(astate_no=3) +R3 iout 0 0.9 + +.control +tran 100n 1m +set xbrushwidth=2 +plot i(Vmeas) v(iout) +.endc + +.end diff --git a/src/xspice/icm/analog/astate/cfunc.mod b/src/xspice/icm/analog/astate/cfunc.mod new file mode 100644 index 000000000..cf987bb47 --- /dev/null +++ b/src/xspice/icm/analog/astate/cfunc.mod @@ -0,0 +1,188 @@ +/*.......1.........2.........3.........4.........5.........6.........7.........8 +================================================================================ + +FILE astate/cfunc.mod + +3-clause BSD + +Copyright 2025 +The ngspice team + +AUTHORS + + 20 September 2025 Holger Vogt + + +MODIFICATIONS + + + +SUMMARY + + This file contains the functional description of the analog + state code model. + + +INTERFACES + + FILE ROUTINE CALLED + + + +REFERENCED FILES + + Inputs from and outputs to ARGS structure. + + +NON-STANDARD FEATURES + + NONE + +===============================================================================*/ + +/*=== INCLUDE FILES ====================*/ + +#include + + +/*=== CONSTANTS ========================*/ + + + + +/*=== MACROS ===========================*/ + + + + +/*=== LOCAL VARIABLES & TYPEDEFS =======*/ + +typedef struct { + double state1; /* first state value */ + double state2; /* second state value */ + double state3; /* third state value */ + double outval; /* output value */ + double xval1; /* first x value */ + double xval2; /* second x value */ + double xval3; /* third x value */ +} stLocal_Data_t; + + + + + +/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ + +static void cm_astate_callback(ARGS, Mif_Callback_Reason_t reason); + +/*=== CM_STATE ROUTINE ===*/ + +void cm_astate(ARGS) +{ + int state_number = 0; + double outval = 0.0; + + stLocal_Data_t *loc; /* Pointer to local static data, not to be included + in the state vector */ + + + if (ANALYSIS != MIF_AC) { /**** only Transient Analysis and dc ****/ + + /** INIT: allocate storage **/ + + if (INIT==1) { + + CALLBACK = cm_astate_callback; + + /*** allocate static storage for *loc ***/ + if ((loc = (stLocal_Data_t *) (STATIC_VAR(locdata) = calloc(1, + sizeof(stLocal_Data_t)))) == (stLocal_Data_t *) NULL) { + cm_message_send("Unable to allocate Local_Data_t " + "in cm_astate()"); + return; + } + loc->state1 = 0; + loc->state2 = 0; + loc->state3 = 0; + loc->outval = 0; + loc->xval1 = 0; + loc->xval2 = 0; + loc->xval3 = 0; + } + + /* retrieve previous values */ + + loc = STATIC_VAR (locdata); + + state_number = PARAM(astate_no); + + if (state_number == 0) { + OUTPUT(out) = INPUT(in); + return; + } + + if (TIME == loc->xval1) { + switch(state_number) { + case 1: + loc->outval = loc->state1; + break; + case 2: + loc->outval = loc->state2; + break; + case 3: + loc->outval = loc->state3; + break; + default: + loc->outval = INPUT(in); + break; + } + } + else if (TIME > loc->xval1) { + loc->state3 = loc->state2; + loc->state2 = loc->state1; + loc->state1 = INPUT(in); + + loc->xval3 = loc->xval2; + loc->xval2 = loc->xval1; + loc->xval1 = TIME; + } + /* initial time iteration */ + else if (TIME == 0.0) { + loc->state1 = loc->outval = INPUT(in); + loc->xval1 = 0.0; + } + /* time step rejected ? */ + else if (TIME < loc->xval1){ + loc->state1 = INPUT(in); + loc->xval1 = TIME; + } + /* output */ + if (ANALYSIS == MIF_TRAN) { + OUTPUT(out) = loc->outval; + } + else { /* dc */ + OUTPUT(out) = INPUT(in); + } + } + else { + OUTPUT(out) = INPUT(in); + } +} + +/* free the memory created locally */ +static void cm_astate_callback(ARGS, Mif_Callback_Reason_t reason) +{ + switch (reason) { + case MIF_CB_DESTROY: { + stLocal_Data_t *loc = (stLocal_Data_t *) STATIC_VAR(locdata); + if (loc == (stLocal_Data_t *) NULL) { + break; + } + + free(loc); + + STATIC_VAR(locdata) = NULL; + break; + } + } +} /* end of function cm_astate_callback */ diff --git a/src/xspice/icm/analog/astate/ifspec.ifs b/src/xspice/icm/analog/astate/ifspec.ifs new file mode 100644 index 000000000..7e11d8311 --- /dev/null +++ b/src/xspice/icm/analog/astate/ifspec.ifs @@ -0,0 +1,58 @@ +/*.......1.........2.........3.........4.........5.........6.........7.........8 +================================================================================ + +------------------------------------------------------------------------- + Copyright 2025 + The ngspice team + 3 - Clause BSD license + (see COPYING or https://opensource.org/licenses/BSD-3-Clause) +------------------------------------------------------------------------- + +AUTHORS + + 20 September 2025 Holger Vogt + + +SUMMARY + + This file contains the interface specification file for the + astate code model. + +===============================================================================*/ + +NAME_TABLE: + +C_Function_Name: cm_astate +Spice_Model_Name: astate +Description: "analog state return" + + +PORT_TABLE: + +Port_Name: in out +Description: "input" "output" +Direction: in out +Default_Type: v v +Allowed_Types: [v,vd,vnam,i,id] [v,vd,i,id] +Vector: no no +Vector_Bounds: - - +Null_Allowed: no no + + +PARAMETER_TABLE: + +Parameter_Name: astate_no +Description: "state to be returned" +Data_Type: int +Default_Value: 1 +Limits: [0 3] +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +STATIC_VAR_TABLE: + +Static_Var_Name: locdata +Description: "local static data" +Data_Type: pointer diff --git a/src/xspice/icm/analog/modpath.lst b/src/xspice/icm/analog/modpath.lst index acf24b33f..1c6f1595d 100644 --- a/src/xspice/icm/analog/modpath.lst +++ b/src/xspice/icm/analog/modpath.lst @@ -20,3 +20,4 @@ triangle file_source delay pwlts +astate diff --git a/visualc/xspice/analog.vcxproj b/visualc/xspice/analog.vcxproj index 57074ec99..4c81fd959 100644 --- a/visualc/xspice/analog.vcxproj +++ b/visualc/xspice/analog.vcxproj @@ -244,6 +244,8 @@ + + @@ -291,6 +293,8 @@ + + From 7ea0ee9714f593242afbd6b38dee3868de9a3076 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 21 Sep 2025 16:23:35 +0200 Subject: [PATCH 029/161] Add short description of code model --- src/xspice/icm/analog/astate/cfunc.mod | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/xspice/icm/analog/astate/cfunc.mod b/src/xspice/icm/analog/astate/cfunc.mod index cf987bb47..58028cedb 100644 --- a/src/xspice/icm/analog/astate/cfunc.mod +++ b/src/xspice/icm/analog/astate/cfunc.mod @@ -21,6 +21,9 @@ SUMMARY This file contains the functional description of the analog state code model. + It takes an input node, stores its value (voltage or current) + during the last three time steps and returns a value at the output, + delayed by 0 to 3 steps, depending on the model parameter astate_no. INTERFACES From e69498353679c608a678cc43c95ef4bc559e48ec Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Sun, 21 Sep 2025 09:32:06 -0700 Subject: [PATCH 030/161] Fix memory leaks in INPpas4 and get_number_terminals found using paranoia_parallel. --- src/frontend/inpcom.c | 18 +++++++++++++----- src/spicelib/parser/inppas4.c | 1 + 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 9c354356e..ff693b115 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -5171,7 +5171,6 @@ int get_number_terminals(char *c) { int i, j, k; char *inst; - char *name[12]; bool area_found = FALSE; if (!c) @@ -5277,20 +5276,26 @@ int get_number_terminals(char *c) * */ /* 12 tokens maximum */ { + char *name[12]; char* cc, * ccfree; + (void) memset(name, 0, sizeof(name)); cc = copy(c); /* required to make m= 1 a single token m=1 */ ccfree = cc = inp_remove_ws(cc); for (i = j = 0; (i < 12) && (*cc != '\0'); ++i) { name[i] = gettok_instance(&cc); + if (!name[i] || name[i][0] == '\0') { + continue; + } if (search_plain_identifier(name[i], "off")) { j++; } #ifdef CIDER - if (search_plain_identifier(name[i], "save") || - search_plain_identifier(name[i], "print")) { + if (search_plain_identifier(name[i], "save")) { + j++; + } else if (search_plain_identifier(name[i], "print")) { j++; } #endif @@ -5320,8 +5325,11 @@ int get_number_terminals(char *c) if (only_digits && (strchr(name[k - 1], ',') == NULL)) area_found = TRUE; } - for (k = i; k >= 0; k--) - tfree(name[k]); + for (k = 0; k < 12; k++) { + if (name[k]) { + tfree(name[k]); + } + } if (area_found) { return i - j - 2; } diff --git a/src/spicelib/parser/inppas4.c b/src/spicelib/parser/inppas4.c index f053435d8..dd6096577 100644 --- a/src/spicelib/parser/inppas4.c +++ b/src/spicelib/parser/inppas4.c @@ -58,6 +58,7 @@ void INPpas4(CKTcircuit *ckt, INPtables *tab) char* devname = tprintf("capac%dshunt", nn); (*(ft_sim->newInstance))(ckt, tab->defCmod, &fast, devname); + txfree(devname); /* the top node, second node is gnd automatically */ (*(ft_sim->bindNode))(ckt, fast, 1, node); From 8e1ba4d9e22b8e0c52a42e54c2d3fdb9a241ab30 Mon Sep 17 00:00:00 2001 From: dwarning Date: Tue, 23 Sep 2025 16:47:52 +0200 Subject: [PATCH 031/161] count level=3 model poly and metal capacitance in charge calculation --- src/spicelib/devices/dio/dioload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spicelib/devices/dio/dioload.c b/src/spicelib/devices/dio/dioload.c index 65a88b82a..9c3aa3f00 100644 --- a/src/spicelib/devices/dio/dioload.c +++ b/src/spicelib/devices/dio/dioload.c @@ -435,7 +435,7 @@ next1: diffcharge = here->DIOtTransitTime*cd; *(ckt->CKTstate0 + here->DIOcapCharge) = - diffcharge + deplcharge + deplchargeSW; + diffcharge + deplcharge + deplchargeSW + (here->DIOcmetal + here->DIOcpoly)*vd; diffcap = here->DIOtTransitTime*gd; From 3286651aca2ffcd47324c5970743e71fc185e493 Mon Sep 17 00:00:00 2001 From: dwarning Date: Tue, 23 Sep 2025 17:02:42 +0200 Subject: [PATCH 032/161] correct xoi and xom defaults to Angstrom and clarify comments --- src/spicelib/devices/dio/diompar.c | 4 ++-- src/spicelib/devices/dio/diosetup.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/spicelib/devices/dio/diompar.c b/src/spicelib/devices/dio/diompar.c index 8c06b4bfc..e68052eb0 100644 --- a/src/spicelib/devices/dio/diompar.c +++ b/src/spicelib/devices/dio/diompar.c @@ -263,11 +263,11 @@ DIOmParam(int param, IFvalue *value, GENmodel *inModel) model->DIOwidthPolyGiven = TRUE; break; case DIO_MOD_XOM: - model->DIOmetalOxideThick = value->rValue * 1e-10; /* m */ + model->DIOmetalOxideThick = value->rValue * 1e-10; /* Angstrom -> m */ model->DIOmetalOxideThickGiven = TRUE; break; case DIO_MOD_XOI: - model->DIOpolyOxideThick = value->rValue * 1e-10; /* m */ + model->DIOpolyOxideThick = value->rValue * 1e-10; /* Angstrom -> m */ model->DIOpolyOxideThickGiven = TRUE; break; case DIO_MOD_XM: diff --git a/src/spicelib/devices/dio/diosetup.c b/src/spicelib/devices/dio/diosetup.c index d67449313..98ced6e01 100644 --- a/src/spicelib/devices/dio/diosetup.c +++ b/src/spicelib/devices/dio/diosetup.c @@ -259,10 +259,10 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) model->DIOwidthPoly = 0.0; } if(!model->DIOmetalOxideThickGiven) { - model->DIOmetalOxideThick = 1e-06; /* m */ + model->DIOmetalOxideThick = 1e4; /* 10k Angstrom */ } if(!model->DIOpolyOxideThickGiven) { - model->DIOpolyOxideThick = 1e-06; /* m */ + model->DIOpolyOxideThick = 1e4; /* 10k Angstrom */ } if(!model->DIOmetalMaskOffsetGiven) { model->DIOmetalMaskOffset = 0.0; From 7d4cf5487d31fd5d3e9e4bd342f8ef55695f8abc Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 23 Sep 2025 22:57:48 +0200 Subject: [PATCH 033/161] Typo --- src/spicelib/devices/bsim4v6/b4v6check.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spicelib/devices/bsim4v6/b4v6check.c b/src/spicelib/devices/bsim4v6/b4v6check.c index d78af90be..5c01820a6 100644 --- a/src/spicelib/devices/bsim4v6/b4v6check.c +++ b/src/spicelib/devices/bsim4v6/b4v6check.c @@ -55,7 +55,7 @@ CKTcircuit *ckt) wl = wlstart = TMALLOC(wordlist, 1); wl->wl_prev = NULL; wl->wl_next = NULL; - wl->wl_word = tprintf("\nChecking parameters for BSIM 4.5 model %s\n", model->BSIM4v6modName); + wl->wl_word = tprintf("\nChecking parameters for BSIM 4.6 model %s\n", model->BSIM4v6modName); if ((here->BSIM4v6rgateMod == 2) || (here->BSIM4v6rgateMod == 3)) { if ((here->BSIM4v6trnqsMod == 1) || (here->BSIM4v6acnqsMod == 1)) { From 766c8d15e235b2936302acecf3b19600fc768d7b Mon Sep 17 00:00:00 2001 From: dwarning Date: Thu, 25 Sep 2025 17:09:33 +0200 Subject: [PATCH 034/161] correct init state vector for qth integration --- src/spicelib/devices/dio/dioload.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/spicelib/devices/dio/dioload.c b/src/spicelib/devices/dio/dioload.c index 9c3aa3f00..e8f1dd755 100644 --- a/src/spicelib/devices/dio/dioload.c +++ b/src/spicelib/devices/dio/dioload.c @@ -492,6 +492,10 @@ next1: } if (selfheat) { + if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->DIOqth) = + *(ckt->CKTstate0 + here->DIOqth); + } error = NIintegrate(ckt, &gcTt, &ceqqth, model->DIOcth0, here->DIOqth); if (error) return(error); if (ckt->CKTmode & MODEINITTRAN) { From 71614dba3a4e1a982f89f238247b940eabe5d0c5 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Sat, 27 Sep 2025 12:16:39 -0700 Subject: [PATCH 035/161] Add a correction to the previous change of inppas4.c, which freed devname and left instance name pointers in DEVnameHash pointing at freed memory. This commit adds the devname string to the symbol tables which are eventually cleared by INPtabEnd. Also, if a capacitor in the spice netlist has the same name (unlikely, but possible) as a shunt capacitor, then no shunt is created, and a warning is issued. --- src/spicelib/parser/inppas4.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/spicelib/parser/inppas4.c b/src/spicelib/parser/inppas4.c index dd6096577..d30283c8b 100644 --- a/src/spicelib/parser/inppas4.c +++ b/src/spicelib/parser/inppas4.c @@ -57,8 +57,24 @@ void INPpas4(CKTcircuit *ckt, INPtables *tab) int nn = node->number; char* devname = tprintf("capac%dshunt", nn); - (*(ft_sim->newInstance))(ckt, tab->defCmod, &fast, devname); - txfree(devname); + fast = (*(ft_sim->findInstance))(ckt, devname); + if (fast) { + fprintf(stderr, + "WARNING: non-cshunt instance %s already exists\n", + devname); + tfree(devname); + continue; + } + error = (*(ft_sim->newInstance))(ckt, tab->defCmod, &fast, devname); + if (error) { + fprintf(stderr, + "ERROR: cshunt newInstance status %d devname %s\n", + error, devname); + tfree(devname); + continue; + } + /* devname is eventually freed when INPtabEnd is called */ + INPinsert(&devname, tab); /* the top node, second node is gnd automatically */ (*(ft_sim->bindNode))(ckt, fast, 1, node); From a99ff45eaf0267b8b6b6ea8cb71a2206bdc11bb4 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Sun, 28 Sep 2025 11:59:17 -0700 Subject: [PATCH 036/161] Update and clarify the comments at the top of udevices.c, which should make it easier when someone in the future has to make changes. --- src/frontend/udevices.c | 63 +++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/src/frontend/udevices.c b/src/frontend/udevices.c index fe406cb7c..c2f14ec47 100644 --- a/src/frontend/udevices.c +++ b/src/frontend/udevices.c @@ -4,10 +4,16 @@ Notes: To translate Pspice U* devices in a subcircuit containing U* instance and Pspice .model cards, two passes through the subcircuit are necessary. The first pass is to translate the timing models from - the .model cards. This timing delay information is stored. The second - pass is for translating the U* instance cards to generate equivalent - Xspice digital device instances and their timing delay .model cards - using the previously stored delays. + the .model cards. This timing delay information is stored. Also, during + the first pass each U* instance in the subcircuit is checked to see + if it can be translated. + + The second pass is for translating the U* instance cards to generate + equivalent Xspice digital device instances and their timing delay + .model cards using the previously stored delays. + + The two pass algorithm is implemented by the function u_instances() + in frontend/inpcompat.c. Some limitations are: No support for CONSTRAINT, RAM, ROM, STIM, PLAs. @@ -21,24 +27,45 @@ f_logicexp and f_pindly. First pass through a subcircuit. Call initialize_udevice() and read the - .model cards by calling u_process_model_line() (or similar) for each card, - The delays for the different types (ugate, utgate, ueff, ugff, udly) are stored - by get_delays_...() and add_delays_to_model_xlator(). Also, during the - first pass, check that each U* instance can be translated to Xspice. + .model cards by calling u_process_model_line() for each model card. + The delays for the different types (ugate, utgate, ueff, ugff, udly) + are stored by: + get_delays_ugate(), get_delays_utgate(), get_delays_ueff(), + get_delays_ugff(), get_delays_udly(). + + Also, during the first pass, verify that each U* instance can be translated + to Xspice by calling u_check_instance(). If there are any .model or U* instance cards that cannot be processed in the .subckt, then there is no second pass and the .subckt is skipped. Second pass through a subcircuit. To translate each U* instance call - u_process_instance_line() (or similar). This calls translate_...() - functions for gates, tristate, flip-flops and latches. translate_...() - calls add_..._inout_timing_model() to parse the U* card, and then calls - gen_..._instance(). Creating new cards to replace the U* and .model - cards is done by calling replacement_udevice_cards(), which returns a - list of new cards. The list of cards is then to be inserted after the - .subckt card and before the .ends card. This occurs in the driver - function u_instances() in frontend/inpcom.c. - Finally, call cleanup_udevice() before repeating the sequence for - another subcircuit. + u_process_instance(). This calls: + translate_gate(), translate_ff_latch(), translate_pull(), + translate_dlyline() + functions for gates, tristate, flip-flops, latches etc. + + The translate functions call the corresponding: + add_gate_inout_timing_model(), add_array_inout_timing_model(), + add_compound_inout_timing_model(), add_dff_inout_timing_model(), + add_dltch_inout_timing_model(), add_jkff_inout_timing_model(), + add_srff_inout_timing_model() + when parsing the U* card to add inputs, outputs, and timing model + to an Xspice instance. + + Finally, the translate functions call: + gen_gate_instance(), gen_compound_instance(), gen_dff_instance(), + gen_jkff_instance(), gen_dltch_instance(), gen_srff_instance(). + + Each gen_..._instance() creates new cards to replace the U* and .model + cards. + + If all the U* instances and timing models in the subcircuit can be + translated, the driver function u_instances() (in inpcompat.c) will call + replacement_udevice_cards(), + which returns a list of new cards. The list of cards is then inserted + after the .subckt card and before the .ends card. + Finally, the driver calls cleanup_udevice() before repeating the sequence + for another subcircuit. More explanations are provided below in comments with NOTE. */ From e277c886efdc3c3b3eff8882821ae3478aa9ead1 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 3 Oct 2025 15:45:47 +0200 Subject: [PATCH 037/161] Improve reading the source code sequence by extra comments: While searching for 'Parsing the circuit', the sequence of major functions is revealed. --- src/frontend/inp.c | 16 +++++++++++++--- src/frontend/inpcom.c | 4 ++++ src/frontend/spiceif.c | 20 ++++++++++++++------ src/main.c | 5 ++++- src/spicelib/parser/inppas1.c | 5 ++--- src/winmain.c | 4 +++- 6 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/frontend/inp.c b/src/frontend/inp.c index c12489ef8..b857a1462 100644 --- a/src/frontend/inp.c +++ b/src/frontend/inp.c @@ -530,7 +530,9 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) char *dir_name = ngdirname(filename ? filename : "."); startTime = seconds(); - /* inp_source() called with fp: load from file, */ + /* Parsing the circuit 2. + This is the next major step: + inp_source() called with fp: load circuit netlist from file, */ /* called with *fp == NULL and intfile: we want to load circuit from circarray */ if (fp || intfile) { deck = inp_readall(fp, dir_name, filename, comfile, intfile, &expr_w_temper); @@ -931,7 +933,9 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) } } - /* Now expand subcircuit macros and substitute numparams.*/ + /* Parsing the circuit 4. + This is the next major step: + Expand subcircuit macros and substitute numparams.*/ if (!cp_getvar("nosubckt", CP_BOOL, NULL, 0)) if ((deck->nextcard = inp_subcktexpand(deck->nextcard)) == NULL) { line_free(realdeck, TRUE); @@ -1084,7 +1088,9 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) if (newcompat.hs || newcompat.spe) rem_unused_mos_models(deck->nextcard); #endif - /* now load deck into ft_curckt -- the current circuit. */ + /* Parsing the circuit 5. + This is the next major step: + load deck into ft_curckt -- the current circuit. */ if(inp_dodeck(deck, tt, wl_first, FALSE, options, filename) != 0) return 1; @@ -1411,6 +1417,10 @@ inp_dodeck( *---------------------------------------------------*/ if (!noparse) { startTime = seconds(); + /* Parsing the circuit 6. + This is the next major step: + Input a single deck, and return a pointer to the circuit. + Parse all models and instances */ ckt = if_inpdeck(deck, &tab); ft_curckt->FTEstats->FTESTATnetParseTime = seconds() - startTime; /* if .probe, rename the current measurement node vcurr_ */ diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index ff693b115..0e8367926 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -1054,6 +1054,10 @@ struct card *inp_readall(FILE *fp, const char *dir_name, const char* file_name, /* set the members of the compatibility structure */ set_compat_mode(); + /* Parsing the circuit 3. + This is the next major step: + Reading the netlist line by line, handle .include and .lib, + line continuation and upper/lower casing */ rv = inp_read(fp, 0, dir_name, file_name, comfile, intfile); cc = rv.cc; diff --git a/src/frontend/spiceif.c b/src/frontend/spiceif.c index 2615a5978..9697d7298 100644 --- a/src/frontend/spiceif.c +++ b/src/frontend/spiceif.c @@ -93,8 +93,9 @@ static int finddev(CKTcircuit *ckt, char *name, GENinstance **devptr, GENmodel * /* espice fix integration */ static int finddev_special(CKTcircuit *ckt, char *name, GENinstance **devptr, GENmodel **modptr, int *device_or_model); -/* Input a single deck, and return a pointer to the circuit. */ - +/* Input a single deck, and return a pointer to the circuit. + Parse all models in function INPpas1, instances (devices) in INPpas2, + consider initial conditions (INPpas3), and shunt capacitors (INPpas4). */ CKTcircuit * if_inpdeck(struct card *deck, INPtables **tab) { @@ -162,16 +163,23 @@ if_inpdeck(struct card *deck, INPtables **tab) ft_curckt->ci_curTask = ft_curckt->ci_defTask; - /* Parse the .model lines. Enter the model into the global model table modtab. */ modtab = NULL; modtabhash = NULL; - /* Parse .model lines, put them into 'tab' */ + /* Parsing the circuit 7. + This is the next major step: + Parse the .model lines. + Enter the model into the global model table modtab + and into the corresponding hash table modtabhash. + The role of 'tab' is unclear (not used any more?). */ INPpas1(ckt, deck->nextcard, *tab); - /* store the new model table in the current circuit */ + /* store the new model tables in the current circuit */ ft_curckt->ci_modtab = modtab; ft_curckt->ci_modtabhash = modtabhash; - /* Scan through the instance lines and parse the circuit. */ + /* Parsing the circuit 8. + This is the next major step: + Scan through the instance lines and parse the circuit. + Set up the circuit matrix. */ INPpas2(ckt, deck->nextcard, *tab, ft_curckt->ci_defTask); #ifdef XSPICE if (!Evtcheck_nodes(ckt, *tab)) { diff --git a/src/main.c b/src/main.c index a5a83c011..986714e72 100644 --- a/src/main.c +++ b/src/main.c @@ -1490,7 +1490,10 @@ int main(int argc, char **argv) gotone = FALSE; // Re-use if (tempfile && (!err || !ft_batchmode)) { - /* Copy the input file name for becoming another file search path */ + /* Parsing the circuit 1. + This is the next major step: + Source the input file, then parse the data and create the circuit. + Copy the input file name for becoming another file search path */ if (inp_spsource(tempfile, FALSE, dname, FALSE) != 0) { fprintf(stderr, " Simulation interrupted due to error!\n\n"); if (ft_stricterror || (oflag && !cp_getvar("interactive", CP_BOOL, NULL, 0))) diff --git a/src/spicelib/parser/inppas1.c b/src/spicelib/parser/inppas1.c index b990cadf6..c5048d134 100644 --- a/src/spicelib/parser/inppas1.c +++ b/src/spicelib/parser/inppas1.c @@ -8,9 +8,8 @@ Author: 1985 Thomas L. Quarles #include "inppas1.h" /* - * The first pass of the circuit parser just looks for '.model' lines - */ - + The first pass of the circuit parser just looks for '.model' lines, + and sticks model into model table tab. */ void INPpas1(CKTcircuit *ckt, struct card *deck, INPtables * tab) { struct card *current; diff --git a/src/winmain.c b/src/winmain.c index d380ff753..a851f4242 100644 --- a/src/winmain.c +++ b/src/winmain.c @@ -1340,7 +1340,9 @@ wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR /* Wait until everything is settled */ WaitForIdle(); - /* Go to main() */ + /* Parsing the command line. + This is the next major step: + Go to main() for reading the start command line and preparing the simulator. */ nReturnCode = xmain(argc, argv); THE_END: From 76c4be60ced3f8fc07668c105d1abe967badbf09 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 4 Oct 2025 19:58:22 +0200 Subject: [PATCH 038/161] Add info for line source --- src/xspice/enh/enhtrans.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/xspice/enh/enhtrans.c b/src/xspice/enh/enhtrans.c index 5e2bf8339..2eb23aa2a 100644 --- a/src/xspice/enh/enhtrans.c +++ b/src/xspice/enh/enhtrans.c @@ -124,6 +124,9 @@ ENHtranslate_poly( l1->linenum = d->linenum; l2->linenum = d->linenum; + l1->linesource = copy("internal"); + l2->linesource = copy("internal"); + /* Create the translated cards */ d->error = two2three_translate(d->line, &(l1->line), &(l2->line)); From c4ae3b124339e8c6000cce56280ae74e4dd70c89 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 4 Oct 2025 19:59:19 +0200 Subject: [PATCH 039/161] Improve on truncation when printing out the .model lines during debug-out --- src/frontend/inp.c | 5 ++++- src/frontend/inpcom.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/frontend/inp.c b/src/frontend/inp.c index b857a1462..56951b617 100644 --- a/src/frontend/inp.c +++ b/src/frontend/inp.c @@ -989,8 +989,11 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) continue; /* Only truncated .model lines */ if (ciprefix(".model", tc->line)) { - fprintf(fdo, "%6d %.100s ...\n", + fprintf(fdo, "%6d %.100s ", tc->linenum, tc->line); + if (strlen(tc->line) > 100) + fprintf(fdo, " ... (truncated)"); + fprintf(fdo, "\n"); } else { fprintf(fdo, "%6d %s\n", diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 0e8367926..0c6f5b283 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -1245,8 +1245,11 @@ struct card *inp_readall(FILE *fp, const char *dir_name, const char* file_name, continue; /* Only truncated .model lines */ if (ciprefix(".model", t->line)) { - fprintf(fd, "%6d %.100s ...\n", + fprintf(fd, "%6d %.100s ", t->linenum, t->line); + if (strlen(t->line) > 100) + fprintf(fd, " ... (truncated)"); + fprintf(fd, "\n"); } else { fprintf(fd, "%6d %s\n", From f84a72d1f83c3c4876fdb65ca39fb7274878762b Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 6 Oct 2025 17:07:27 +0200 Subject: [PATCH 040/161] Improve error messages. Towards better locating of errors: Remove entry to avoid false file readings. Still to do: Return correct fline numbers, when reading large PDKs. --- src/frontend/inpcom.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 0c6f5b283..af7e2c0d1 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -1609,11 +1609,8 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name char* tmpstr = copy(nexttok(buffer)); wl_append_word(&sourceinfo, &sourceinfo, tmpstr); - /* Add source of netlist data, for use in verbose error messages. - Set the compatibility mode flag to 1, if pslt is read. */ + /* Set the compatibility mode flag to 1, if pslt is read. */ for (tmpcard = newcard; tmpcard; tmpcard = tmpcard->nextcard) { - /* skip *include */ - tmpcard->linesource = tmpstr; if (compset) tmpcard->compmod = 1; else From 5fcbe3c6df11c7f0d947efdd57262882262b22cd Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 6 Oct 2025 17:30:38 +0200 Subject: [PATCH 041/161] Improve error message: add source type --- src/frontend/inpcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index af7e2c0d1..1f90d2732 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -9042,7 +9042,7 @@ static void inp_check_syntax(struct card *deck) acline = nexttok(acline); if (!acline) { fprintf(stderr, "Error in line %s\n", cut_line); - fprintf(stderr, " Not enough parameters\n"); + fprintf(stderr, " Not enough parameters for %c source\n", *cut_line); fprintf(stderr, " line no. %d from file %s\n", card->linenum_orig, card->linesource); From 68e8f43318285c79c68a2ac766b9614501634f00 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 7 Oct 2025 15:36:27 +0200 Subject: [PATCH 042/161] Re-enable warning note when rusage xxx is not implemented. --- src/frontend/resource.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/resource.c b/src/frontend/resource.c index 2008efc48..47b4ae400 100644 --- a/src/frontend/resource.c +++ b/src/frontend/resource.c @@ -339,9 +339,9 @@ printres(char *name) ft_curckt->ci_ckt->CKTstat->devTimes[i]/(double)(ft_curckt->ci_ckt->CKTstat->devCounts[i]) ); } + yy = TRUE; } - yy = TRUE; - + #ifdef CIDER /* begin cider integration */ if (!name || eq(name, "circuit") || eq(name, "task")) From 87338b0b8a775da54b71f3b6f9b8b6c99f56b9c2 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Wed, 8 Oct 2025 18:19:17 +0100 Subject: [PATCH 043/161] Fix Bug 817 - "Global models are not visible from with subcircuits". Remove code that can miscount the number of nodes to be renamed. --- src/frontend/subckt.c | 188 +++++------------------------------------- 1 file changed, 20 insertions(+), 168 deletions(-) diff --git a/src/frontend/subckt.c b/src/frontend/subckt.c index 4cb7be417..52eb230f5 100644 --- a/src/frontend/subckt.c +++ b/src/frontend/subckt.c @@ -97,11 +97,10 @@ struct bxx_buffer; static void finishLine(struct bxx_buffer *dst, char *src, char *scname); static int settrans(char *formal, int flen, char *actual, const char *subname); static char *gettrans(const char *name, const char *name_end, bool *isglobal); -static int numnodes(const char *line, struct subs *subs, wordlist const *modnames); +static int numnodes(const char *line); static int numdevs(char *s); static wordlist *modtranslate(struct card *deck, char *subname, wordlist *new_modnames); static void devmodtranslate(struct card *deck, char *subname, wordlist * const orig_modnames); -static int inp_numnodes(char c); /* hash table to store the global nodes * For now its use is limited to avoid double entries in global_nodes[] */ @@ -1384,9 +1383,11 @@ translate(struct card *deck, char *formal, int flen, char *actual, char *scname, tfree(name); bxx_putc(&buffer, ' '); - /* Next iterate over all nodes (netnames) found and translate them. */ - nnodes = numnodes(c->line, subs, modnames); + /* Next iterate over all nodes (netnames) found and translate them. + * Ignore controlling nodes as they get special treatment for POLY. + */ + nnodes = numnodes(c->line); while (--nnodes >= 0) { name = gettok_node(&s); if (name == NULL) { @@ -1476,13 +1477,7 @@ translate(struct card *deck, char *formal, int flen, char *actual, char *scname, tfree(name); bxx_putc(&buffer, ' '); - /* FIXME anothet hack: if no models found for m devices, set number of nodes to 4 */ - if (!modnames && *(c->line) == 'm') - nnodes = get_number_terminals(c->line); - else if (*(c->line) == 'n') - nnodes = get_number_terminals(c->line); - else - nnodes = numnodes(c->line, subs, modnames); + nnodes = numnodes(c->line); while (--nnodes >= 0) { name = gettok_node(&s); if (name == NULL) { @@ -1692,91 +1687,23 @@ gettrans(const char *name, const char *name_end, bool *isglobal) } -/*-------------------------------------------------------------------*/ -/*-------------------------------------------------------------------*/ +/* Control nodes for E and G sources are not counted as they vary in + * the case of POLY. The count returned by get_number_terminals() includes + * devices for K (mutual inductors) and W (current-controlled switch). + */ + static int -numnodes(const char *line, struct subs *subs, wordlist const *modnames) +numnodes(const char *line) { - /* gtri - comment - wbk - 10/23/90 - Do not modify this routine for */ - /* 'A' type devices since the callers will not know how to find the */ - /* nodes even if they know how many there are. Modify the callers */ - /* instead. */ - /* gtri - end - wbk - 10/23/90 */ - char c; - int n; - - line = skip_ws(line); - - c = tolower_c(*line); - - if (c == 'x') { /* Handle this ourselves. */ - const char *xname_e = skip_back_ws(strchr(line, '\0'), line); - const char *xname = skip_back_non_ws(xname_e, line); - for (; subs; subs = subs->su_next) - if (eq_substr(xname, xname_e, subs->su_name)) - return subs->su_numargs; - /* - * number of nodes not known so far. - * lets count the nodes ourselves, - * assuming `buf' looks like this: - * xname n1 n2 ... nn subname - */ - { - int nodes = -2; - while (*line) { - nodes++; - line = skip_ws(skip_non_ws(line)); - } - return (nodes); - } - } - /* if we use option skywaterpdk, MOS has four nodes. Required if number of devices is large */ - if (ft_skywaterpdk && c == 'm') - return 4; - - n = inp_numnodes(c); - - /* Added this code for variable number of nodes on certain devices. */ - /* The consequence of this code is that the value returned by the */ - /* inp_numnodes(c) call must be regarded as "maximum number of nodes */ - /* for a given device type. */ - /* Paolo Nenzi Jan-2001 */ - - /* If model names equal node names, this code will fail! */ - if ((c == 'm') || (c == 'p') || (c == 'q') || (c == 'd')) { /* IF this is a mos, cpl, bjt or diode */ - char *s = nexttok(line); /* Skip the instance name */ - int gotit = 0; - int i = 0; - - while ((i <= n) && (*s) && !gotit) { - char *t = gettok_node(&s); /* get nodenames . . . */ - const wordlist *wl; - for (wl = modnames; wl; wl = wl->wl_next) - if (model_name_match(t, wl->wl_word)) { - gotit = 1; - break; - } - i++; - tfree(t); - } - - /* Note: node checks must be done on #_of_node-1 because the */ - /* "while" cycle increments the counter even when a model is */ - /* recognized. This code may be better! */ - - if ((i < 4) && ((c == 'm') || (c == 'q'))) { - fprintf(cp_err, "Error: too few nodes for MOS or BJT: %s\n", line); - return (0); - } - if ((i < 5) && (c == 'p')) { - fprintf(cp_err, "Error: too few nodes for CPL: %s\n", line); - return (0); - } - return (i-1); /* compensate the unnecessary increment in the while cycle */ - } else { - /* for all other elements */ - return (n); + switch (*line) { + case 'e': + case 'g': + case 'w': + return 2; + case 'k': + return 0; } + return get_number_terminals((char *)line); } @@ -2286,78 +2213,3 @@ devmodtranslate(struct card *s, char *subname, wordlist * const orig_modnames) bxx_free(&buffer); } - - -/*----------------------------------------------------------------------* - * inp_numnodes returns the maximum number of nodes (netnames) attached - * to the component. - * This is a spice-dependent thing. It should probably go somewhere - * else, but... Note that we pretend that dependent sources and mutual - * inductors have more nodes than they really do... - *----------------------------------------------------------------------*/ -static int -inp_numnodes(char c) -{ - if (isupper_c(c)) - c = tolower_c(c); - switch (c) { - case ' ': - case '\t': - case '.': - case 'x': - case '*': - case '$': - return (0); - - case 'b': - return (2); - case 'c': - return (2); - case 'd': - return (3); - case 'e': - return (2); /* changed from 4 to 2 by SDB on 4.22.2003 to enable POLY */ - case 'f': - return (2); - case 'g': - return (2); /* changed from 4 to 2 by SDB on 4.22.2003 to enable POLY */ - case 'h': - return (2); - case 'i': - return (2); - case 'j': - return (3); - case 'k': - return (0); - case 'l': - return (2); - case 'm': - return (7); /* This means that 7 is the maximun number of nodes */ - case 'o': - return (4); - case 'p': - return (18);/* 16 lines + 2 gnd is the maximum number of nodes for CPL */ - case 'q': - return (5); - case 'r': - return (2); - case 's': - return (4); - case 't': - return (4); - case 'u': - return (3); - case 'v': - return (2); - case 'w': - return (2); /* change 3 to 2 here to fix w bug, NCF 1/31/95 */ - case 'y': - return (4); - case 'z': - return (3); - - default: - fprintf(cp_err, "Warning: unknown device type: %c\n", c); - return (2); - } -} From e4aacf352a0861880c271e19b0e8479a094dae23 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 10 Oct 2025 20:44:21 +0200 Subject: [PATCH 044/161] Add breakpoints to achieve quadratic smoothing. Shift 50%-detection for breakpoints into the INIT section, to do it only once. --- src/xspice/icm/analog/pwlts/cfunc.mod | 57 +++++++++++++++++++-------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/src/xspice/icm/analog/pwlts/cfunc.mod b/src/xspice/icm/analog/pwlts/cfunc.mod index 8aaf26d45..c26cbd89e 100644 --- a/src/xspice/icm/analog/pwlts/cfunc.mod +++ b/src/xspice/icm/analog/pwlts/cfunc.mod @@ -13,6 +13,7 @@ AUTHORS Pwl with time input and smoothing: pwlts 9 Sep 2022 Holger Vogt + 10 Oct 2025 Holger Vogt SUMMARY @@ -211,6 +212,46 @@ void cm_pwlts(ARGS) /* structure holding parms, y[0] = 2. * y[1] - y[2]; y[size - 1] = 2. * y[size - 2] - y[size - 3]; } + + /* See if input_domain is absolute...if so, test against */ + /* breakpoint segments for violation of 50% rule... */ + if (PARAM(fraction) == MIF_FALSE) { + if ( 3 < size ) { + for (i=1; i<(size-2); i++) { + /* Test for overlap...0.999999999 factor is to */ + /* prevent floating point problems with comparison. */ + if ( (test1 = x[i+1] - x[i]) < + (test2 = 0.999999999 * (2.0 * input_domain)) ) { + cm_message_send(limit_error); + } + } + } + } + + /* add permanent breakpoints */ + if (PARAM(fraction) == MIF_FALSE) { + for (i=1; i= dthi) ? dthi : dtlo) * input_domain; + if (x[i] - dt <= 0) + continue; + cm_analog_set_perm_bkpt(x[i] - dt); + cm_analog_set_perm_bkpt(x[i]); + cm_analog_set_perm_bkpt(x[i] + dt); + } + } + /* debug printout for (i = 0; i < size; i++) fprintf(stderr, "%e ", y[i]); @@ -229,22 +270,6 @@ void cm_pwlts(ARGS) /* structure holding parms, } - /* See if input_domain is absolute...if so, test against */ - /* breakpoint segments for violation of 50% rule... */ - if (PARAM(fraction) == MIF_FALSE) { - if ( 3 < size ) { - for (i=1; i<(size-2); i++) { - /* Test for overlap...0.999999999 factor is to */ - /* prevent floating point problems with comparison. */ - if ( (test1 = x[i+1] - x[i]) < - (test2 = 0.999999999 * (2.0 * input_domain)) ) { - cm_message_send(limit_error); - } - } - } - - } - /* Retrieve x_input value as current simulation time. */ x_input = TIME; From 7fe6ab542478939fb1dfff97f762b0ab607e00af Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 15 Oct 2025 17:37:14 +0200 Subject: [PATCH 045/161] Improve error messages. --- src/main.c | 2 +- src/spicelib/analysis/dctran.c | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main.c b/src/main.c index 986714e72..723855c7a 100644 --- a/src/main.c +++ b/src/main.c @@ -1397,7 +1397,7 @@ int main(int argc, char **argv) tpf = smktemp("sp"); tempfile = fopen(tpf, "w+bTD"); if (tempfile == NULL) { - fprintf(stderr, "Could not open a temporary file " + fprintf(stderr, "Error: Could not open a temporary file " "to save and use optional arguments.\n"); sp_shutdown(EXIT_BAD); } diff --git a/src/spicelib/analysis/dctran.c b/src/spicelib/analysis/dctran.c index e83143318..fe208f516 100644 --- a/src/spicelib/analysis/dctran.c +++ b/src/spicelib/analysis/dctran.c @@ -131,6 +131,7 @@ DCtran(CKTcircuit *ckt, int redostep; #endif if(restart || ckt->CKTtime == 0) { + /* set the first step time */ delta=MIN(ckt->CKTfinalTime/100,ckt->CKTstep)/10; #ifdef STEPDEBUG @@ -251,10 +252,10 @@ DCtran(CKTcircuit *ckt, ckt->CKTdcMaxIter); if(converged != 0) { - fprintf(stdout,"\nTransient solution failed -\n"); + fprintf(stderr,"\nError: Finding the operating point for transient simulation failed \n"); CKTncDump(ckt); - fprintf(stdout,"\n"); - fflush(stdout); + fprintf(stderr,"\n"); + fflush(stderr); } else if (ckt->CKTmode & MODEUIC && !ft_ngdebug) { fprintf(stdout,"Operating point simulation skipped by 'uic',\n"); fprintf(stdout," now using transient initial conditions.\n"); @@ -273,6 +274,7 @@ DCtran(CKTcircuit *ckt, fflush(stdout); } + /* return upon failure to converge during op */ if (converged != 0) { SPfrontEnd->OUTendPlot(job->TRANplot); return(converged); @@ -311,7 +313,7 @@ DCtran(CKTcircuit *ckt, for(i=0;i<7;i++) { ckt->CKTdeltaOld[i]=ckt->CKTmaxStep; } - ckt->CKTdelta = delta; + ckt->CKTdelta = delta; /* delta set in line 135 */ #ifdef STEPDEBUG (void)printf("delta initialized to %g\n",ckt->CKTdelta); #endif @@ -983,6 +985,7 @@ resume: SPfrontEnd->OUTendPlot(job->TRANplot); job->TRANplot = NULL; UPDATE_STATS(0); + /* return upon convergence failure */ return(E_TIMESTEP); } } From 827e6ba7fbe465608e053ae742c47a4905232049 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 15 Oct 2025 17:58:10 +0200 Subject: [PATCH 046/161] Add perror() to fopen: more info for user. --- src/frontend/device.c | 1 + src/frontend/inpcom.c | 2 ++ src/frontend/measure.c | 4 +++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/frontend/device.c b/src/frontend/device.c index 0062bbeef..00cb3b881 100644 --- a/src/frontend/device.c +++ b/src/frontend/device.c @@ -1542,6 +1542,7 @@ com_alter_mod(wordlist *wl) if (modfile == NULL) { fprintf(cp_err, "Warning: Could not open file %s, altermod ignored\n", filename); + perror(" Cause: "); tfree(input); tfree(filename); return; diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 1f90d2732..2263b7b82 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -583,6 +583,7 @@ static struct library *read_a_lib(const char *y, const char *dir_name) if (!newfp) { fprintf(cp_err, "Error: Could not open library file %s\n", y); + perror(" Cause: "); return NULL; } @@ -1564,6 +1565,7 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name else fprintf(cp_err, " While reading %s\n", y_resolved); } + perror(" Cause: "); tfree(buffer); /* allocated by readline() above */ controlled_exit(EXIT_FAILURE); } diff --git a/src/frontend/measure.c b/src/frontend/measure.c index b7b6680cc..4efd1d7bf 100644 --- a/src/frontend/measure.c +++ b/src/frontend/measure.c @@ -255,8 +255,10 @@ do_measure( if (cp_getvar("measoutfile", CP_STRING, out_file, sizeof(out_file))) { measout = fopen(out_file, "w"); - if (!measout) + if (!measout) { fprintf(stderr, " Warning: Could not open file %s\n", out_file); + perror(" Cause: "); + } } /* Evaluating the linked list of .meas cards, assembled from the input deck From 9fc4435dcaebb22dfa0a416151d9bd710ce6d21c Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 15 Oct 2025 22:35:04 +0200 Subject: [PATCH 047/161] Update on comments. --- src/spicelib/analysis/dctran.c | 205 ++++++++++++++------------------- 1 file changed, 89 insertions(+), 116 deletions(-) diff --git a/src/spicelib/analysis/dctran.c b/src/spicelib/analysis/dctran.c index fe208f516..731a04631 100644 --- a/src/spicelib/analysis/dctran.c +++ b/src/spicelib/analysis/dctran.c @@ -5,8 +5,7 @@ Modified: 2000 AlansFixes Modified: 2023 XSPICE breakpoint fix for shared ngspice by Vyacheslav Shevchuk **********/ -/* subroutine to do DC TRANSIENT analysis - --- ONLY, unlike spice2 routine with the same name! */ +/* subroutine to do DC TRANSIENT analysis */ #include "ngspice/ngspice.h" #include "ngspice/cktdefs.h" @@ -21,15 +20,12 @@ extern struct dbcomm *dbs; #include "ngspice/ftedebug.h" #ifdef XSPICE -/* gtri - add - wbk - Add headers */ #include "ngspice/miftypes.h" - #include "ngspice/evt.h" #include "ngspice/enh.h" #include "ngspice/mif.h" #include "ngspice/evtproto.h" #include "ngspice/ipctiein.h" -/* gtri - end - wbk - Add headers */ #endif #ifdef CLUSTER @@ -100,13 +96,12 @@ DCtran(CKTcircuit *ckt, int ltra_num; CKTnode *node; #ifdef XSPICE -/* gtri - add - wbk - 12/19/90 - Add IPC stuff */ + /* IPC stuff */ Ipc_Boolean_t ipc_firsttime = IPC_TRUE; Ipc_Boolean_t ipc_secondtime = IPC_FALSE; Ipc_Boolean_t ipc_delta_cut = IPC_FALSE; double ipc_last_time = 0.0; double ipc_last_delta = 0.0; -/* gtri - end - wbk - 12/19/90 - Add IPC stuff */ // Fix for sharedsync olddelta: When DCTran processes // either analog or XSPICE breakpoint, then it subtracts delta from @@ -154,6 +149,8 @@ DCtran(CKTcircuit *ckt, ckt->CKTtimePoints = TMALLOC(double, ckt->CKTtimeListSize); /* end LTRA code addition */ + /* Reset the breakpoint list. + Add breakpoints at 0 time and TSTOP (final) time */ if(ckt->CKTbreaks) FREE(ckt->CKTbreaks); ckt->CKTbreaks = TMALLOC(double, 2); if(ckt->CKTbreaks == NULL) return(E_NOMEM); @@ -166,16 +163,18 @@ DCtran(CKTcircuit *ckt, #endif #ifdef XSPICE -/* gtri - begin - wbk - 12/19/90 - Modify setting of CKTminBreak */ - /* Set to 10 times delmin for ATESSE 1 compatibity */ - if(ckt->CKTminBreak==0) ckt->CKTminBreak = 10.0 * ckt->CKTdelmin; -/* gtri - end - wbk - 12/19/90 - Modify setting of CKTminBreak */ + /* Modify setting of CKTminBreak + Set to 10 times delmin (minimum step time). */ + if(ckt->CKTminBreak == 0) + ckt->CKTminBreak = 10.0 * ckt->CKTdelmin; + #else - if(ckt->CKTminBreak==0) ckt->CKTminBreak=ckt->CKTmaxStep*5e-5; + if(ckt->CKTminBreak == 0) + ckt->CKTminBreak = ckt->CKTmaxStep * 5e-5; #endif #ifdef XSPICE -/* gtri - add - wbk - 12/19/90 - Add IPC stuff and set anal_init and anal_type */ + /* Add IPC stuff and set anal_init and anal_type */ /* Tell the beginPlot routine what mode we're in */ g_ipc.anal_type = IPC_ANAL_TRAN; @@ -183,7 +182,6 @@ DCtran(CKTcircuit *ckt, g_mif_info.circuit.anal_type = MIF_DC; g_mif_info.circuit.anal_init = MIF_TRUE; -/* gtri - end - wbk */ #endif error = CKTnames(ckt,&numNames,&nameList); if(error) return(error); @@ -196,7 +194,7 @@ DCtran(CKTcircuit *ckt, tfree(nameList); if(error) return(error); - /* initialize CKTsoaCheck `warn' counters */ + /* initialize CKTsoaCheck 'warn' counters */ if (ckt->CKTsoaCheck) error = CKTsoaInit(); @@ -225,13 +223,12 @@ DCtran(CKTcircuit *ckt, } #ifdef XSPICE -/* gtri - begin - wbk - set a breakpoint at end of supply ramping time */ - /* must do this after CKTtime set to 0 above */ + /* set a breakpoint at end of supply ramping time. + Must do this after CKTtime is set to 0 above */ if(ckt->enh->ramp.ramptime > 0.0) CKTsetBreak(ckt, ckt->enh->ramp.ramptime); -/* gtri - end - wbk - set a breakpoint at end of supply ramping time */ -/* gtri - begin - wbk - Call EVTop if event-driven instances exist */ + /* Call EVTop if event-driven instances exist */ if(ckt->evt->counts.num_insts != 0) { /* use new DCOP algorithm */ converged = EVTop(ckt, @@ -242,10 +239,9 @@ DCtran(CKTcircuit *ckt, EVTdump(ckt, IPC_ANAL_DCOP, 0.0); EVTop_save(ckt, MIF_FALSE, 0.0); - -/* gtri - end - wbk - Call EVTop if event-driven instances exist */ } else #endif + /* Get operating point for analogue circuit */ converged = CKTop(ckt, (ckt->CKTmode & MODEUIC) | MODETRANOP | MODEINITJCT, (ckt->CKTmode & MODEUIC) | MODETRANOP | MODEINITFLOAT, @@ -280,40 +276,31 @@ DCtran(CKTcircuit *ckt, return(converged); } #ifdef XSPICE -/* gtri - add - wbk - 12/19/90 - Add IPC stuff */ - - /* Send the operating point results for Mspice compatibility */ + /* IPC stuff: Send the operating point results */ if(g_ipc.enabled) { ipc_send_dcop_prefix(); CKTdump(ckt, 0.0, job->TRANplot); ipc_send_dcop_suffix(); } -/* gtri - end - wbk */ - -/* gtri - add - wbk - 12/19/90 - set anal_init and anal_type */ - + /* set anal_init and anal_type */ g_mif_info.circuit.anal_init = MIF_TRUE; /* Tell the code models what mode we're in */ g_mif_info.circuit.anal_type = MIF_TRAN; -/* gtri - end - wbk */ - -/* gtri - begin - wbk - Add Breakpoint stuff */ - + /* Breakpoint stuff */ /* Initialize the temporary breakpoint variables to infinity */ g_mif_info.breakpoint.current = 1.0e30; g_mif_info.breakpoint.last = 1.0e30; - -/* gtri - end - wbk - Add Breakpoint stuff */ #endif ckt->CKTstat->STATtimePts ++; ckt->CKTorder = 1; + /* Initialze CKTdeltaOld with maximum value */ for(i=0;i<7;i++) { ckt->CKTdeltaOld[i]=ckt->CKTmaxStep; } - ckt->CKTdelta = delta; /* delta set in line 135 */ + ckt->CKTdelta = delta; /* delta set in line 130 */ #ifdef STEPDEBUG (void)printf("delta initialized to %g\n",ckt->CKTdelta); #endif @@ -339,9 +326,9 @@ DCtran(CKTcircuit *ckt, ckt->CKTorder = save2; } #endif - - ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODETRAN | MODEINITTRAN; /* modeinittran set here */ + ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODETRAN | MODEINITTRAN; + /* Reset the gear variable coefficient matrix. */ ckt->CKTag[0]=ckt->CKTag[1]=0; if (ckt->CKTstate1 && ckt->CKTstate0) { memcpy(ckt->CKTstate1, ckt->CKTstate0, @@ -360,14 +347,16 @@ DCtran(CKTcircuit *ckt, #ifdef CLUSTER CLUsetup(ckt); #endif + /* End of (restart || ckt->CKTtime == 0) */ } else { - /* saj As traninit resets CKTmode */ + /* traninit resets CKTmode */ ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODETRAN | MODEINITPRED; - /* saj */ + INIT_STATS(); - if(ckt->CKTminBreak==0) ckt->CKTminBreak=ckt->CKTmaxStep*5e-5; + if(ckt->CKTminBreak == 0) + ckt->CKTminBreak = ckt->CKTmaxStep * 5e-5; firsttime=0; - /* To get rawfile working saj*/ + /* To get rawfile working */ error = SPfrontEnd->OUTpBeginPlot (NULL, NULL, NULL, NULL, 0, @@ -377,8 +366,7 @@ DCtran(CKTcircuit *ckt, fprintf(stderr, "Couldn't relink rawfile\n"); return error; } - /* end saj*/ - goto resume; + goto resume; /* line 517 */ } /* 650 */ @@ -403,7 +391,8 @@ DCtran(CKTcircuit *ckt, error = CKTaccept(ckt); /* check if current breakpoint is outdated; if so, clear */ - if (ckt->CKTtime > ckt->CKTbreaks[0]) CKTclrBreak(ckt); + if (ckt->CKTtime > ckt->CKTbreaks[0]) + CKTclrBreak(ckt); if (ckt->CKTsoaCheck) error = CKTsoaCheck(ckt); @@ -432,8 +421,8 @@ DCtran(CKTcircuit *ckt, return(error); } #ifdef XSPICE -/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */ + /* Send IPC stuff */ if ((g_ipc.enabled) || wantevtdata) { /* Send event-driven results */ @@ -477,8 +466,8 @@ DCtran(CKTcircuit *ckt, g_ipc.last_time = ckt->CKTtime; } + /* End of Send IPC stuff*/ } else -/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */ #endif #ifdef CLUSTER CLUoutput(ckt); @@ -487,15 +476,14 @@ DCtran(CKTcircuit *ckt, || (!(ckt->CKTmode&MODEUIC) && ckt->CKTtime >= ckt->CKTinitTime)) CKTdump(ckt, ckt->CKTtime, job->TRANplot); #ifdef XSPICE -/* gtri - begin - wbk - Update event queues/data for accepted timepoint */ - /* Note: this must be done AFTER sending results to SI so it can't */ - /* go next to CKTaccept() above */ + /* Update event queues/data for accepted timepoint */ + /* Note: this must be done AFTER sending results to SI so it can't + go next to CKTaccept() above */ if(ckt->evt->counts.num_insts > 0) EVTaccept(ckt, ckt->CKTtime); -/* gtri - end - wbk - Update event queues/data for accepted timepoint */ #endif ckt->CKTstat->STAToldIter = ckt->CKTstat->STATnumIter; - /* check for the end of the tran simulation, either by< stop time given, + /* Check for the end of the tran simulation, either by stop time given, or final time has been reached. */ if (have_autostop) /* time consuming autostop check only, when variable 'autostop' has been set @@ -518,7 +506,7 @@ DCtran(CKTcircuit *ckt, if (flag_autostop) fprintf(stdout, "\nNote: Autostop after %e s, all measurement conditions are fulfilled.\n", ckt->CKTtime); - /* Final return from tran*/ + /* Final return from tran upon success */ return(OK); } if(SPfrontEnd->IFpauseTest()) { @@ -556,14 +544,12 @@ resume: #endif - /* are we at a breakpoint, or indistinguishably close? */ - /* if ((ckt->CKTtime == ckt->CKTbreaks[0]) || (ckt->CKTbreaks[0] - */ + /* Are we at a breakpoint, or indistinguishably close? */ if ( AlmostEqualUlps( ckt->CKTtime, ckt->CKTbreaks[0], 100 ) || ckt->CKTbreaks[0] - ckt->CKTtime <= ckt->CKTdelmin) { - /* first timepoint after a breakpoint - cut integration order */ - /* and limit timestep to .1 times minimum of time to next breakpoint, - * and previous timestep - */ + /* First timepoint after a breakpoint: cut integration order + and limit timestep to .1 times minimum of time to next breakpoint, + and previous timestep. */ ckt->CKTorder = 1; #ifdef STEPDEBUG if( (ckt->CKTdelta > .1*ckt->CKTsaveDelta) || @@ -612,11 +598,10 @@ resume: #ifdef XSPICE -/* gtri - begin - wbk - Add Breakpoint stuff */ - + /* More Breakpoint stuff */ if(ckt->CKTtime + ckt->CKTdelta >= g_mif_info.breakpoint.current) { - /* If next time > temporary breakpoint, force it to the breakpoint */ - /* And mark that timestep was set by temporary breakpoint */ + /* If next time > temporary breakpoint, force it to the breakpoint, + and mark that timestep was set by temporary breakpoint */ ckt->CKTsaveDelta = ckt->CKTdelta; ckt->CKTdelta = g_mif_info.breakpoint.current - ckt->CKTtime; g_mif_info.breakpoint.last = ckt->CKTtime + ckt->CKTdelta; @@ -625,12 +610,8 @@ resume: g_mif_info.breakpoint.last = 1.0e30; } -/* gtri - end - wbk - Add Breakpoint stuff */ - -/* gtri - begin - wbk - Modify Breakpoint stuff */ /* Throw out any permanent breakpoint with time <= current time or in the - * very near future, unless it the final stop break. - */ + very near future, unless it is the final stop break. */ #ifdef STEPDEBUG printf(" brk_pt: %g ckt_time: %g ckt_min_break: %g\n", ckt->CKTbreaks[0], ckt->CKTtime, ckt->CKTminBreak); @@ -654,8 +635,6 @@ resume: ckt->CKTdelta = ckt->CKTbreaks[0] - ckt->CKTtime; } -/* gtri - end - wbk - Modify Breakpoint stuff */ - #ifdef SHARED_MODULE /* Either directly go to next time step, or modify ckt->CKTdelta depending on synchronization requirements. sharedsync() returns 0. */ @@ -663,17 +642,16 @@ resume: ckt->CKTdelmin, 0, &ckt->CKTstat->STATrejected, 0); #endif -/* gtri - begin - wbk - Do event solution */ - + /* Do event solution */ if(ckt->evt->counts.num_insts > 0) { - /* if time = 0 and op_alternate was specified as false during */ - /* dcop analysis, call any changed instances to let them */ - /* post their outputs with their associated delays */ + /* If time = 0 and op_alternate was specified as false during + dcop analysis, call any changed instances to let them + post their outputs with their associated delays */ if((ckt->CKTtime == 0.0) && (! ckt->evt->options.op_alternate)) EVTiter(ckt); - /* while there are events on the queue with event time <= next */ + /* While there are events on the queue with event time <= next */ /* projected analog time, process them */ while((g_mif_info.circuit.evt_step = EVTnext_time(ckt)) <= (ckt->CKTtime + ckt->CKTdelta)) { @@ -685,14 +663,14 @@ resume: EVTdequeue(ckt, g_mif_info.circuit.evt_step); EVTiter(ckt); - /* If any instances have forced an earlier */ - /* next analog time, cut the delta */ + /* If any instances have forced an earlier + next analog time, cut the delta */ if(ckt->CKTbreaks[0] < g_mif_info.breakpoint.current) if(ckt->CKTbreaks[0] > ckt->CKTtime + ckt->CKTminBreak) g_mif_info.breakpoint.current = ckt->CKTbreaks[0]; if(g_mif_info.breakpoint.current < ckt->CKTtime + ckt->CKTdelta) { - /* Breakpoint must be > last accepted timepoint */ - /* and >= current event time */ + /* Breakpoint must be > last accepted timepoint + and >= current event time */ if(g_mif_info.breakpoint.current > ckt->CKTtime + ckt->CKTminBreak && g_mif_info.breakpoint.current >= g_mif_info.circuit.evt_step) { ckt->CKTsaveDelta = ckt->CKTdelta; @@ -704,7 +682,6 @@ resume: } /* end while next event time <= next analog time */ } /* end if there are event instances */ -/* gtri - end - wbk - Do event solution */ #else /* no XSPICE */ #ifdef CLUSTER @@ -739,14 +716,10 @@ resume: redostep = 1; #endif #ifdef XSPICE -/* gtri - add - wbk - 4/17/91 - Fix Berkeley bug */ -/* This is needed here to allow CAPask to output currents */ -/* during Transient analysis. A grep for CKTcurrentAnalysis */ -/* indicates that it should not hurt anything else ... */ - +/* This is needed here to allow CAPask to output currents + during Transient analysis. */ ckt->CKTcurrentAnalysis = DOING_TRAN; -/* gtri - end - wbk - 4/17/91 - Fix Berkeley bug */ xspice_breakpoints_processed = 0; #endif olddelta=ckt->CKTdelta; @@ -763,33 +736,25 @@ resume: save_mode = ckt->CKTmode; save_order = ckt->CKTorder; #ifdef XSPICE -/* gtri - begin - wbk - Add Breakpoint stuff */ /* Initialize temporary breakpoint to infinity */ g_mif_info.breakpoint.current = 1.0e30; -/* gtri - end - wbk - Add Breakpoint stuff */ - - -/* gtri - begin - wbk - add convergence problem reporting flags */ + /* Add convergence problem reporting flags */ /* delta is forced to equal delmin on last attempt near line 650 */ if(ckt->CKTdelta <= ckt->CKTdelmin) ckt->enh->conv_debug.last_NIiter_call = MIF_TRUE; else ckt->enh->conv_debug.last_NIiter_call = MIF_FALSE; -/* gtri - begin - wbk - add convergence problem reporting flags */ +/* Call all hybrids */ -/* gtri - begin - wbk - Call all hybrids */ - -/* gtri - begin - wbk - Set evt_step */ - + /* Set evt_step */ if(ckt->evt->counts.num_insts > 0) { g_mif_info.circuit.evt_step = ckt->CKTtime; } -/* gtri - end - wbk - Set evt_step */ #endif - + /* Central solver step */ converged = NIiter(ckt,ckt->CKTtranMaxIter); ckt->CKTstat->STATtimePts ++; @@ -805,6 +770,7 @@ resume: return(converged); } + /* If no convergence in Central solver step */ if(converged != 0) { #ifndef CLUSTER #ifndef SHARED_MODULE @@ -825,10 +791,12 @@ resume: ckt->CKTorder = 1; #ifdef XSPICE -/* gtri - begin - wbk - Add Breakpoint stuff */ - + /* Add Breakpoint stuff */ } else if(g_mif_info.breakpoint.current < ckt->CKTtime) { - /* Force backup if temporary breakpoint is < current time */ + /* Force backup if temporary breakpoint is < current time: + - save old delta + - retract time by old delta + - new delta by difference between by retracted time and breakpoint */ past_breakpoint: ckt->CKTsaveDelta = ckt->CKTdelta; @@ -841,11 +809,13 @@ resume: ckt->CKTmode = (ckt->CKTmode&MODEUIC)|MODETRAN | MODEINITTRAN; } ckt->CKTorder = 1; - -/* gtri - end - wbk - Add Breakpoint stuff */ #endif } else { + /* If converged: + - go to next time step if this was the first time. + - If not the first time step, don not accept, but check the truncation errors, + and reduce delta accordingly, thenm redo the step, to bound the error. */ if (firsttime) { #ifdef WANT_SENSE2 if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & TRANSEN)){ @@ -863,15 +833,16 @@ resume: #endif firsttime = 0; #if !defined CLUSTER && !defined SHARED_MODULE - goto nextTime; /* no check on - * first time point - */ + /* no check on first time point */ + goto nextTime; /* line 373 */ #else redostep = 0; goto chkStep; #endif } newdelta = ckt->CKTdelta; + /* Scan through all devices, estimate the truncation error, + and reduce the time step, if necessary.*/ error = CKTtrunc(ckt,&newdelta); if(error) { UPDATE_STATS(DOING_TRAN); @@ -893,13 +864,12 @@ resume: EVTcall_hybrids(ckt); if (g_mif_info.breakpoint.current < ckt->CKTtime) { /* A hybrid requested a breakpoint in the past. */ - goto past_breakpoint; } } #endif - - if ((ckt->CKTorder == 1) && (ckt->CKTmaxOrder > 1)) { /* don't rise the order for backward Euler */ + /* don't raise the order for backward Euler */ + if ((ckt->CKTorder == 1) && (ckt->CKTmaxOrder > 1)) { newdelta = ckt->CKTdelta; ckt->CKTorder = 2; error = CKTtrunc(ckt, &newdelta); @@ -950,13 +920,16 @@ resume: #endif #if !defined CLUSTER && !defined SHARED_MODULE - /* go to 650 - trapezoidal */ - goto nextTime; + /* trapezoidal */ + goto nextTime; /* line 373 */ #else redostep = 0; goto chkStep; #endif } else { + /* not (newdelta > .9 * ckt->CKTdelta): reject the step + - redo the time + - apply the new (reduced) delta */ #ifndef CLUSTER #ifndef SHARED_MODULE ckt->CKTtime = ckt->CKTtime -ckt->CKTdelta; @@ -968,11 +941,13 @@ resume: ckt->CKTdelta = newdelta; #ifdef STEPDEBUG (void)printf( - "delta set to truncation error result:point rejected\n"); + "delta set to truncation error result: point rejected\n"); #endif } } - + /* Set the new delta to delmin (minimum delta allowed). However: + If the new delta has been less than the minimum delta + for the second time, bail out with 'Timestep too small'. */ if (ckt->CKTdelta <= ckt->CKTdelmin) { if (olddelta > ckt->CKTdelmin) { ckt->CKTdelta = ckt->CKTdelmin; @@ -990,8 +965,7 @@ resume: } } #ifdef XSPICE -/* gtri - begin - wbk - Do event backup */ - + /* Do event backup */ if(ckt->evt->counts.num_insts > 0) { #ifdef SHARED_MODULE double discard_start_time = ckt->CKTtime + ckt->CKTdelta; @@ -1011,7 +985,6 @@ resume: #endif } -/* gtri - end - wbk - Do event backup */ #endif #ifdef CLUSTER chkStep: From 58380ba1b8581bf41b515931a6aede6f042a95cc Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 15 Oct 2025 22:44:24 +0200 Subject: [PATCH 048/161] Remove all entries related to CLUSTER, an old, never finished attempt to run transient in parallel. --- src/spicelib/analysis/dctran.c | 46 ++++++---------------------------- 1 file changed, 8 insertions(+), 38 deletions(-) diff --git a/src/spicelib/analysis/dctran.c b/src/spicelib/analysis/dctran.c index 731a04631..95c03457d 100644 --- a/src/spicelib/analysis/dctran.c +++ b/src/spicelib/analysis/dctran.c @@ -28,10 +28,6 @@ extern struct dbcomm *dbs; #include "ngspice/ipctiein.h" #endif -#ifdef CLUSTER -#include "ngspice/cluster.h" -#endif - #ifdef SHARED_MODULE extern int add_bkpt(void); extern int sharedsync(double*, double*, double, double, double, int, int*, int); @@ -120,9 +116,9 @@ DCtran(CKTcircuit *ckt, #ifdef SHARED_MODULE double olddelta_for_shared_sync = 0.0; -#endif // SHARED_MODULE #endif -#if defined CLUSTER || defined SHARED_MODULE +#endif +#if defined SHARED_MODULE int redostep; #endif if(restart || ckt->CKTtime == 0) { @@ -344,9 +340,7 @@ DCtran(CKTcircuit *ckt, #endif INIT_STATS(); -#ifdef CLUSTER - CLUsetup(ckt); -#endif + /* End of (restart || ckt->CKTtime == 0) */ } else { /* traninit resets CKTmode */ @@ -469,9 +463,7 @@ DCtran(CKTcircuit *ckt, /* End of Send IPC stuff*/ } else #endif -#ifdef CLUSTER - CLUoutput(ckt); -#endif + if((ckt->CKTmode&MODEUIC && ckt->CKTtime > 0 && ckt->CKTtime >= ckt->CKTinitTime) || (!(ckt->CKTmode&MODEUIC) && ckt->CKTtime >= ckt->CKTinitTime)) CKTdump(ckt, ckt->CKTtime, job->TRANplot); @@ -684,13 +676,6 @@ resume: #else /* no XSPICE */ -#ifdef CLUSTER - if(!CLUsync(ckt->CKTtime,&ckt->CKTdelta,0)) { - printf("Sync error!\n"); - exit(0); - } -#endif /* CLUSTER */ - #ifdef SHARED_MODULE /* Either directly go to next time step, or modify ckt->CKTdelta depending on synchronization requirements. sharedsync() returns 0. @@ -712,7 +697,7 @@ resume: /* 600 */ for (;;) { -#if defined CLUSTER || defined SHARED_MODULE +#if defined SHARED_MODULE redostep = 1; #endif #ifdef XSPICE @@ -725,9 +710,6 @@ resume: olddelta=ckt->CKTdelta; /* time abort? */ ckt->CKTtime += ckt->CKTdelta; -#ifdef CLUSTER - CLUinput(ckt); -#endif ckt->CKTdeltaOld[0]=ckt->CKTdelta; NIcomCof(ckt); #ifdef PREDICTOR @@ -772,13 +754,12 @@ resume: /* If no convergence in Central solver step */ if(converged != 0) { -#ifndef CLUSTER + #ifndef SHARED_MODULE ckt->CKTtime = ckt->CKTtime -ckt->CKTdelta; ckt->CKTstat->STATrejected ++; #else redostep = 1; -#endif #endif ckt->CKTdelta = ckt->CKTdelta/8; #ifdef STEPDEBUG @@ -832,7 +813,7 @@ resume: } #endif firsttime = 0; -#if !defined CLUSTER && !defined SHARED_MODULE +#if !defined SHARED_MODULE /* no check on first time point */ goto nextTime; /* line 373 */ #else @@ -919,7 +900,7 @@ resume: } #endif -#if !defined CLUSTER && !defined SHARED_MODULE +#if !defined SHARED_MODULE /* trapezoidal */ goto nextTime; /* line 373 */ #else @@ -930,13 +911,11 @@ resume: /* not (newdelta > .9 * ckt->CKTdelta): reject the step - redo the time - apply the new (reduced) delta */ -#ifndef CLUSTER #ifndef SHARED_MODULE ckt->CKTtime = ckt->CKTtime -ckt->CKTdelta; ckt->CKTstat->STATrejected ++; #else redostep = 1; -#endif #endif ckt->CKTdelta = newdelta; #ifdef STEPDEBUG @@ -986,15 +965,6 @@ resume: } #endif -#ifdef CLUSTER - chkStep: - if(CLUsync(ckt->CKTtime,&ckt->CKTdelta,redostep)){ - goto nextTime; - } else { - ckt->CKTtime -= olddelta; - ckt->CKTstat->STATrejected ++; - } -#endif #ifdef SHARED_MODULE /* redostep == 0: From 1f2a6f3665a978834a64f257ed31a7feb282921f Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 15 Oct 2025 22:59:28 +0200 Subject: [PATCH 049/161] document the goto labels. --- src/spicelib/analysis/dctran.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/spicelib/analysis/dctran.c b/src/spicelib/analysis/dctran.c index 95c03457d..3e139096a 100644 --- a/src/spicelib/analysis/dctran.c +++ b/src/spicelib/analysis/dctran.c @@ -7,6 +7,13 @@ Modified: 2023 XSPICE breakpoint fix for shared ngspice by Vyacheslav Shevchuk /* subroutine to do DC TRANSIENT analysis */ + +/* line goto label: + 373 nextTime + 515 resume + 788 past_breakpoint + 987 chkStep */ + #include "ngspice/ngspice.h" #include "ngspice/cktdefs.h" #include "cktaccept.h" @@ -360,10 +367,9 @@ DCtran(CKTcircuit *ckt, fprintf(stderr, "Couldn't relink rawfile\n"); return error; } - goto resume; /* line 517 */ + goto resume; /* line 515 */ } -/* 650 */ nextTime: /* begin LTRA code addition */ @@ -818,7 +824,7 @@ resume: goto nextTime; /* line 373 */ #else redostep = 0; - goto chkStep; + goto chkStep; /* line 987 */ #endif } newdelta = ckt->CKTdelta; @@ -845,7 +851,7 @@ resume: EVTcall_hybrids(ckt); if (g_mif_info.breakpoint.current < ckt->CKTtime) { /* A hybrid requested a breakpoint in the past. */ - goto past_breakpoint; + goto past_breakpoint; /* line 788 */ } } #endif @@ -905,7 +911,7 @@ resume: goto nextTime; /* line 373 */ #else redostep = 0; - goto chkStep; + goto chkStep; /* line 987 */ #endif } else { /* not (newdelta > .9 * ckt->CKTdelta): reject the step @@ -991,11 +997,11 @@ chkStep: olddelta_for_shared_sync = 0.0; if(sharedsync(&ckt->CKTtime, &ckt->CKTdelta, olddelta_for_shared_sync, ckt->CKTfinalTime, ckt->CKTdelmin, redostep, &ckt->CKTstat->STATrejected, 1) == 0) - goto nextTime; + goto nextTime; /* line 373 */ #else if(sharedsync(&ckt->CKTtime, &ckt->CKTdelta, olddelta, ckt->CKTfinalTime, ckt->CKTdelmin, redostep, &ckt->CKTstat->STATrejected, 1) == 0) - goto nextTime; + goto nextTime; /* line 373 */ #endif // XSPICE #endif // SHARED_MODULE From d49134df9321958c6eeb1de1810bf19987ae9730 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 15 Oct 2025 23:59:01 +0200 Subject: [PATCH 050/161] Small update on comments. --- src/spicelib/analysis/dctran.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/spicelib/analysis/dctran.c b/src/spicelib/analysis/dctran.c index 3e139096a..6c7364b24 100644 --- a/src/spicelib/analysis/dctran.c +++ b/src/spicelib/analysis/dctran.c @@ -11,8 +11,8 @@ Modified: 2023 XSPICE breakpoint fix for shared ngspice by Vyacheslav Shevchuk /* line goto label: 373 nextTime 515 resume - 788 past_breakpoint - 987 chkStep */ + 786 past_breakpoint + 985 chkStep */ #include "ngspice/ngspice.h" #include "ngspice/cktdefs.h" @@ -469,7 +469,7 @@ DCtran(CKTcircuit *ckt, /* End of Send IPC stuff*/ } else #endif - + /* Output the data of the current accepted time point */ if((ckt->CKTmode&MODEUIC && ckt->CKTtime > 0 && ckt->CKTtime >= ckt->CKTinitTime) || (!(ckt->CKTmode&MODEUIC) && ckt->CKTtime >= ckt->CKTinitTime)) CKTdump(ckt, ckt->CKTtime, job->TRANplot); @@ -531,15 +531,13 @@ resume: else SetAnalyse( "tran", (int)((ckt->CKTtime * 1000.) / ckt->CKTfinalTime + 0.5)); #endif - ckt->CKTdelta = - MIN(ckt->CKTdelta,ckt->CKTmaxStep); + + ckt->CKTdelta = MIN(ckt->CKTdelta,ckt->CKTmaxStep); + #ifdef XSPICE -/* gtri - begin - wbk - Cut integration order if first timepoint after breakpoint */ - /* if(ckt->CKTtime == g_mif_info.breakpoint.last) */ + /* Cut integration order if first timepoint after breakpoint */ if ( AlmostEqualUlps( ckt->CKTtime, g_mif_info.breakpoint.last, 100 ) ) ckt->CKTorder = 1; -/* gtri - end - wbk - Cut integration order if first timepoint after breakpoint */ - #endif /* Are we at a breakpoint, or indistinguishably close? */ @@ -851,7 +849,7 @@ resume: EVTcall_hybrids(ckt); if (g_mif_info.breakpoint.current < ckt->CKTtime) { /* A hybrid requested a breakpoint in the past. */ - goto past_breakpoint; /* line 788 */ + goto past_breakpoint; /* line 786 */ } } #endif From 5443385ae9bfb58a458fc5e2d49484fd634484f6 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 17 Oct 2025 17:31:12 +0200 Subject: [PATCH 051/161] Another update on comments --- src/spicelib/analysis/dctran.c | 46 +++++++++++++++++----------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/spicelib/analysis/dctran.c b/src/spicelib/analysis/dctran.c index 6c7364b24..fc5cf9f58 100644 --- a/src/spicelib/analysis/dctran.c +++ b/src/spicelib/analysis/dctran.c @@ -106,19 +106,11 @@ DCtran(CKTcircuit *ckt, double ipc_last_time = 0.0; double ipc_last_delta = 0.0; - // Fix for sharedsync olddelta: When DCTran processes - // either analog or XSPICE breakpoint, then it subtracts delta from - // ckt->CKTtime. It sends 0 as olddelta after analog breakpoint - // processing. Still, for XSPICE breakpoints it subtracts delta (see code - // 'else if(g_mif_info.breakpoint.current < ckt->CKTtime)' branch) and - // then sends non zero olddelta to sharedsync at the end of the function - // (see chkStep: label). Thus olddelta is subtracted twice. Then - // ckt->CKTtime becomes less than last_accepted_time. - // xspice_breakpoints_processed 0: - // XSPICE models didn't have breakpoints in [last_accepted_time, CKTtime]. - // xspice_breakpoints_processed 1: - // convergence criteria are satisfied but XSPICE breakpoint(s) is in the - // time interval [last_accepted_time, CKTtime]. + /* xspice_breakpoints_processed 0: + XSPICE models didn't have breakpoints in [last_accepted_time, CKTtime]. + xspice_breakpoints_processed 1: + convergence criteria are satisfied but XSPICE breakpoint(s) is in the + time interval [last_accepted_time, CKTtime]. */ int xspice_breakpoints_processed = 0; #ifdef SHARED_MODULE @@ -129,7 +121,14 @@ DCtran(CKTcircuit *ckt, int redostep; #endif if(restart || ckt->CKTtime == 0) { - /* set the first step time */ + /* dctran() is entered here upon starting transient simulation + with time 0 and restart 1. + ckt->CKTstep, CKTfinalTime, CKTinitTime, CKTmaxStep have been + set already in fcn TRANinit() of traninit.c according to + TSTEP TSTOP TSTART TMAX given on the .tran line. TMAX is set to TSTEP, + if 'set nostepsizelimit' is not given in .spiceinit.*/ + + /* Set the first delta (step) time, typically depending on TSTEP */ delta=MIN(ckt->CKTfinalTime/100,ckt->CKTstep)/10; #ifdef STEPDEBUG @@ -167,7 +166,7 @@ DCtran(CKTcircuit *ckt, #ifdef XSPICE /* Modify setting of CKTminBreak - Set to 10 times delmin (minimum step time). */ + Set to 10 times delmin (minimum delta step time). */ if(ckt->CKTminBreak == 0) ckt->CKTminBreak = 10.0 * ckt->CKTdelmin; @@ -186,6 +185,7 @@ DCtran(CKTcircuit *ckt, g_mif_info.circuit.anal_init = MIF_TRUE; #endif + /* Scan ckt->CKTnodes and create list of node names */ error = CKTnames(ckt,&numNames,&nameList); if(error) return(error); SPfrontEnd->IFnewUid (ckt, &timeUid, NULL, "time", UID_OTHER, NULL); @@ -952,14 +952,14 @@ resume: if(ckt->evt->counts.num_insts > 0) { #ifdef SHARED_MODULE double discard_start_time = ckt->CKTtime + ckt->CKTdelta; - // ngspice in executable mode subtracts olddelta from the time - // before new delta calculation, but it keeps delta in CKTtime and - // postpones subtraction in library mode. Delayed subtraction leads - // to incorrect points dropping because ckt->CKTdelta is almost always - // less than olddelta if there are convergence issues, and EVTbackup - // may drop valid events that need to be processed within - // [last_accepted_time, last_accepted_time + ckt->CKTdelta] range - // after delta adjustment. + /* ngspice in executable mode subtracts olddelta from the time + before new delta calculation, but it keeps delta in CKTtime and + postpones subtraction in library mode. Delayed subtraction leads + to incorrect points dropping because ckt->CKTdelta is almost always + less than olddelta if there are convergence issues, and EVTbackup + may drop valid events that need to be processed within + [last_accepted_time, last_accepted_time + ckt->CKTdelta] range + after delta adjustment. */ if (redostep && xspice_breakpoints_processed == 0) discard_start_time -= olddelta; EVTbackup(ckt, discard_start_time); From aa1242ac70aea87b814287013fcc6ba06da51ac2 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Thu, 16 Oct 2025 18:04:46 +0100 Subject: [PATCH 052/161] Add new functions for .param expressions. vec() takes a string argument and fetches a vector value from the current plot or "const". var() is similar but fetches an interpreter variable. --- src/frontend/numparam/xpressn.c | 55 ++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/src/frontend/numparam/xpressn.c b/src/frontend/numparam/xpressn.c index ad0620983..ec1c55f8b 100644 --- a/src/frontend/numparam/xpressn.c +++ b/src/frontend/numparam/xpressn.c @@ -30,6 +30,7 @@ extern long dynsubst; /* see inpcom.c */ #define S_stop 4 static char* sort_idlist(char *list); +static char *string_expr(dico_t *, DSTRINGPTR, const char *, const char *); static double ternary_fcn(double conditional, double if_value, double else_value) @@ -83,23 +84,27 @@ limit(double nominal_val, double abs_variation) return (nominal_val + (drand() > 0 ? abs_variation : -1. * abs_variation)); } +/* The list of built-in functions. Patch 'mathfunction', here to get more ... + * Function "vec" and following take a string argument and must come last. + */ static const char *fmathS = /* all math functions */ "sqr sqrt sin cos exp ln arctan abs pow pwr max min int log log10 sinh cosh" " tanh ternary_fcn agauss sgn gauss unif aunif limit ceil floor" - " asin acos atan asinh acosh atanh tan nint"; + " asin acos atan asinh acosh atanh tan nint" + " vec var"; enum { XFU_SQR = 1, XFU_SQRT, XFU_SIN, XFU_COS, XFU_EXP, XFU_LN, XFU_ARCTAN, XFU_ABS, XFU_POW, XFU_PWR, XFU_MAX, XFU_MIN, XFU_INT, XFU_LOG, XFU_LOG10, XFU_SINH, XFU_COSH, XFU_TANH, XFU_TERNARY_FCN, XFU_AGAUSS, XFU_SGN, XFU_GAUSS, XFU_UNIF, XFU_AUNIF, XFU_LIMIT, XFU_CEIL, XFU_FLOOR, - XFU_ASIN, XFU_ACOS, XFU_ATAN, XFU_ASINH, XFU_ACOSH, XFU_ATANH, XFU_TAN, XFU_NINT + XFU_ASIN, XFU_ACOS, XFU_ATAN, XFU_ASINH, XFU_ACOSH, XFU_ATANH, XFU_TAN, XFU_NINT, + XFU_VEC, XFU_VAR // String arguments. }; static double mathfunction(int f, double z, double x) -/* the list of built-in functions. Patch 'fmath', here and near line 888 to get more ...*/ { double y; switch (f) @@ -946,6 +951,48 @@ formula(dico_t *dico, const char *s, const char *s_end, bool *perror) if (kptr >= s_end) { error = message(dico, "Closing \")\" not found.\n"); natom++; /* shut up other error message */ + } else if (fu >= XFU_VEC) { + struct dvec *d; + char *vec_name; + + /* Special case: function with string arg. + * Try to evaluate any string expression, else use directly. + */ + + if (string_expr(dico, &tstr, s, kptr) != kptr) + pscopy(&tstr, s, kptr); // No, or not fully consumed. + vec_name = ds_get_buf(&tstr); + + if (fu == XFU_VEC) { + struct plot *cplot, *prev; + + d = vec_get(vec_name); + + /* A simple name will be looked-up is the current plot. + * Try "const" if not found. + */ + + if (!d && !strchr(vec_name, '.')) { + cplot = get_plot("const"); + if (plot_cur != cplot) { + prev = plot_cur; + plot_cur = cplot; + d = vec_get(vec_name); + plot_cur = prev; + } + } + + if (d && d->v_length > 0 && isreal(d)) + u = d->v_realdata[0]; + else + u = 0; + } else if (fu == XFU_VAR) { + if (!cp_getvar(vec_name, CP_REAL, &u, sizeof u)) + u = 0; + } + state = S_atom; + s = kptr + 1; + fu = 0; } else { if (arg2 >= s) { v = formula(dico, s, arg2, &error); @@ -1088,7 +1135,7 @@ formula(dico_t *dico, const char *s, const char *s_end, bool *perror) } -/* Check for a string expression, return end pointer or NULL. +/* Check for a string expression, return end pointer or NULL. * A string expression is a sequence of quoted strings and string * variables, optionally enclosed by '{}' with no interventing space. * If successful return pointer to next char, otherwise NULL. From 4594d5fd9193b386ba9d097aeb507995af7a9134 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 18 Oct 2025 15:40:02 +0200 Subject: [PATCH 053/161] Add variable deltacheck to measure the CKTdelta[0] (most recent accepted delta time) versus simulation time. Activated if 'set ngdebug' is given (not forget to set '.save deltacheck' if other .save commands are given). --- src/frontend/outitf.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/frontend/outitf.c b/src/frontend/outitf.c index d47e61632..6ca75d8d5 100644 --- a/src/frontend/outitf.c +++ b/src/frontend/outitf.c @@ -280,6 +280,12 @@ beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analNam saves[i].used = 1; break; } + else if (ft_ngdebug && refName && eq(refName, "time") && eq(saves[i].name, "deltacheck")) { + addDataDesc(run, "deltacheck", IF_REAL, j, initmem); + savesused[i] = TRUE; + saves[i].used = 1; + break; + } } } } @@ -307,6 +313,7 @@ beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analNam /* generate a vector of real time information */ if (ft_ngdebug && refName && eq(refName, "time")) { addDataDesc(run, "speedcheck", IF_REAL, numNames, initmem); + addDataDesc(run, "deltacheck", IF_REAL, numNames, initmem); } } @@ -582,6 +589,9 @@ OUTpD_memory(runDesc *run, IFvalue *refValue, IFvalue *valuePtr) double tt = ((double)cl - (double)startclock) / CLOCKS_PER_SEC; plotAddRealValue(d, tt); } + else if (ft_ngdebug && d->type == IF_REAL && eq(d->name, "deltacheck")) { + plotAddRealValue(d, ft_curckt->ci_ckt->CKTdeltaOld[0]); + } else if (d->type == IF_REAL) plotAddRealValue(d, valuePtr->v.vec.rVec[d->outIndex]); else if (d->type == IF_COMPLEX) @@ -693,6 +703,9 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr) double tt = ((double)cl - (double)startclock) / CLOCKS_PER_SEC; fileAddRealValue(run->fp, run->binary, tt); } + else if (ft_ngdebug && run->data[i].type == IF_REAL && eq(run->data[i].name, "deltacheck")) { + fileAddRealValue(run->fp, run->binary, ft_curckt->ci_ckt->CKTdeltaOld[0]); + } else if (run->data[i].type == IF_REAL) fileAddRealValue(run->fp, run->binary, valuePtr->v.vec.rVec [run->data[i].outIndex]); @@ -970,6 +983,8 @@ guess_type(const char *name, char* pltypename) type = SV_TIME; else if ( cieq(name, "speedcheck")) type = SV_TIME; + else if ( cieq(name, "deltacheck")) + type = SV_TIME; else if (cieq(name, "frequency")) type = SV_FREQUENCY; else if (ciprefix("inoise", name)) From 48d28f9f4a05410b62725fb076c5bc1dec00a739 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 19 Oct 2025 22:27:21 +0200 Subject: [PATCH 054/161] Entries to old CLUSTER code removed. --- configure.ac | 12 - src/include/ngspice/Makefile.am | 1 - src/include/ngspice/cluster.h | 24 -- src/spicelib/analysis/Makefile.am | 3 +- src/spicelib/analysis/cluster.c | 426 --------------------------- src/spicelib/analysis/dcpss.c | 59 +--- visualc/sharedspice.vcxproj | 2 - visualc/src/include/ngspice/config.h | 3 - visualc/vngspice-fftw.vcxproj | 2 - visualc/vngspice.vcxproj | 2 - 10 files changed, 6 insertions(+), 528 deletions(-) delete mode 100644 src/include/ngspice/cluster.h delete mode 100644 src/spicelib/analysis/cluster.c diff --git a/configure.ac b/configure.ac index d7189937b..565f8630a 100644 --- a/configure.ac +++ b/configure.ac @@ -285,10 +285,6 @@ AC_ARG_ENABLE([expdevices], AC_ARG_ENABLE([ndev], [AS_HELP_STRING([--enable-ndev], [Enable NDEV interface, (experimental)])]) -# --enable-cluster: define CLUSTER in the code. This is for cluster support -AC_ARG_ENABLE([cluster], - [AS_HELP_STRING([--enable-cluster], [Enable cluster support, (experimental)])]) - # --enable-cmathtests: run the ancient tests in src/math/cmaths AC_ARG_ENABLE([cmathtests], [AS_HELP_STRING([--enable-cmathtests], [Enable ancient tests in src/math/cmaths])]) @@ -1244,14 +1240,6 @@ if test "x$enable_ndev" = xyes; then fi AM_CONDITIONAL([NDEV_WANTED], [test "x$enable_ndev" = xyes]) - -# Cluster option -if test "x$enable_cluster" = xyes; then - AC_MSG_RESULT([Cluster version is being compiled]) - AC_DEFINE([CLUSTER], [], [Spice cluster support]) - LIBS="$LIBS -lpthread" -fi - if test "x$enable_expdevices" = xyes; then AC_DEFINE([EXP_DEV], [], [Define if we want to enable experimental devices]) AC_MSG_RESULT([WARNING: Experimental devices enabled]) diff --git a/src/include/ngspice/Makefile.am b/src/include/ngspice/Makefile.am index 1783a9df1..fcda98836 100644 --- a/src/include/ngspice/Makefile.am +++ b/src/include/ngspice/Makefile.am @@ -11,7 +11,6 @@ noinst_HEADERS = \ ciderinp.h \ cidersupt.h \ cktdefs.h \ - cluster.h \ cmconstants.h \ cm.h \ cmproto.h \ diff --git a/src/include/ngspice/cluster.h b/src/include/ngspice/cluster.h deleted file mode 100644 index b6391c29b..000000000 --- a/src/include/ngspice/cluster.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef ngspice_CLUSTER_H -#define ngspice_CLUSTER_H -#include "ngspice/cktdefs.h" - -/* Cluster definitions */ -#define PORT 1234 -#define TIME_PORT 1235 -#define DOMAIN_NAME "cluster.multigig" -#define CLUSTER_WIDTH 4 -#define TIME_HOST "time.cluster.multigig" -/* does all the setups */ -extern int CLUsetup(CKTcircuit *ckt); - -/* reads input pipes and sets voltages*/ -/* call each time the present time is changed, ie just before NIinter*/ -extern int CLUinput(CKTcircuit *ckt); - -/* call after each accepted timestep, ie CKTdump */ -extern int CLUoutput(CKTcircuit *ckt); - - -/* the time step control */ -extern int CLUsync(double time,double *delta, int error); -#endif diff --git a/src/spicelib/analysis/Makefile.am b/src/spicelib/analysis/Makefile.am index c6d98c35f..33d62591a 100644 --- a/src/spicelib/analysis/Makefile.am +++ b/src/spicelib/analysis/Makefile.am @@ -98,8 +98,7 @@ libckt_la_SOURCES = \ tfsetp.c \ tranaskq.c \ traninit.c \ - transetp.c \ - cluster.c + transetp.c if PSS_WANTED diff --git a/src/spicelib/analysis/cluster.c b/src/spicelib/analysis/cluster.c deleted file mode 100644 index c34f75181..000000000 --- a/src/spicelib/analysis/cluster.c +++ /dev/null @@ -1,426 +0,0 @@ -/* Spice hooks */ -#include "ngspice/ngspice.h" -#ifdef CLUSTER -#include "ngspice/inpdefs.h" -#include "ngspice/cluster.h" -#include "ngspice/cktdefs.h" -#include "ngspice/gendefs.h" - -/* Misc stuff */ -#include -#include - -/*Network stuff*/ -#include -#include -#include -#include -#include - - -struct input_pipe { - /*the names of the local and remote nodes*/ - char remote[32]; - char local[32]; - int fd; - FILE *stream; - /* the data recieved */ - double time; - double data; - /*resistance of this link*/ - double res; - /* The value controled */ - double *currentPtr; - /*The output it is linked to*/ - struct output_pipe *link; - struct input_pipe *next; -}; - -struct output_pipe { - int fd; - FILE *stream; - /*the names of the local and remote nodes*/ - char local[32]; - char remote[32]; - /* The index of the local node value in the ckt->CKTrhsOld array */ - int outIndex; - /*Last values sent*/ - double time,data; - struct input_pipe *link; - struct output_pipe *next; -}; - -static double lastTimeSent=0; - -static int time_sock=0; -static FILE *time_outfile=NULL; -static FILE *time_infile=NULL; - -static struct input_pipe* input_pipes=NULL; -static struct output_pipe* output_pipes=NULL; - -/* sets up deamon which waits for connections - *and sets up input pipes as it recieves them */ -static void *start_listener(void *); - -/* Setup the output pipes*/ -static int setup_output(CKTcircuit *ckt); -static int setup_input(CKTcircuit *ckt); -static int setup_time(); - -int CLUsetup(CKTcircuit *ckt){ - pthread_t tid; - struct input_pipe *curr; - int i, connections=0; - GENmodel *mod; - GENinstance *inst; - - /* count the number of connections expected */ - i = INPtypelook("Isource"); - for(mod = ckt->CKThead[i]; - mod != NULL; - mod = mod->GENnextModel) - for (inst = mod->GENinstances; - inst != NULL; - inst = inst->GENnextInstance) - if(strncmp("ipcx",inst->GENname,4) == 0) - connections++; - - /* allocate the input connections */ - for(i=0;inext = input_pipes; - else - curr->next = NULL; - input_pipes = curr; - } - - pthread_create(&tid,NULL,start_listener,(void *)&connections); - setup_output(ckt); - pthread_join(tid,NULL); - setup_input(ckt); - setup_time(); - return 0; -} - -#include "../devices/isrc/isrcdefs.h" -/*Connect to remote machine and find the data*/ -static int setup_output(CKTcircuit *ckt){ - int type; - GENmodel *mod; - GENinstance *inst; - char hostname[64]; - - lastTimeSent = 0; - type = INPtypelook("Isource"); - - for(mod = ckt->CKThead[type]; - mod != NULL; - mod = mod->GENnextModel) - - for (inst = mod->GENinstances; - inst != NULL; - inst = inst->GENnextInstance) - - if(strncmp("ipcx",inst->GENname,4) == 0){ - ISRCinstance *isrc = (ISRCinstance *)inst; - CKTnode *node; - struct output_pipe *curr; - struct sockaddr_in address; - struct hostent *host=NULL; - int sock,nodeNum,i; - - /*Create the struct*/ - curr = TMALLOC(struct output_pipe, 1); - if(output_pipes) - curr->next = output_pipes; - else - curr->next = NULL; - output_pipes = curr; - - /* The node names */ - strcpy(curr->local,CKTnodName(ckt,isrc->ISRCnegNode));/*weird*/ - strcpy(curr->remote,isrc->ISRCname); - - /* extract remote node number */ - nodeNum = /*Xcoord*/(curr->remote[4] - '0') * CLUSTER_WIDTH - + /*Ycoord*/(curr->remote[9] - '0'); - sprintf(hostname,"n%d."DOMAIN_NAME,nodeNum); - - /* network stuff */ - host = gethostbyname(hostname); - if(!host){ - printf("Host not found in setup_output\n"); - exit(0); - } - - if((sock = socket(PF_INET,SOCK_STREAM,0)) < 0){ - printf("Socket open in setup_output\n"); - exit(0); - } - - address.sin_family = AF_INET; - address.sin_port = htons(PORT); - memcpy(&address.sin_addr,host->h_addr_list[0], - sizeof(address.sin_addr)); - - printf("connecting to %s ...... ",hostname); - fflush(stdout); - - while(connect(sock,(struct sockaddr *)&address,sizeof(address))){ - usleep(500);/*wait for the sever to start*/ - } - - printf("connected\n"); - - curr->fd = sock; - - /* send stuff */ - /* buffer */ - i = (strlen(curr->remote) + strlen(curr->local) + 2)*sizeof(char); - setsockopt(sock,SOL_SOCKET,SO_SNDBUF,&i,sizeof(i)); - - curr->stream = fdopen(curr->fd,"w"); - - fwrite(curr->remote,sizeof(char),strlen(curr->remote),curr->stream); - fputc('\0',curr->stream); - fwrite(curr->local,sizeof(char),strlen(curr->local),curr->stream); - fputc('\0',curr->stream); - fflush(curr->stream); - - /* buffer, what is done per time point */ - i = sizeof(double)*2; - setsockopt(sock,SOL_SOCKET,SO_SNDBUF,&i,sizeof(i)); - - /* find the index in ckt->rhsOld which contains the local node */ - i = 0; - for(node = ckt->CKTnodes->next;node;node = node->next){ - i++; - if(strcmp(node->name,curr->local)==0){ - curr->outIndex = i; - goto next; - } - } - printf("Local node %s not found\n",curr->local); - exit(0); - next: - - } - return 0; -} - -/*Processes the connections recieved by start_listener*/ -static int setup_input(CKTcircuit *ckt){ - int type; - GENmodel *mod; - GENinstance *inst; - struct input_pipe *input; - type = INPtypelook("Isource"); - - for(input = input_pipes;input;input = input->next){ - int i; - - input->stream = fdopen(input->fd,"r"); - - /*Get the local and remote node names*/ - i=0; - do { - while(fread(&input->local[i],sizeof(char),1,input->stream) != 1); - }while(input->local[i++] != '\0'); - - i=0; - do { - while(fread(&input->remote[i],sizeof(char),1,input->stream) != 1); - }while(input->remote[i++] != '\0'); - - /* initilise */ - input->time = -1; - - /*Find the Isource to control*/ - for(mod = ckt->CKThead[type]; - mod != NULL; - mod = mod->GENnextModel) - - for (inst = mod->GENinstances; - inst != NULL; - inst = inst->GENnextInstance) - - if(strcmp(input->remote,&inst->GENname[11]) == 0){ - - ISRCinstance *isrc = (ISRCinstance *)inst; - input->res = isrc->ISRCdcValue; - isrc->ISRCdcValue = 0; - input->currentPtr = &isrc->ISRCdcValue; - goto next; - } - /* We get here if no Isource matches */ - printf("Current source %s not found\n",input->remote); - exit(0); - - next: - - /* Now find the corresponding output */ - { - struct output_pipe *output; - for(output = output_pipes;output;output = output->next) - if(strcmp(&input->local[11],output->local)==0){ - input->link = output; - output->link = input; - goto next2; - } - printf("Parent to %s not found\n",&input->local[11]); - exit(0); - next2: - } - } - return 0; -} - -/* This starts a server and waits for connections, number given by argument*/ -static void *start_listener(void *v){ - int *connections = (int *)v; - int count=0; - struct sockaddr_in address; - int sock, conn,i; - size_t addrLength = sizeof(struct sockaddr_in); - struct input_pipe *curr; - - if((sock = socket(PF_INET,SOCK_STREAM,0)) < 0){ - printf("socket in start_listener\n"); - exit(0); - } - - /* Allow reuse of the socket */ - i = 1; - setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(i)); - - /* port, inferface ..*/ - address.sin_family = AF_INET; - address.sin_port = htons(PORT); - memset(&address.sin_addr,0,sizeof(address.sin_addr)); - - if(bind(sock, (struct sockaddr *)&address,sizeof(address))){ - printf("bind in start_listener\n"); - exit(0); - } - if(listen(sock,5)){ - printf("listen in start_listener\n"); - exit(0); - } - - /* Loop till recieved all connections */ - curr = input_pipes; - while (count < *connections){ - if((conn = accept(sock, (struct sockaddr *)&address,&addrLength)) < 0){ - printf("accept in start_listener\n"); - exit(0); - } - - curr->fd = conn; - /* will fill rest of structure later in setup_input*/ - count ++; - curr = curr->next; - } - - close(sock); - - return NULL; -} - -/*Writes data to remote computer*/ -int CLUoutput(CKTcircuit *ckt){ - struct output_pipe *output; - lastTimeSent = ckt->CKTtime; - for(output = output_pipes; - output; - output = output->next){ - output->time = ckt->CKTtime; - output->data = ckt->CKTrhsOld[output->outIndex]; - fwrite(&output->time,sizeof(double),1,output->stream); - fwrite(&output->data, - sizeof(double),1,output->stream); - fflush(output->stream); - } - return 0; -} - -/*Maniputates the local circuit based on the links*/ -int CLUinput(CKTcircuit *ckt){ - struct input_pipe *input; - double tmp; - for(input= input_pipes;input;input = input->next){ - /*recieve data till we get a good time point*/ - while (input->time < lastTimeSent){ - while(fread(&input->time, sizeof(double), 1, input->stream) != 1){} - while(fread(&input->data, sizeof(double), 1, input->stream) != 1){} - } - tmp = (input->link->data - input->data) / input->res; - - /*dampen out large currents*/ - if(tmp > 0) - *input->currentPtr = 0.2 * (1 - exp(-tmp/0.2)); - else - *input->currentPtr = -0.2 * (1 - exp(tmp/0.2)); - - /*GND is the posNode, local node is the negNode*/ - } - return 0; -} - -static int setup_time(){ - struct sockaddr_in address; - struct hostent *host=NULL; - char *hostname = TIME_HOST; - int sock,i; - - /* network stuff */ - host = gethostbyname(hostname); - if(!host){ - printf("Host not found in setup_time\n"); - exit(0); - } - if((sock = socket(PF_INET,SOCK_STREAM,0)) < 0){ - printf("Socket open in setup_time\n"); - exit(0); - } - - i = sizeof(double)*2; - setsockopt(sock,SOL_SOCKET,SO_SNDBUF ,&i,sizeof(i)); - - address.sin_family = AF_INET; - address.sin_port = htons(TIME_PORT); - memcpy(&address.sin_addr,host->h_addr_list[0], - sizeof(address.sin_addr)); - - - while(connect(sock,(struct sockaddr *)&address,sizeof(address))){ - usleep(500);/*wait for the sever to start*/ - } - time_sock=sock; - time_outfile=fdopen(sock,"w"); - time_infile=fdopen(sock,"r"); - - return 0; -} - - -int CLUsync(double time,double *delta, int error){ - double tmp; - if(error) - tmp = *delta * (-1); - else - tmp = *delta; - fwrite(&time,sizeof(double),1,time_outfile); - fwrite(&tmp,sizeof(double),1,time_outfile); - fflush(time_outfile); - while(fread(&tmp,sizeof(double),1,time_infile) != 1); - if(tmp < 0){ - *delta = -tmp; - return 0; - } else { - *delta = tmp; - return 1; - } -} -#endif diff --git a/src/spicelib/analysis/dcpss.c b/src/spicelib/analysis/dcpss.c index 61350383c..2ecc36943 100644 --- a/src/spicelib/analysis/dcpss.c +++ b/src/spicelib/analysis/dcpss.c @@ -24,11 +24,6 @@ /* gtri - end - wbk - Add headers */ #endif -#ifdef CLUSTER -#include "ngspice/cluster.h" -#endif - - #define INIT_STATS() \ do { \ startTime = SPfrontEnd->IFseconds(); \ @@ -97,9 +92,6 @@ DCpss(CKTcircuit *ckt, double ipc_last_time = 0.0; double ipc_last_delta = 0.0; /* gtri - end - wbk - 12/19/90 - Add IPC stuff */ -#endif -#ifdef CLUSTER - int redostep; #endif /* New variables */ @@ -365,9 +357,7 @@ DCpss(CKTcircuit *ckt, /* Statistics Initialization using a macro at the beginning of this code */ INIT_STATS(); -#ifdef CLUSTER - CLUsetup(ckt); -#endif + } else { /* saj As traninit resets CKTmode */ ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODETRAN | MODEINITPRED; @@ -490,10 +480,6 @@ DCpss(CKTcircuit *ckt, } } else /* gtri - modify - wbk - 12/19/90 - Send IPC stuff */ -#endif -#ifdef CLUSTER - if (pss_state == PSS) - CLUoutput(ckt); #endif if (pss_state == PSS) @@ -1278,14 +1264,6 @@ resume: } /* end if there are event instances */ /* gtri - end - wbk - Do event solution */ -#else - -#ifdef CLUSTER - if(!CLUsync(ckt->CKTtime,&ckt->CKTdelta,0)) { - fprintf (stderr, "Sync error!\n"); - exit(0); - } -#endif /* CLUSTER */ #endif @@ -1302,9 +1280,6 @@ resume: /* 600 */ for (;;) { -#ifdef CLUSTER - redostep = 1; -#endif #ifdef XSPICE /* gtri - add - wbk - 4/17/91 - Fix Berkeley bug */ /* This is needed here to allow CAPask to output currents */ @@ -1318,9 +1293,6 @@ resume: olddelta=ckt->CKTdelta; /* time abort? */ ckt->CKTtime += ckt->CKTdelta; -#ifdef CLUSTER - CLUinput(ckt); -#endif ckt->CKTdeltaOld[0]=ckt->CKTdelta; NIcomCof(ckt); #ifdef PREDICTOR @@ -1384,10 +1356,8 @@ resume: fprintf (stderr, "pss_state: %d, converged: %d\n", pss_state, converged) ; #endif if(converged != 0) { -#ifndef CLUSTER - ckt->CKTtime = ckt->CKTtime -ckt->CKTdelta; - ckt->CKTstat->STATrejected ++; -#endif + ckt->CKTtime = ckt->CKTtime - ckt->CKTdelta; + ckt->CKTstat->STATrejected++; ckt->CKTdelta = ckt->CKTdelta/8; #ifdef STEPDEBUG fprintf (stderr, "delta cut to %g for non-convergence\n", ckt->CKTdelta) ; @@ -1419,14 +1389,9 @@ resume: } else { if (firsttime) { firsttime = 0; -#ifndef CLUSTER goto nextTime; /* no check on * first time point */ -#else - redostep = 0; - goto chkStep; -#endif } newdelta = ckt->CKTdelta; error = CKTtrunc(ckt,&newdelta); @@ -1467,18 +1432,13 @@ resume: fflush(stdout); #endif -#ifndef CLUSTER + /* go to 650 - trapezoidal */ goto nextTime; -#else - redostep = 0; - goto chkStep; -#endif + } else { /* newdelta <= .9 * ckt->CKTdelta */ -#ifndef CLUSTER ckt->CKTtime = ckt->CKTtime -ckt->CKTdelta; ckt->CKTstat->STATrejected ++; -#endif ckt->CKTdelta = newdelta; #ifdef STEPDEBUG fprintf (stderr, "delta set to truncation error result:point rejected\n") ; @@ -1505,15 +1465,6 @@ resume: EVTbackup(ckt, ckt->CKTtime + ckt->CKTdelta); /* gtri - end - wbk - Do event backup */ -#endif -#ifdef CLUSTER - chkStep: - if(CLUsync(ckt->CKTtime,&ckt->CKTdelta,redostep)){ - goto nextTime; - } else { - ckt->CKTtime -= olddelta; - ckt->CKTstat->STATrejected ++; - } #endif } /* NOTREACHED */ diff --git a/visualc/sharedspice.vcxproj b/visualc/sharedspice.vcxproj index c62fafd5e..461f74e6a 100644 --- a/visualc/sharedspice.vcxproj +++ b/visualc/sharedspice.vcxproj @@ -740,7 +740,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 - @@ -1544,7 +1543,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 - diff --git a/visualc/src/include/ngspice/config.h b/visualc/src/include/ngspice/config.h index 096b80fee..7daa091dc 100644 --- a/visualc/src/include/ngspice/config.h +++ b/visualc/src/include/ngspice/config.h @@ -47,9 +47,6 @@ /* Define to 1 if the `closedir' function returns void instead of `int'. */ /* #undef CLOSEDIR_VOID */ -/* Spice cluster support */ -/* #undef CLUSTER */ - /* Define if you want to debug ngspice shell */ /* #undef CPDEBUG */ diff --git a/visualc/vngspice-fftw.vcxproj b/visualc/vngspice-fftw.vcxproj index 026d116fe..59239b20a 100644 --- a/visualc/vngspice-fftw.vcxproj +++ b/visualc/vngspice-fftw.vcxproj @@ -956,7 +956,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 - @@ -1764,7 +1763,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 8e80be4e2..238bb520b 100644 --- a/visualc/vngspice.vcxproj +++ b/visualc/vngspice.vcxproj @@ -971,7 +971,6 @@ - @@ -1779,7 +1778,6 @@ - From 7fbb4450d49551821116a46f075dd95b21560c5b Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 20 Oct 2025 16:07:19 +0200 Subject: [PATCH 055/161] Improve comments, add note to user. --- src/spicelib/analysis/optran.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/spicelib/analysis/optran.c b/src/spicelib/analysis/optran.c index 8483560f3..0ba875d97 100644 --- a/src/spicelib/analysis/optran.c +++ b/src/spicelib/analysis/optran.c @@ -67,6 +67,8 @@ static bool nooptran = TRUE; we firstly fill the static vars opstepsize, opfinaltime, and opramptime. Later from inp.c we call com_optran again and set the data in ft_curckt->ci_defTask. + + com_optran is called from cp_init() as 'optran 1 1 1 100n 10u 0'. */ void com_optran(wordlist* wl) { wordlist* wltmp = wl; @@ -177,8 +179,10 @@ void com_optran(wordlist* wl) { goto bugquit; } /* optran deselected by setting opstepsize to 0 */ - if (opstepsize == 0) + if (opstepsize == 0) { nooptran = TRUE; + fprintf(stdout, "Note: Optran is deselected"); + } dataset = TRUE; if (errno == 0) @@ -311,8 +315,8 @@ OPtran(CKTcircuit *ckt, int oldconverged) int redostep; #endif - /* if optran command has not been given (in .spiceinit or in .control section), - we don' use optran */ + /* if optran command with step size 0 has been set in in .spiceinit or in .control section, + we don't use optran */ if (nooptran) return oldconverged; /* From 4d24b18f352ce41ce404c32a03155f8d18462ca2 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 21 Oct 2025 11:18:22 +0200 Subject: [PATCH 056/161] Remove all entries connected to IPC, an outdated (>30 years) method to link ngspice to a now defunct controller (ATESSE). --- configure.ac | 1 - src/Makefile.am | 3 - src/frontend/inp.c | 11 - src/frontend/inpcom.c | 43 +- src/frontend/resource.c | 8 - src/frontend/runcoms.c | 16 - src/spicelib/analysis/acan.c | 54 -- src/spicelib/analysis/cktdojob.c | 38 +- src/spicelib/analysis/dcop.c | 37 +- src/spicelib/analysis/dcpss.c | 81 +-- src/spicelib/analysis/dctran.c | 78 +-- src/spicelib/analysis/dctrcurv.c | 29 +- src/spicelib/analysis/noisean.c | 58 +- src/spicelib/analysis/span.c | 57 -- src/xspice/Makefile.am | 2 +- src/xspice/evt/evtdump.c | 252 +------- src/xspice/ipc/Makefile.am | 17 - src/xspice/ipc/ipc.c | 978 ------------------------------- src/xspice/ipc/ipcaegis.c | 309 ---------- src/xspice/ipc/ipcsockets.c | 756 ------------------------ src/xspice/ipc/ipcstdio.c | 77 --- src/xspice/ipc/ipctiein.c | 520 ---------------- visualc/sharedspice.vcxproj | 7 - visualc/vngspice-fftw.vcxproj | 7 - visualc/vngspice.vcxproj | 7 - 25 files changed, 54 insertions(+), 3392 deletions(-) delete mode 100644 src/xspice/ipc/Makefile.am delete mode 100644 src/xspice/ipc/ipc.c delete mode 100644 src/xspice/ipc/ipcaegis.c delete mode 100644 src/xspice/ipc/ipcsockets.c delete mode 100644 src/xspice/ipc/ipcstdio.c delete mode 100644 src/xspice/ipc/ipctiein.c diff --git a/configure.ac b/configure.ac index 565f8630a..94f8bf640 100644 --- a/configure.ac +++ b/configure.ac @@ -1428,7 +1428,6 @@ AC_CONFIG_FILES([Makefile src/xspice/mif/Makefile src/xspice/evt/Makefile src/xspice/enh/Makefile - src/xspice/ipc/Makefile src/xspice/idn/Makefile src/xspice/verilog/Makefile src/xspice/vhdl/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index aa2a49183..d1cedb9bf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -163,7 +163,6 @@ ngspice_LDADD += \ xspice/mif/libmifxsp.la \ xspice/evt/libevtxsp.la \ xspice/enh/libenhxsp.la \ - xspice/ipc/libipcxsp.la \ xspice/idn/libidnxsp.la endif ngspice_LDADD += $(XSPICEDLLIBS) @@ -459,7 +458,6 @@ if XSPICE_WANTED libspice_la_LIBADD += \ xspice/evt/libevtxsp.la \ xspice/enh/libenhxsp.la \ - xspice/ipc/libipcxsp.la \ xspice/idn/libidnxsp.la endif libspice_la_LIBADD += $(XSPICEDLLIBS) @@ -586,7 +584,6 @@ if XSPICE_WANTED libngspice_la_LIBADD += \ xspice/evt/libevtxsp.la \ xspice/enh/libenhxsp.la \ - xspice/ipc/libipcxsp.la \ xspice/idn/libidnxsp.la endif libngspice_la_LIBADD += $(XSPICEDLLIBS) diff --git a/src/frontend/inp.c b/src/frontend/inp.c index 56951b617..603132760 100644 --- a/src/frontend/inp.c +++ b/src/frontend/inp.c @@ -244,13 +244,6 @@ inp_list(FILE *file, struct card *deck, struct card *extras, int type) bool useout = (file == cp_out); int i = 1; - /* gtri - wbk - 03/07/91 - Don't use 'more' type output if ipc enabled */ -#ifdef XSPICE - if (g_ipc.enabled) - useout = FALSE; -#endif - /* gtri - end - 03/07/91 */ - if (useout) { out_init(); file = cp_more; @@ -1474,10 +1467,6 @@ inp_dodeck( if (dd->error) { char *p, *q; -#ifdef XSPICE - /* add setting of ipc syntax error flag */ - g_ipc.syntax_error = IPC_TRUE; -#endif p = dd->error; fflush(stdout); do { diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 2263b7b82..4edecffa8 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -1355,53 +1355,24 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name else { #ifdef XSPICE - /* gtri - modify - 12/12/90 - wbk - read from mailbox if ipc - * enabled */ - /* If IPC is not enabled, do equivalent of what SPICE did before - */ - if (!g_ipc.enabled) { - if (call_depth == 0 && line_count == 0) { - line_count++; - if (fgets(big_buff, 5000, fp)) - buffer = copy(big_buff); - } - else { - buffer = readline(fp); - if (!buffer) - break; - } + if (call_depth == 0 && line_count == 0) { + line_count++; + if (fgets(big_buff, 5000, fp)) + buffer = copy(big_buff); } else { - /* else, get the line from the ipc channel. */ - /* We assume that newlines are not sent by the client */ - /* so we add them here */ - char ipc_buffer[1025]; /* Had better be big enough */ - int ipc_len; - Ipc_Status_t ipc_status = - ipc_get_line(ipc_buffer, &ipc_len, IPC_WAIT); - if (ipc_status == IPC_STATUS_END_OF_DECK) { - buffer = NULL; + buffer = readline(fp); + if (!buffer) break; - } - else if (ipc_status == IPC_STATUS_OK) { - buffer = TMALLOC(char, strlen(ipc_buffer) + 3); - strcpy(buffer, ipc_buffer); - strcat(buffer, "\n"); - } - else { /* No good way to report this so just die */ - fprintf(stderr, "Error: IPC status not o.k.\n"); - controlled_exit(EXIT_FAILURE); - } } - /* gtri - end - 12/12/90 */ #else buffer = readline(fp); if (!buffer) { break; - } + } #endif } diff --git a/src/frontend/resource.c b/src/frontend/resource.c index 47b4ae400..303cb65de 100644 --- a/src/frontend/resource.c +++ b/src/frontend/resource.c @@ -213,14 +213,6 @@ printres(char *name) called = TRUE; } -#ifdef XSPICE - /* gtri - add - 12/12/90 - wbk - record cpu time used for ipc */ - g_ipc.cpu_time = (double) last_msec; - g_ipc.cpu_time /= 1000.0; - g_ipc.cpu_time += (double) last_sec; - /* gtri - end - 12/12/90 */ -#endif - yy = TRUE; #else if (!name || eq(name, "totalcputime")) diff --git a/src/frontend/runcoms.c b/src/frontend/runcoms.c index 10077f0b8..9d98747df 100644 --- a/src/frontend/runcoms.c +++ b/src/frontend/runcoms.c @@ -323,14 +323,6 @@ static int dosim( if (if_sens_run(ft_curckt->ci_ckt, ww, ft_curckt->ci_symtab) == 1) { /* The circuit was interrupted somewhere. */ fprintf(cp_err, "%s simulation interrupted\n", what); -#ifdef XSPICE - /* gtri - add - 12/12/90 - wbk - record error and return errchk */ - g_ipc.run_error = IPC_TRUE; - if (g_ipc.enabled) { - ipc_send_errchk(); - } - /* gtri - end - 12/12/90 */ -#endif } else { ft_curckt->ci_inprogress = FALSE; @@ -342,14 +334,6 @@ static int dosim( if (err == 1) { /* The circuit was interrupted somewhere. */ fprintf(cp_err, "%s simulation interrupted\n", what); -#ifdef XSPICE - /* record error and return errchk */ - g_ipc.run_error = IPC_TRUE; - if (g_ipc.enabled) { - ipc_send_errchk(); - } - /* gtri - end - 12/12/90 */ -#endif err = 0; } else if (err == 2) { diff --git a/src/spicelib/analysis/acan.c b/src/spicelib/analysis/acan.c index e00fa41a0..97b25e163 100644 --- a/src/spicelib/analysis/acan.c +++ b/src/spicelib/analysis/acan.c @@ -62,16 +62,9 @@ ACan(CKTcircuit* ckt, int restart) #ifdef XSPICE - /* gtri - add - wbk - 12/19/90 - Add IPC stuff and anal_init and anal_type */ - - /* Tell the beginPlot routine what mode we're in */ - g_ipc.anal_type = IPC_ANAL_AC; - /* Tell the code models what mode we're in */ g_mif_info.circuit.anal_type = MIF_DC; g_mif_info.circuit.anal_init = MIF_TRUE; - - /* gtri - end - wbk */ #endif /* start at beginning */ @@ -152,40 +145,6 @@ ACan(CKTcircuit* ckt, int restart) else fprintf(stdout, "\n Linear circuit, option noopac given: no OP analysis\n"); -#ifdef XSPICE - /* gtri - add - wbk - 12/19/90 - Add IPC stuff */ - - /* Send the operating point results for Mspice compatibility */ - if (g_ipc.enabled) - { - /* Call CKTnames to get names of nodes/branches used by - BeginPlot */ - /* Probably should free nameList after this block since - called again... */ - error = CKTnames(ckt, &numNames, &nameList); - if (error) return(error); - - /* We have to do a beginPlot here since the data to return is - * different for the DCOP than it is for the AC analysis. - * Moreover the begin plot has not even been done yet at this - * point... - */ - SPfrontEnd->OUTpBeginPlot(ckt, ckt->CKTcurJob, - ckt->CKTcurJob->JOBname, - NULL, IF_REAL, - numNames, nameList, IF_REAL, - &acPlot); - txfree(nameList); - - ipc_send_dcop_prefix(); - CKTdump(ckt, 0.0, acPlot); - ipc_send_dcop_suffix(); - - SPfrontEnd->OUTendPlot(acPlot); - } - /* gtri - end - wbk */ -#endif - ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG; error = CKTload(ckt); if (error) return(error); @@ -376,21 +335,8 @@ ACan(CKTcircuit* ckt, int restart) } #endif -#ifdef XSPICE - /* gtri - modify - wbk - 12/19/90 - Send IPC stuff */ - - if (g_ipc.enabled) - ipc_send_data_prefix(freq); - error = CKTacDump(ckt, freq, acPlot); - if (g_ipc.enabled) - ipc_send_data_suffix(); - - /* gtri - modify - wbk - 12/19/90 - Send IPC stuff */ -#else - error = CKTacDump(ckt, freq, acPlot); -#endif if (error) { UPDATE_STATS(DOING_AC); return(error); diff --git a/src/spicelib/analysis/cktdojob.c b/src/spicelib/analysis/cktdojob.c index 9b12fb097..627626a2e 100644 --- a/src/spicelib/analysis/cktdojob.c +++ b/src/spicelib/analysis/cktdojob.c @@ -157,51 +157,15 @@ CKTdoJob(CKTcircuit* ckt, int reset, TSKtask* task) if (!error) error = CKTunsetup(ckt); -#ifdef XSPICE - /* gtri - add - 12/12/90 - wbk - set ipc syntax error flag */ - if (error) g_ipc.syntax_error = IPC_TRUE; - /* gtri - end - 12/12/90 */ -#endif - if (!error) error = CKTsetup(ckt); -#ifdef XSPICE - /* gtri - add - 12/12/90 - wbk - set ipc syntax error flag */ - if (error) g_ipc.syntax_error = IPC_TRUE; - /* gtri - end - 12/12/90 */ -#endif - if (!error) error = CKTtemp(ckt); -#ifdef XSPICE - /* gtri - add - 12/12/90 - wbk - set ipc syntax error flag */ - if (error) g_ipc.syntax_error = IPC_TRUE; - /* gtri - end - 12/12/90 */ -#endif - if (error) { - -#ifdef XSPICE - /* gtri - add - 12/12/90 - wbk - return if syntax errors from parsing */ - if (g_ipc.enabled) { - if (g_ipc.syntax_error) - ; - else { - /* else, send (GO) errchk status if we got this far */ - /* Caller is responsible for sending NOGO status if we returned earlier */ - ipc_send_errchk(); - } - } - /* gtri - end - 12/12/90 */ -#endif - - return error; - - - }/* if error */ + } } error2 = OK; diff --git a/src/spicelib/analysis/dcop.c b/src/spicelib/analysis/dcop.c index fc94dae9d..4d8bfe8ca 100644 --- a/src/spicelib/analysis/dcop.c +++ b/src/spicelib/analysis/dcop.c @@ -35,18 +35,13 @@ DCop(CKTcircuit *ckt, int notused) NG_IGNORE(notused); #ifdef XSPICE -/* gtri - add - wbk - 12/19/90 - Add IPC stuff and initialize anal_init and anal_type */ - - /* Tell the beginPlot routine what mode we're in */ - g_ipc.anal_type = IPC_ANAL_DCOP; /* Tell the code models what mode we're in */ g_mif_info.circuit.anal_type = MIF_DC; g_mif_info.circuit.anal_init = MIF_TRUE; -/* gtri - end - wbk */ -#endif +#endif error = CKTnames(ckt,&numNames,&nameList); if(error) return(error); @@ -114,31 +109,17 @@ DCop(CKTcircuit *ckt, int notused) } #endif + converged = CKTload(ckt); -#ifdef XSPICE -/* gtri - modify - wbk - 12/19/90 - Send IPC data delimiters */ - if(g_ipc.enabled) - ipc_send_dcop_prefix(); - - CKTdump(ckt, 0.0, plot); - - if (ckt->CKTsoaCheck) - error = CKTsoaCheck(ckt); - - if(g_ipc.enabled) - ipc_send_dcop_suffix(); - -/* gtri - end - wbk */ -#else if(converged == 0) { - CKTdump(ckt, 0.0, plot); - if (ckt->CKTsoaCheck) - error = CKTsoaCheck(ckt); - } else { - fprintf(stderr,"error: circuit reload failed.\n"); - } -#endif + CKTdump(ckt, 0.0, plot); + if (ckt->CKTsoaCheck) + error = CKTsoaCheck(ckt); + } else { + fprintf(stderr,"error: circuit reload failed.\n"); + } + SPfrontEnd->OUTendPlot (plot); return(converged); } diff --git a/src/spicelib/analysis/dcpss.c b/src/spicelib/analysis/dcpss.c index 2ecc36943..d02b33712 100644 --- a/src/spicelib/analysis/dcpss.c +++ b/src/spicelib/analysis/dcpss.c @@ -84,15 +84,6 @@ DCpss(CKTcircuit *ckt, int ltra_num; CKTnode *node; -#ifdef XSPICE -/* gtri - add - wbk - 12/19/90 - Add IPC stuff */ - Ipc_Boolean_t ipc_firsttime = IPC_TRUE; - Ipc_Boolean_t ipc_secondtime = IPC_FALSE; - Ipc_Boolean_t ipc_delta_cut = IPC_FALSE; - double ipc_last_time = 0.0; - double ipc_last_delta = 0.0; -/* gtri - end - wbk - 12/19/90 - Add IPC stuff */ -#endif /* New variables */ int j, oscnNode; @@ -216,15 +207,12 @@ DCpss(CKTcircuit *ckt, #endif #ifdef XSPICE -/* gtri - add - wbk - 12/19/90 - Add IPC stuff and set anal_init and anal_type */ - /* Tell the beginPlot routine what mode we're in */ - g_ipc.anal_type = IPC_ANAL_TRAN; + /* set anal_init and anal_type */ /* Tell the code models what mode we're in */ g_mif_info.circuit.anal_type = MIF_DC; g_mif_info.circuit.anal_init = MIF_TRUE; -/* gtri - end - wbk */ #endif /* Time Domain plot start and prepared to be filled in later */ @@ -298,35 +286,18 @@ DCpss(CKTcircuit *ckt, #endif /* If no convergence reached - NO valid Operating Point */ - if(converged != 0) return(converged); + if(converged != 0) + return(converged); + #ifdef XSPICE -/* gtri - add - wbk - 12/19/90 - Add IPC stuff */ - - /* Send the operating point results for Mspice compatibility */ - if(g_ipc.enabled) { - ipc_send_dcop_prefix(); - CKTdump(ckt, 0.0, job->PSSplot_td); - ipc_send_dcop_suffix(); - } - -/* gtri - end - wbk */ - -/* gtri - add - wbk - 12/19/90 - set anal_init and anal_type */ - g_mif_info.circuit.anal_init = MIF_TRUE; /* Tell the code models what mode we're in */ g_mif_info.circuit.anal_type = MIF_TRAN; -/* gtri - end - wbk */ - -/* gtri - begin - wbk - Add Breakpoint stuff */ - /* Initialize the temporary breakpoint variables to infinity */ g_mif_info.breakpoint.current = HUGE_VAL; g_mif_info.breakpoint.last = HUGE_VAL; - -/* gtri - end - wbk - Add Breakpoint stuff */ #endif ckt->CKTstat->STATtimePts ++; @@ -434,52 +405,16 @@ DCpss(CKTcircuit *ckt, return(error); } #ifdef XSPICE -/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */ - if ((g_ipc.enabled) || wantevtdata) { + if (wantevtdata) { if (pss_state == PSS) { - /* Send event-driven results */ - EVTdump(ckt, IPC_ANAL_TRAN, 0.0); - - /* Then follow with analog results... */ - - /* Test to see if delta was cut by a breakpoint, */ - /* a non-convergence, or a too large truncation error */ - if(ipc_firsttime) - ipc_delta_cut = IPC_FALSE; - else if(ckt->CKTtime < (ipc_last_time + (0.999 * ipc_last_delta))) - ipc_delta_cut = IPC_TRUE; - else - ipc_delta_cut = IPC_FALSE; - - /* Record the data required to check for delta cuts */ - ipc_last_time = ckt->CKTtime; - ipc_last_delta = MIN(ckt->CKTdelta, ckt->CKTmaxStep); - - /* Send results data if time since last dump is greater */ - /* than 'mintime', or if first or second timepoints, */ - /* or if delta was cut */ - if( (ckt->CKTtime >= (g_ipc.mintime + g_ipc.last_time)) || - ipc_firsttime || ipc_secondtime || ipc_delta_cut ) { - - ipc_send_data_prefix(ckt->CKTtime); - CKTdump(ckt, ckt->CKTtime, job->PSSplot_td); - ipc_send_data_suffix(); - - if(ipc_firsttime) { - ipc_firsttime = IPC_FALSE; - ipc_secondtime = IPC_TRUE; - } else if(ipc_secondtime) { - ipc_secondtime = IPC_FALSE; - } - - g_ipc.last_time = ckt->CKTtime; - } + /* Send event-driven results */ + EVTdump(ckt, IPC_ANAL_TRAN, 0.0); } } else -/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */ + #endif if (pss_state == PSS) diff --git a/src/spicelib/analysis/dctran.c b/src/spicelib/analysis/dctran.c index fc5cf9f58..035105a79 100644 --- a/src/spicelib/analysis/dctran.c +++ b/src/spicelib/analysis/dctran.c @@ -99,13 +99,6 @@ DCtran(CKTcircuit *ckt, int ltra_num; CKTnode *node; #ifdef XSPICE - /* IPC stuff */ - Ipc_Boolean_t ipc_firsttime = IPC_TRUE; - Ipc_Boolean_t ipc_secondtime = IPC_FALSE; - Ipc_Boolean_t ipc_delta_cut = IPC_FALSE; - double ipc_last_time = 0.0; - double ipc_last_delta = 0.0; - /* xspice_breakpoints_processed 0: XSPICE models didn't have breakpoints in [last_accepted_time, CKTtime]. xspice_breakpoints_processed 1: @@ -176,13 +169,9 @@ DCtran(CKTcircuit *ckt, #endif #ifdef XSPICE - /* Add IPC stuff and set anal_init and anal_type */ - /* Tell the beginPlot routine what mode we're in */ - g_ipc.anal_type = IPC_ANAL_TRAN; - + /* set anal_init and anal_type */ /* Tell the code models what mode we're in */ g_mif_info.circuit.anal_type = MIF_DC; - g_mif_info.circuit.anal_init = MIF_TRUE; #endif /* Scan ckt->CKTnodes and create list of node names */ @@ -279,13 +268,6 @@ DCtran(CKTcircuit *ckt, return(converged); } #ifdef XSPICE - /* IPC stuff: Send the operating point results */ - if(g_ipc.enabled) { - ipc_send_dcop_prefix(); - CKTdump(ckt, 0.0, job->TRANplot); - ipc_send_dcop_suffix(); - } - /* set anal_init and anal_type */ g_mif_info.circuit.anal_init = MIF_TRUE; @@ -420,59 +402,21 @@ DCtran(CKTcircuit *ckt, UPDATE_STATS(DOING_TRAN); return(error); } + #ifdef XSPICE - - /* Send IPC stuff */ - if ((g_ipc.enabled) || wantevtdata) { - + /* Send evt data stuff in shared library */ + if (wantevtdata) { /* Send event-driven results */ EVTdump(ckt, IPC_ANAL_TRAN, 0.0); - /* Then follow with analog results... */ - - /* Test to see if delta was cut by a breakpoint, */ - /* a non-convergence, or a too large truncation error */ - if(ipc_firsttime) - ipc_delta_cut = IPC_FALSE; - else if(ckt->CKTtime < (ipc_last_time + (0.999 * ipc_last_delta))) - ipc_delta_cut = IPC_TRUE; - else - ipc_delta_cut = IPC_FALSE; - - /* Record the data required to check for delta cuts */ - ipc_last_time = ckt->CKTtime; - ipc_last_delta = MIN(ckt->CKTdelta, ckt->CKTmaxStep); - - /* Send results data if time since last dump is greater */ - /* than 'mintime', or if first or second timepoints, */ - /* or if delta was cut */ - if( (ckt->CKTtime >= (g_ipc.mintime + g_ipc.last_time)) || - ipc_firsttime || ipc_secondtime || ipc_delta_cut ) { - - if (wantevtdata) - CKTdump(ckt, ckt->CKTtime, job->TRANplot); - else { - ipc_send_data_prefix(ckt->CKTtime); - CKTdump(ckt, ckt->CKTtime, job->TRANplot); - ipc_send_data_suffix(); - } - - if(ipc_firsttime) { - ipc_firsttime = IPC_FALSE; - ipc_secondtime = IPC_TRUE; - } else if(ipc_secondtime) { - ipc_secondtime = IPC_FALSE; - } - - g_ipc.last_time = ckt->CKTtime; - } - /* End of Send IPC stuff*/ - } else + } #endif - /* Output the data of the current accepted time point */ - if((ckt->CKTmode&MODEUIC && ckt->CKTtime > 0 && ckt->CKTtime >= ckt->CKTinitTime) - || (!(ckt->CKTmode&MODEUIC) && ckt->CKTtime >= ckt->CKTinitTime)) - CKTdump(ckt, ckt->CKTtime, job->TRANplot); + + /* Output the data of the current accepted time point */ + if ((ckt->CKTmode & MODEUIC && ckt->CKTtime > 0 && ckt->CKTtime >= ckt->CKTinitTime) + || (!(ckt->CKTmode & MODEUIC) && ckt->CKTtime >= ckt->CKTinitTime)) { + CKTdump(ckt, ckt->CKTtime, job->TRANplot); + } #ifdef XSPICE /* Update event queues/data for accepted timepoint */ /* Note: this must be done AFTER sending results to SI so it can't diff --git a/src/spicelib/analysis/dctrcurv.c b/src/spicelib/analysis/dctrcurv.c index f2a46d3b4..dd312a637 100644 --- a/src/spicelib/analysis/dctrcurv.c +++ b/src/spicelib/analysis/dctrcurv.c @@ -165,17 +165,12 @@ DCtrCurv(CKTcircuit *ckt, int restart) #endif #ifdef XSPICE -/* gtri - add - wbk - 12/19/90 - Add IPC stuff and anal_init and anal_type */ - - /* Tell the beginPlot routine what mode we're in */ - g_ipc.anal_type = IPC_ANAL_DCTRCURVE; /* Tell the code models what mode we're in */ g_mif_info.circuit.anal_type = MIF_DC; g_mif_info.circuit.anal_init = MIF_TRUE; -/* gtri - end - wbk */ #endif error = CKTnames(ckt, &numNames, &nameList); @@ -383,18 +378,10 @@ DCtrCurv(CKTcircuit *ckt, int restart) ckt->CKTtime = ckt->CKTtemp - CONSTCtoK; #ifdef XSPICE -/* gtri - add - wbk - 12/19/90 - Add IPC stuff */ - /* If first time through, call CKTdump to output Operating Point info */ - /* for Mspice compatibility */ - - if (((g_ipc.enabled) || wantevtdata) && firstTime) { - ipc_send_dcop_prefix(); + if (wantevtdata && firstTime) { CKTdump(ckt, 0.0, plot); - ipc_send_dcop_suffix(); } - -/* gtri - end - wbk */ #endif #ifdef WANT_SENSE2 @@ -435,25 +422,11 @@ DCtrCurv(CKTcircuit *ckt, int restart) } #endif -#ifdef XSPICE -/* gtri - modify - wbk - 12/19/90 - Send IPC delimiters */ - - if (g_ipc.enabled) - ipc_send_data_prefix(ckt->CKTtime); -#endif - CKTdump(ckt,ckt->CKTtime,plot); if (ckt->CKTsoaCheck) error = CKTsoaCheck(ckt); -#ifdef XSPICE - if (g_ipc.enabled) - ipc_send_data_suffix(); - -/* gtri - end - wbk */ -#endif - if (firstTime) { firstTime = 0; if (ckt->CKTstate1 && ckt->CKTstate0) { diff --git a/src/spicelib/analysis/noisean.c b/src/spicelib/analysis/noisean.c index 5115f854f..de15daaf8 100644 --- a/src/spicelib/analysis/noisean.c +++ b/src/spicelib/analysis/noisean.c @@ -65,16 +65,9 @@ NOISEan(CKTcircuit* ckt, int restart) runDesc* plot = NULL; #ifdef XSPICE - /* gtri - add - wbk - 12/19/90 - Add IPC stuff and anal_init and anal_type */ - - /* Tell the beginPlot routine what mode we're in */ - g_ipc.anal_type = IPC_ANAL_NOI; - /* Tell the code models what mode we're in */ g_mif_info.circuit.anal_type = MIF_DC; g_mif_info.circuit.anal_init = MIF_TRUE; - - /* gtri - end - wbk */ #endif #ifdef KLU @@ -193,15 +186,15 @@ NOISEan(CKTcircuit* ckt, int restart) #endif #ifdef KLU - if (ckt->CKTmatrix->CKTkluMODE) - { - /* Conversion from Complex Matrix to Real Matrix */ - for (i = 0 ; i < DEVmaxnum ; i++) - if (DEVices [i] && DEVices [i]->DEVbindCSCComplexToReal && ckt->CKThead [i]) - DEVices [i]->DEVbindCSCComplexToReal (ckt->CKThead [i], ckt) ; + if (ckt->CKTmatrix->CKTkluMODE) + { + /* Conversion from Complex Matrix to Real Matrix */ + for (i = 0 ; i < DEVmaxnum ; i++) + if (DEVices [i] && DEVices [i]->DEVbindCSCComplexToReal && ckt->CKThead [i]) + DEVices [i]->DEVbindCSCComplexToReal (ckt->CKThead [i], ckt) ; - ckt->CKTmatrix->SMPkluMatrix->KLUmatrixIsComplex = KLUmatrixReal ; - } + ckt->CKTmatrix->SMPkluMatrix->KLUmatrixIsComplex = KLUmatrixReal ; + } #endif /* If no event-driven instances, do what SPICE normally does */ @@ -220,43 +213,8 @@ NOISEan(CKTcircuit* ckt, int restart) else { fprintf(stdout, "\n Linear circuit, option noopac given: no OP analysis\n"); } - -#ifdef XSPICE } // end of no XSPICE event-driven instances - /* gtri - add - wbk - 12/19/90 - Add IPC stuff */ - - /* Send the operating point results for Mspice compatibility */ - if (g_ipc.enabled) - { - /* Call CKTnames to get names of nodes/branches used by - BeginPlot */ - /* Probably should free nameList after this block since - called again... */ - error = CKTnames(ckt, &numNames, &nameList); - if (error) return(error); - - /* We have to do a beginPlot here since the data to return is - * different for the DCOP than it is for the AC analysis. - * Moreover the begin plot has not even been done yet at this - * point... - */ - SPfrontEnd->OUTpBeginPlot(ckt, ckt->CKTcurJob, - ckt->CKTcurJob->JOBname, - NULL, IF_REAL, - numNames, nameList, IF_REAL, - &noiPlot); - txfree(nameList); - - ipc_send_dcop_prefix(); - CKTdump(ckt, 0.0, noiPlot); - ipc_send_dcop_suffix(); - - SPfrontEnd->OUTendPlot(noiPlot); - } - /* gtri - end - wbk */ -#endif - /* Patch to noisean.c by Richard D. McRoberts. */ ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG; error = CKTload(ckt); diff --git a/src/spicelib/analysis/span.c b/src/spicelib/analysis/span.c index 46c7756fe..b70eab72d 100644 --- a/src/spicelib/analysis/span.c +++ b/src/spicelib/analysis/span.c @@ -386,18 +386,9 @@ SPan(CKTcircuit* ckt, int restart) } #ifdef XSPICE - /* gtri - add - wbk - 12/19/90 - Add IPC stuff and anal_init and anal_type */ - - /* Tell the beginPlot routine what mode we're in */ - - // For now, let's keep this as IPC_ANAL_AC (TBD) - g_ipc.anal_type = IPC_ANAL_AC; - /* Tell the code models what mode we're in */ g_mif_info.circuit.anal_type = MIF_DC; g_mif_info.circuit.anal_init = MIF_TRUE; - - /* gtri - end - wbk */ #endif /* start at beginning */ @@ -475,40 +466,6 @@ SPan(CKTcircuit* ckt, int restart) else fprintf(stdout, "\n Linear circuit, option noopac given: no OP analysis\n"); -#ifdef XSPICE - /* gtri - add - wbk - 12/19/90 - Add IPC stuff */ - - /* Send the operating point results for Mspice compatibility */ - if (g_ipc.enabled) - { - /* Call CKTnames to get names of nodes/branches used by - BeginPlot */ - /* Probably should free nameList after this block since - called again... */ - error = CKTnames(ckt, &numNames, &nameList); - if (error) return(error); - - /* We have to do a beginPlot here since the data to return is - * different for the DCOP than it is for the AC analysis. - * Moreover the begin plot has not even been done yet at this - * point... - */ - SPfrontEnd->OUTpBeginPlot(ckt, ckt->CKTcurJob, - ckt->CKTcurJob->JOBname, - NULL, IF_REAL, - numNames, nameList, IF_REAL, - &spPlot); - txfree(nameList); - - ipc_send_dcop_prefix(); - CKTdump(ckt, 0.0, spPlot); - ipc_send_dcop_suffix(); - - SPfrontEnd->OUTendPlot(spPlot); - } - /* gtri - end - wbk */ -#endif - ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG; error = CKTload(ckt); if (error) return(error); @@ -937,22 +894,8 @@ SPan(CKTcircuit* ckt, int restart) data->lstFreq = freq; } - -#ifdef XSPICE - /* gtri - modify - wbk - 12/19/90 - Send IPC stuff */ - - if (g_ipc.enabled) - ipc_send_data_prefix(freq); - error = CKTspDump(ckt, freq, spPlot, job->SPdoNoise); - if (g_ipc.enabled) - ipc_send_data_suffix(); - - /* gtri - modify - wbk - 12/19/90 - Send IPC stuff */ -#else - error = CKTspDump(ckt, freq, spPlot, job->SPdoNoise); -#endif if (error) { UPDATE_STATS(DOING_AC); tfree(internalNoiseAN); diff --git a/src/xspice/Makefile.am b/src/xspice/Makefile.am index 7359ac577..fe83489bb 100644 --- a/src/xspice/Makefile.am +++ b/src/xspice/Makefile.am @@ -9,7 +9,7 @@ EXTRA_DIST = README examples icm xspice.c .gitignore \ tlines/msline_common.c tlines/msline_common.h \ tlines/tline_common.c tlines/tline_common.h -SUBDIRS = mif cm enh evt ipc idn cmpp icm verilog vhdl +SUBDIRS = mif cm enh evt idn cmpp icm verilog vhdl dist-hook: rm -f "$(distdir)/icm/makedefs" diff --git a/src/xspice/evt/evtdump.c b/src/xspice/evt/evtdump.c index 2f1c6db61..40a73f083 100644 --- a/src/xspice/evt/evtdump.c +++ b/src/xspice/evt/evtdump.c @@ -53,10 +53,6 @@ NON-STANDARD FEATURES #include "ngspice/evtproto.h" #include "ngspice/evtudn.h" -#include "ngspice/ipc.h" -#include "ngspice/ipctiein.h" -#include "ngspice/ipcproto.h" - #ifdef SHARED_MODULE /* global flag, TRUE if callback is used */ extern bool wantevtdata; @@ -76,13 +72,6 @@ static void EVTsharedsend_line( int mode); /* mode (op, dc, tran) we are in */ #endif -static void EVTsend_line( - int ipc_index, /* The index used in the dictionary */ - double step, /* The analysis step */ - void *node_value, /* The node value */ - int udn_index); /* The user-defined node index */ - - /* EVTdump @@ -129,250 +118,25 @@ void EVTdump( double step) /* The sweep step for a DCTRCURVE analysis, or */ /* 0.0 for DCOP and TRAN */ { - static evtdump_dict_t *node_dict = NULL; - static int num_send_nodes; - - int i; - int j; - int num_nodes; - int num_modified; - int index; - - char *name; - int name_len; - - Mif_Boolean_t firstcall; - - Evt_Node_Data_t *node_data; - - Evt_Node_t *rhsold; - Evt_Node_t **head; - Evt_Node_t *here; - - Evt_Node_Info_t **node_table; - - char buff[10000]; - - Mif_Boolean_t equal; #ifdef SHARED_MODULE - if((! g_ipc.enabled) && (!wantevtdata)) + if (!wantevtdata) return; - if ((!g_ipc.enabled) && (wantevtdata)) { + else { EVTshareddump(ckt, mode, step); return; } #else - /* Return immediately if IPC is not enabled */ - if(! g_ipc.enabled) - return; + (void)*ckt; + (void)mode; + (void)step; + + /* Return immediately */ + return; #endif - /* Get number of event-driven nodes */ - num_nodes = ckt->evt->counts.num_nodes; - - /* Exit immediately if no event-driven nodes in circuit */ - if(num_nodes <= 0) - return; - - - /* Get pointers for fast access to event data */ - node_data = ckt->evt->data.node; - node_table = ckt->evt->info.node_table; - rhsold = node_data->rhsold; - head = node_data->head; - - - /* Determine if this is the first call */ - if(node_dict == NULL) - firstcall = MIF_TRUE; - else - firstcall = MIF_FALSE; - - - /* If this is the first call, get the dictionary info */ - if(firstcall) { - - /* Allocate local data structure used to process nodes */ - node_dict = TMALLOC(evtdump_dict_t, num_nodes); - - /* Loop through all nodes to determine which nodes should be sent. */ - /* Only nodes not within subcircuits qualify. */ - - num_send_nodes = 0; - for(i = 0; i < num_nodes; i++) { - - /* Get the name of the node. */ - name = node_table[i]->name; - - /* If name is in a subcircuit, mark that node should not be sent */ - /* and continue to next node. */ - name_len = (int) strlen(name); - for(j = 0; j < name_len; j++) { - if(name[j] == ':') - break; - } - if(j < name_len) { - node_dict[i].send = MIF_FALSE; - continue; - } - - /* Otherwise, fill in info in dictionary. */ - node_dict[i].send = MIF_TRUE; - node_dict[i].ipc_index = num_send_nodes; - node_dict[i].node_name_str = name; - node_dict[i].udn_type_str = g_evt_udn_info[node_table[i]->udn_index]->name; - - /* Increment the count of nodes to be sent. */ - num_send_nodes++; - } /* end for */ - } /* end if first call */ - - - /* Exit if there are no nodes to be sent */ - if(num_send_nodes <= 0) - return; - - - /* If this is the first call, send the dictionary */ - if(firstcall) { - ipc_send_evtdict_prefix(); - for(i = 0; i < num_nodes; i++) { - if(node_dict[i].send) { - sprintf(buff, "%d %s %s", node_dict[i].ipc_index, - node_dict[i].node_name_str, - node_dict[i].udn_type_str); - ipc_send_line(buff); - } - } - ipc_send_evtdict_suffix(); - } - - /* If this is the first call, send the operating point solution */ - /* and return. */ - if(firstcall) { - ipc_send_evtdata_prefix(); - for(i = 0; i < num_nodes; i++) { - if(node_dict[i].send) { - EVTsend_line(node_dict[i].ipc_index, - step, - rhsold[i].node_value, - node_table[i]->udn_index); - } - } - ipc_send_evtdata_suffix(); - return; - } - - /* Otherwise, this must be DCTRCURVE or TRAN mode and we need to */ - /* send only stuff that has changed since the last call. */ - /* The determination of what to send is modeled after code in */ - /* EVTop_save() for DCTRCURVE and EVTaccept() for TRAN. */ - - if(mode == IPC_ANAL_DCTRCURVE) { - /* Send data prefix */ - ipc_send_evtdata_prefix(); - /* Loop through event nodes */ - for(i = 0; i < num_nodes; i++) { - /* If dictionary indicates this node should be sent */ - if(node_dict[i].send) { - /* Locate end of node data */ - here = head[i]; - for(;;) { - if(here->next) - here = here->next; - else - break; - } - /* Compare entry at end of list to rhsold */ - g_evt_udn_info[node_table[i]->udn_index]->compare ( - rhsold[i].node_value, - here->node_value, - &equal); - /* If value in rhsold is different, send it */ - if(!equal) { - EVTsend_line(node_dict[i].ipc_index, - step, - rhsold[i].node_value, - node_table[i]->udn_index); - } - } - } - /* Send data suffix and return */ - ipc_send_evtdata_suffix(); - return; - } - - - if(mode == IPC_ANAL_TRAN) { - /* Send data prefix */ - ipc_send_evtdata_prefix(); - /* Loop through list of nodes modified since last time */ - num_modified = node_data->num_modified; - for(i = 0; i < num_modified; i++) { - /* Get the index of the node modified */ - index = node_data->modified_index[i]; - /* If dictionary indicates this node should be sent */ - if(node_dict[index].send) { - /* Scan through new events and send the data for each event */ - here = *(node_data->last_step[index]); - while((here = here->next) != NULL) { - EVTsend_line(node_dict[index].ipc_index, - here->step, - here->node_value, - node_table[index]->udn_index); - } - } - } - /* Send data suffix and return */ - ipc_send_evtdata_suffix(); - return; - } } - - -/* -EVTsend_line - -This function formats the event node data and sends it to the IPC channel. -*/ - - -static void EVTsend_line( - int ipc_index, /* The index used in the dictionary */ - double step, /* The analysis step */ - void *node_value, /* The node value */ - int udn_index) /* The user-defined node index */ -{ - double dvalue; - char *svalue; - void *pvalue; - int len; - - /* Get the data to send */ - if(g_evt_udn_info[udn_index]->plot_val) - g_evt_udn_info[udn_index]->plot_val (node_value, "", &dvalue); - else - dvalue = 0.0; - - if(g_evt_udn_info[udn_index]->print_val) - g_evt_udn_info[udn_index]->print_val (node_value, "", &svalue); - else - svalue = ""; - - if(g_evt_udn_info[udn_index]->ipc_val) - g_evt_udn_info[udn_index]->ipc_val (node_value, &pvalue, &len); - else { - pvalue = NULL; - len = 0; - } - - /* Send it to the IPC channel */ - ipc_send_event(ipc_index, step, dvalue, svalue, pvalue, len); -} - - #ifdef SHARED_MODULE static void EVTshareddump( CKTcircuit *ckt, /* The circuit structure */ diff --git a/src/xspice/ipc/Makefile.am b/src/xspice/ipc/Makefile.am deleted file mode 100644 index 40e4650c6..000000000 --- a/src/xspice/ipc/Makefile.am +++ /dev/null @@ -1,17 +0,0 @@ -## Process this file with automake to produce Makefile.in -# -# JW 3/9/01 - had a go and makeing an autoconf script. - -noinst_LTLIBRARIES = libipcxsp.la - -libipcxsp_la_SOURCES = \ - ipcaegis.c \ - ipc.c \ - ipcsockets.c \ - ipcstdio.c \ - ipctiein.c - -AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include -I$(top_srcdir)/src/spicelib/devices -AM_CFLAGS = $(STATIC) - -MAINTAINERCLEANFILES = Makefile.in diff --git a/src/xspice/ipc/ipc.c b/src/xspice/ipc/ipc.c deleted file mode 100644 index a689c051b..000000000 --- a/src/xspice/ipc/ipc.c +++ /dev/null @@ -1,978 +0,0 @@ -/*============================================================================ -FILE IPC.c - -MEMBER OF process XSPICE - -Public Domain - -Georgia Tech Research Corporation -Atlanta, Georgia 30332 -PROJECT A-8503 - -AUTHORS - - 9/12/91 Steve Tynor - -MODIFICATIONS - - 6/13/92 Bill Kuhn Added some comments - -SUMMARY - - Provides compatibility for the new SPICE simulator to both the MSPICE user - interface and BCP (via ATESSE v.1 style AEGIS mailboxes) and the new ATESSE - v.2 Simulator Interface and BCP (via Bsd Sockets). - - The Interprocess Communications package provides functions - called to receive XSPICE decks from the ATESSE Simulator Interface - or Batch Control processes, and to return results to those - processes. Functions callable from the simulator packages include: - - ipc_initialize_server - ipc_terminate_server - ipc_get_line - ipc_send_line - ipc_send_data_prefix - ipc_send_data_suffix - ipc_send_dcop_prefix - ipc_send_dcop_suffix - ipc_send_evtdict_prefix - ipc_send_evtdict_suffix - ipc_send_evtdata_prefix - ipc_send_evtdata_suffix - ipc_send_errchk - ipc_send_end - ipc_send_boolean - ipc_send_int - ipc_send_double - ipc_send_complex - ipc_send_event - ipc_flush - - These functions communicate with a set of transport-level functions - that implement the interprocess communications under one of - the following protocol types determined by a compile-time option: - - BSD UNIX Sockets - HP/Apollo Mailboxes - - For each transport protocol, the following functions are written: - - ipc_transport_initialize_server - ipc_transport_get_line - ipc_transport_terminate_server - ipc_transport_send_line - - - -============================================================================*/ - -#include "ngspice/ngspice.h" - -#include -#include "ngspice/memory.h" /* NOTE: I think this is a Sys5ism (there is not man - * page for it under Bsd, but it's in /usr/include - * and it has a BSD copyright header. Go figure. - */ - -#include "ngspice/ipc.h" -#include "ngspice/ipctiein.h" -#include "ngspice/ipcproto.h" - - -/* - * Conditional compilation sanity check: - */ -#if !defined (IPC_AEGIS_MAILBOXES) && !defined (IPC_UNIX_SOCKETS)\ - && !defined (IPC_DEBUG_VIA_STDIO) -" compiler error - must specify a transport mechanism"; -#endif - -/* - * static 'globals' - */ - -/* typedef unsigned char Buffer_Char_t; */ -typedef char Buffer_Char_t; - -#define OUT_BUFFER_SIZE 1000 -#define MAX_NUM_RECORDS 200 -static int end_of_record_index [MAX_NUM_RECORDS]; -static int num_records; -static Buffer_Char_t out_buffer [OUT_BUFFER_SIZE]; -static int fill_count; - -static Ipc_Mode_t mode; -static Ipc_Protocol_t protocol; -static Ipc_Boolean_t end_of_deck_seen; -static int batch_fd; - -#define FMT_BUFFER_SIZE 80 -static char fmt_buffer [FMT_BUFFER_SIZE]; - -/*---------------------------------------------------------------------------*/ -Ipc_Boolean_t -kw_match (char *keyword, char *str) - /* - * returns IPC_TRUE if the first `strlen(keyword)' characters of `str' match - * the ones in `keyword' - case sensitive - */ -{ - char *k = keyword; - char *s = str; - - /* - * quit if we run off the end of either string: - */ - while (*s && *k) { - if (*s != *k) { - return IPC_FALSE; - } - s++; - k++; - } - /* - * if we get this far, it sould be because we ran off the end of the - * keyword else we didn't match: - */ - return (*k == '\0'); -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_initialize_server - -This function creates the interprocess communication channel -server mailbox or socket. -*/ - - -Ipc_Status_t -ipc_initialize_server ( - char *server_name, /* Mailbox path or host/portnumber pair */ - Ipc_Mode_t m, /* Interactive or batch */ - Ipc_Protocol_t p ) /* Type of IPC protocol */ - /* - * For mailboxes, `server_name' would be the mailbox pathname; for - * sockets, this needs to be a host/portnumber pair. Maybe this should be - * automatically generated by the routine... - */ -{ - Ipc_Status_t status; - char batch_filename [1025]; - - mode = m; - protocol = p; - end_of_deck_seen = IPC_FALSE; - - num_records = 0; - fill_count = 0; - - status = ipc_transport_initialize_server (server_name, m, p, - batch_filename); - - if (status != IPC_STATUS_OK) { - fprintf (stderr, "ERROR: IPC: error initializing server\n"); - return IPC_STATUS_ERROR; - } - - if (mode == IPC_MODE_BATCH) { -#ifdef IPC_AEGIS_MAILBOXES - strcat (batch_filename, ".log"); -#endif - batch_fd = open (batch_filename, O_WRONLY | O_CREAT, 0666); - if (batch_fd < 0) { - /* fprintf (stderr, "ERROR: IPC: Error opening batch output file: %s\n",batch_filename); */ - perror ("IPC"); - return IPC_STATUS_ERROR; - } - } - return status; -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_terminate_server - -This function deallocates the interprocess communication channel -mailbox or socket. -*/ - - - -Ipc_Status_t -ipc_terminate_server (void) -{ - return ipc_transport_terminate_server (); -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_get_line - -This function gets a SPICE deck input line from the interprocess -communication channel. Any special control commands in the deck -beginning with a ``>'' or ``#'' character are processed internally by -this function and not returned to SPICE. -*/ - -Ipc_Status_t -ipc_get_line ( - char *str, /* Text retrieved from IPC channel */ - int *len, /* Length of text string */ - Ipc_Wait_t wait ) /* Select blocking or non-blocking */ - /* - * Reads one SPICE line from the connection. Strips any control lines - * which cannot be interpretted by the simulator (e.g. >INQCON) and - * processes them. If such a line is read, it is processed and the next - * line is read. `ipc_get_line' does not return until a non-interceptable - * line is read or end of file. - * - * If `wait' is IPC_NO_WAIT and there is no data available on the - * connection, `ipc_get_line' returns IPC_STATUS_NO_DATA. If `wait' is - * IPC_WAIT, `ipc_get_line' will not return until there is data available - * or and end of file condition is reached or an error occurs. - * - * Intercepts and processes the following commands: - * #RETURNI, #MINTIME, #VTRANS, - * >PAUSE, >CONT, >STOP, >INQCON, >NETLIST, >ENDNET - * Other > records are silently ignored. - * - * Intercepts old-style .TEMP card generated by MSPICE - * - * Returns: - * IPC_STATUS_OK - for successful reads - * IPC_STATUS_NO_DATA - when NO_WAIT and no data available - * IPC_STATUS_END_OF_DECK - at end of deck (>ENDNET seen) - * IPC_STATUS_ERROR - otherwise - */ -{ - Ipc_Status_t status; - Ipc_Boolean_t need_another = IPC_TRUE; - - do { - - status = ipc_transport_get_line (str, len, wait); - - switch (status) { - case IPC_STATUS_NO_DATA: - case IPC_STATUS_ERROR: - need_another = IPC_FALSE; - break; - case IPC_STATUS_END_OF_DECK: - assert (0); /* should never get this from the low-level get-line */ - status = IPC_STATUS_ERROR; - need_another = IPC_FALSE; - break; - case IPC_STATUS_OK: - /* - * Got a good line - check to see if it's one of the ones we need to - * intercept - */ - if (str[0] == '>') { - if (kw_match (">STOP", str)) { - ipc_handle_stop(); - } else if (kw_match (">PAUSE", str)) { - /* assert (need_another); */ - /* - * once more around the loop to do a blocking wait for the >CONT - */ - need_another = IPC_TRUE; - wait = IPC_WAIT; - } else if (kw_match (">INQCON", str)) { - ipc_send_line (">ABRTABL"); - ipc_send_line (">PAUSABL"); - ipc_send_line (">KEEPABL"); - status = ipc_flush (); - if (IPC_STATUS_OK != status) { - need_another = IPC_FALSE; - } - } else if (kw_match (">ENDNET", str)) { - end_of_deck_seen = IPC_TRUE; - need_another = IPC_FALSE; - status = IPC_STATUS_END_OF_DECK; - } else { - /* silently ignore */ - } - } else if (str[0] == '#') { - if (kw_match ("#RETURNI", str)) { - ipc_handle_returni (); - } else if (kw_match ("#MINTIME", str)) { - double d1/*,d2*/; - if (1 != sscanf (&str[8], "%lg", &d1)) { - status = IPC_STATUS_ERROR; - need_another = IPC_FALSE; - } else { - ipc_handle_mintime (d1); - } - } else if (kw_match ("#VTRANS", str)) { - char *tok1; - char *tok2; - char *tok3; - - tok1 = &str[8]; - for (tok2 = tok1; *tok2; tok2++) { - if (isspace_c(*tok2)) { - *tok2 = '\0'; - tok2++; - break; - } - } - for(tok3 = tok2; *tok3; tok3++) { - if(isspace_c(*tok3)) { - *tok3 = '\0'; - break; - } - } - ipc_handle_vtrans (tok1, tok2); - } else { - /* silently ignore */ - } - } else if (str[0] == '.') { - if (kw_match (".TEMP", str)) { - /* don't pass .TEMP card to caller */ - printf("Old-style .TEMP card found - ignored\n"); - } - else { - /* pass all other . cards to the caller */ - need_another = IPC_FALSE; - } - } else { - /* - * Not a '>' or '#' record - let the caller deal with it - */ - need_another = IPC_FALSE; - } - break; - default: - /* - * some unknown status value! - */ - assert (0); - status = IPC_STATUS_ERROR; - need_another = IPC_FALSE; - break; - } - } while (need_another); - - return status; -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_flush - -This function flushes the interprocess communication channel -buffer contents. -*/ - -Ipc_Status_t -ipc_flush (void) - /* - * Flush all buffered messages out the connection. - */ -{ - Ipc_Status_t status; - int last = 0; - /*int bytes;*/ - int i; - - /* if batch mode */ - if (mode == IPC_MODE_BATCH) { - - assert (batch_fd >= 0); - - /* for number of records in buffer */ - for (i = 0; i < num_records; i++) { - - /* write the records to the .log file */ - if ((end_of_record_index [i] - last) != - write (batch_fd, &out_buffer[last], (size_t) (end_of_record_index [i] - last))) { - /* fprintf (stderr,"ERROR: IPC: Error writing to batch output file\n"); */ - perror ("IPC"); - return IPC_STATUS_ERROR; - } - - /* If the record is one of the batch simulation status messages, */ - /* send it over the ipc channel too */ - if( kw_match("#ERRCHK", &out_buffer[last]) || - kw_match(">ENDANAL", &out_buffer[last]) || - kw_match(">ABORTED", &out_buffer[last]) ) { - - status = ipc_transport_send_line (&out_buffer[last], - end_of_record_index [i] - last); - if (IPC_STATUS_OK != status) { - return status; - } - } - last = end_of_record_index [i]; - } - - /* else, must be interactive mode */ - } else { - /* send the full buffer over the ipc channel */ - status = ipc_transport_send_line (&out_buffer[0], - end_of_record_index [num_records - 1]); - if (IPC_STATUS_OK != status) { - return status; - } - } - - /* reset counts to zero and return */ - num_records = 0; - fill_count = 0; - return IPC_STATUS_OK; -} - -/*---------------------------------------------------------------------------*/ -Ipc_Status_t -ipc_send_line_binary ( - char *str, - int len ) - /* - * Same as `ipc_send_line' except does not expect the str to be null - * terminated. Sends exactly `len' characters. Use this for binary data - * strings that may have embedded nulls. - * - * Modified by wbk to append newlines for compatibility with - * ATESSE 1.0 - * - */ -{ - int length = len + 1; - /*int diff;*/ - Ipc_Status_t status; - - /* - * If we can't add the whole str to the buffer, or if there are no more - * record indices free, flush the buffer: - */ - if (((fill_count + length) >= OUT_BUFFER_SIZE) || - (num_records >= MAX_NUM_RECORDS)) { - status = ipc_flush (); - if (IPC_STATUS_OK != status) { - return status; - } - } - - /* - * make sure that the str will fit: - */ - if (length + fill_count > OUT_BUFFER_SIZE) { - /* fprintf (stderr,"ERROR: IPC: String too long to fit in output buffer (> %d bytes) - truncated\n",OUT_BUFFER_SIZE); */ - length = OUT_BUFFER_SIZE - fill_count; - } - - /* - * finally, concatenate the str to the end of the buffer and add the newline: - */ - memcpy (&out_buffer[fill_count], str, (size_t) len); - fill_count += len; - - out_buffer[fill_count] = '\n'; - fill_count++; - - end_of_record_index [num_records++] = fill_count; - - return IPC_STATUS_OK; -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_line - -This function sends a line of text over the interprocess -communication channel. -*/ - - -Ipc_Status_t -ipc_send_line (char *str ) /* The text to send */ -{ - int len; - int send_len; - - char *s; - - Ipc_Status_t status= IPC_STATUS_OK; - - - len = (int) strlen(str); - - /* if short string, send it immediately */ - if(len < 80) - status = ipc_send_line_binary (str, len); - else { - /* otherwise, we have to send it as multiple strings */ - /* because Mspice cannot handle things longer than 80 chars */ - s = str; - while(len > 0) { - if(len < 80) - send_len = len; - else - send_len = 79; - status = ipc_send_line_binary (str, send_len); - if(status != IPC_STATUS_OK) - break; - s += send_len; - len -= send_len; - } - } - - return(status); -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_data_prefix - -This function sends a ``>DATAB'' line over the interprocess -communication channel to signal that this is the beginning of a -results dump for the current analysis point. -*/ - -Ipc_Status_t -ipc_send_data_prefix (double time ) /* The analysis point for this data set */ -{ - char buffer[40]; - - sprintf (buffer, ">DATAB %.5E", time); - return ipc_send_line (buffer); -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_data_suffix - -This function sends a ``>ENDDATA'' line over the interprocess -communication channel to signal that this is the end of a results -dump from a particular analysis point. -*/ - - -Ipc_Status_t -ipc_send_data_suffix (void) -{ - Ipc_Status_t status; - - status = ipc_send_line (">ENDDATA"); - - if(status != IPC_STATUS_OK) - return(status); - - return(ipc_flush()); -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_dcop_prefix - -This function sends a ``>DCOPB'' line over the interprocess -communication channel to signal that this is the beginning of a -results dump from a DC operating point analysis. -*/ - -Ipc_Status_t -ipc_send_dcop_prefix (void) -{ - return ipc_send_line (">DCOPB"); -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_dcop_suffix - -This function sends a ``>ENDDATA'' line over the interprocess -communication channel to signal that this is the end of a results -dump from a particular analysis point. -*/ - - -Ipc_Status_t -ipc_send_dcop_suffix (void) -{ - Ipc_Status_t status; - - status = ipc_send_line (">ENDDCOP"); - - if(status != IPC_STATUS_OK) - return(status); - - return(ipc_flush()); -} - - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_evtdict_prefix - -This function sends a ``>EVTDICT'' line over the interprocess -communication channel to signal that this is the beginning of an -event-driven node dictionary. - -The line is sent only if the IPC is configured -for UNIX sockets, indicating use with the V2 ATESSE SI process. -*/ - -Ipc_Status_t -ipc_send_evtdict_prefix (void) -{ -#ifdef IPC_AEGIS_MAILBOXES - return IPC_STATUS_OK; -#else - return ipc_send_line (">EVTDICT"); -#endif -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_evtdict_suffix - -This function sends a ``>ENDDICT'' line over the interprocess -communication channel to signal that this is the end of an -event-driven node dictionary. - -The line is sent only if the IPC is configured -for UNIX sockets, indicating use with the V2 ATESSE SI process. -*/ - - -Ipc_Status_t -ipc_send_evtdict_suffix (void) -{ -#ifdef IPC_AEGIS_MAILBOXES - return IPC_STATUS_OK; -#else - Ipc_Status_t status; - - status = ipc_send_line (">ENDDICT"); - - if(status != IPC_STATUS_OK) - return(status); - - return(ipc_flush()); -#endif -} - - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_evtdata_prefix - -This function sends a ``>EVTDATA'' line over the interprocess -communication channel to signal that this is the beginning of an -event-driven node data block. - -The line is sent only if the IPC is configured -for UNIX sockets, indicating use with the V2 ATESSE SI process. -*/ - -Ipc_Status_t -ipc_send_evtdata_prefix (void) -{ -#ifdef IPC_AEGIS_MAILBOXES - return IPC_STATUS_OK; -#else - return ipc_send_line (">EVTDATA"); -#endif -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_evtdata_suffix - -This function sends a ``>ENDDATA'' line over the interprocess -communication channel to signal that this is the end of an -event-driven node data block. - -The line is sent only if the IPC is configured -for UNIX sockets, indicating use with the V2 ATESSE SI process. -*/ - - -Ipc_Status_t -ipc_send_evtdata_suffix (void) -{ -#ifdef IPC_AEGIS_MAILBOXES - return IPC_STATUS_OK; -#else - Ipc_Status_t status; - - status = ipc_send_line (">ENDDATA"); - - if(status != IPC_STATUS_OK) - return(status); - - return(ipc_flush()); -#endif -} - - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_errchk - -This function sends a ``\ERRCHK [GO|NOGO]'' message over the -interprocess communication channel to signal that the initial -parsing of the input deck has been completed and to indicate -whether or not errors were detected. -*/ - - -Ipc_Status_t -ipc_send_errchk(void) -{ - char str[IPC_MAX_LINE_LEN+1]; - Ipc_Status_t status; - - if(g_ipc.errchk_sent) - return(IPC_STATUS_OK); - - if(g_ipc.syntax_error) - sprintf(str, "#ERRCHK NOGO"); - else - sprintf(str, "#ERRCHK GO"); - - g_ipc.errchk_sent = IPC_TRUE; - - status = ipc_send_line(str); - if(status != IPC_STATUS_OK) - return(status); - - return(ipc_flush()); -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_end - -This function sends either an ``>ENDANAL'' or an ``>ABORTED'' message -over the interprocess communication channel together with the -total CPU time used to indicate whether or not the simulation -completed normally. -*/ - - -Ipc_Status_t -ipc_send_end(void) -{ - char str[IPC_MAX_LINE_LEN+1]; - Ipc_Status_t status; - - if(g_ipc.syntax_error || g_ipc.run_error) - sprintf(str, ">ABORTED %.4f", g_ipc.cpu_time); - else - sprintf(str, ">ENDANAL %.4f", g_ipc.cpu_time); - - status = ipc_send_line(str); - if(status != IPC_STATUS_OK) - return(status); - - return(ipc_flush()); -} - - -/*---------------------------------------------------------------------------*/ -int -stuff_binary_v1 ( - double d1, double d2, /* doubles to be stuffed */ - int n, /* how many of d1, d2 ( 1 <= n <= 2 ) */ - char *buf, /* buffer to stuff to */ - int pos ) /* index at which to stuff */ -{ - union { - float float_val[2]; - char ch[32]; - } trick; - int i, j; - - assert (protocol == IPC_PROTOCOL_V1); - assert (sizeof(float) == 4); - assert (sizeof(char) == 1); - assert ((n >= 1) && (n <= 2)); - - trick.float_val[0] = (float)d1; - if (n > 1) { - trick.float_val[1] = (float)d2; - } - for (i = 0, j = pos; i < n * (int) sizeof(float); j++, i++) - buf[j] = trick.ch[i]; - buf[0] = (char) ('A' + j - 1); - return j; -} - -/*---------------------------------------------------------------------------*/ - - -/* -ipc_send_double - -This function sends a double data value over the interprocess -communication channel preceded by a character string that -identifies the simulation variable. -*/ - -Ipc_Status_t -ipc_send_double ( - char *tag, /* The node or instance */ - double value ) /* The data value to send */ -{ - int len = 0; - - switch (protocol) { - case IPC_PROTOCOL_V1: - strcpy (fmt_buffer, " "); /* save room for the length byte */ - strcat (fmt_buffer, tag); - strcat (fmt_buffer, " "); - - /* If talking to Mentor tools, must force upper case for Mspice 7.0 */ - strtoupper(fmt_buffer); - - len = stuff_binary_v1 (value, 0.0, 1, fmt_buffer, (int) strlen(fmt_buffer)); - break; - case IPC_PROTOCOL_V2: - break; - } - return ipc_send_line_binary (fmt_buffer, len); -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_complex - -This function sends a complex data value over the interprocess -communication channel preceded by a character string that -identifies the simulation variable. -*/ - - -Ipc_Status_t -ipc_send_complex ( - char *tag, /* The node or instance */ - Ipc_Complex_t value ) /* The data value to send */ -{ - int len=0; - - switch (protocol) { - case IPC_PROTOCOL_V1: - strcpy (fmt_buffer, " "); /* save room for the length byte */ - strcat (fmt_buffer, tag); - strcat (fmt_buffer, " "); - - /* If talking to Mentor tools, must force upper case for Mspice 7.0 */ - strtoupper(fmt_buffer); - - len = stuff_binary_v1 (value.real, value.imag, 2, fmt_buffer, - (int) strlen(fmt_buffer)); - break; - case IPC_PROTOCOL_V2: - break; - } - return ipc_send_line_binary (fmt_buffer, len); -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_event - -This function sends data from an event-driven node over the interprocess -communication channel. The data is sent only if the IPC is configured -for UNIX sockets, indicating use with the V2 ATESSE SI process. -*/ - - -Ipc_Status_t -ipc_send_event ( - int ipc_index, /* Index used in EVTDICT */ - double step, /* Analysis point or timestep (0.0 for DC) */ - double plot_val, /* The value for plotting purposes */ - char *print_val, /* The value for printing purposes */ - void *ipc_val, /* The binary representation of the node data */ - int len ) /* The length of the binary representation */ -{ -#ifdef IPC_AEGIS_MAILBOXES - return IPC_STATUS_OK; -#else - char buff[OUT_BUFFER_SIZE]; - int i; - int buff_len; - char *buff_ptr; - char *temp_ptr; - float fvalue; - - /* Report error if size of data is too big for IPC channel block size */ - if((len + (int) strlen(print_val) + 100) >= OUT_BUFFER_SIZE) { - printf("ERROR - Size of event-driven data too large for IPC channel\n"); - return IPC_STATUS_ERROR; - } - - /* Place the index into the buffer with a trailing space */ - sprintf(buff, "%d ", ipc_index); - - assert(sizeof(float) == 4); - assert(sizeof(int) == 4); - - /* Put the analysis step bytes in */ - buff_len = (int) strlen(buff); - buff_ptr = buff + buff_len; - fvalue = (float)step; - temp_ptr = (char *) &fvalue; - for(i = 0; i < 4; i++) { - *buff_ptr = temp_ptr[i]; - buff_ptr++; - buff_len++; - } - - /* Put the plot value in */ - fvalue = (float)plot_val; - temp_ptr = (char *) &fvalue; - for(i = 0; i < 4; i++) { - *buff_ptr = temp_ptr[i]; - buff_ptr++; - buff_len++; - } - - /* Put the length of the binary representation in */ - temp_ptr = (char *) &len; - for(i = 0; i < 4; i++) { - *buff_ptr = temp_ptr[i]; - buff_ptr++; - buff_len++; - } - - /* Put the binary representation bytes in last */ - temp_ptr = (char*) ipc_val; - for(i = 0; i < len; i++) - buff_ptr[i] = temp_ptr[i]; - buff_ptr += len; - buff_len += len; - - /* Put the print value in */ - strcpy(buff_ptr, print_val); - buff_ptr += strlen(print_val); - buff_len += (int) strlen(print_val); - - /* Send the data to the IPC channel */ - return ipc_send_line_binary(buff, buff_len); - -#endif -} - - diff --git a/src/xspice/ipc/ipcaegis.c b/src/xspice/ipc/ipcaegis.c deleted file mode 100644 index 2254ee460..000000000 --- a/src/xspice/ipc/ipcaegis.c +++ /dev/null @@ -1,309 +0,0 @@ -/*============================================================================ -FILE IPCaegis.c - -MEMBER OF process XSPICE - -Public Domain - -Georgia Tech Research Corporation -Atlanta, Georgia 30332 -PROJECT A-8503 - -AUTHORS - - 9/12/91 Steve Tynor - -MODIFICATIONS - - - -SUMMARY - - Provides compatibility for the new XSPICE simulator to both the MSPICE user - interface and BCP via ATESSE v.1 style AEGIS mailboxes. - -INTERFACES - - -REFERENCED FILES - - None. - -NON-STANDARD FEATURES - - None. - -============================================================================*/ - -#ifdef IPC_AEGIS_MAILBOXES - -#include -#include -#include -#include -#include "ngspice/memory.h" - -#include "ngspice/ipc.h" - - -typedef unsigned char Buffer_char_t; - -static status_$t status; -typedef enum { - IPC_MBX_UNINITIALIZED, - IPC_MBX_INITIALIZED, - IPC_MBX_CONNECTED_TO_CLIENT, -} Ipc_Mbx_State_t; - -static void *mbx_handle; -static Ipc_Mbx_State_t mbx_state = IPC_MBX_UNINITIALIZED; -static mbx_$server_msg_t mbx_send_msg_buf; -static mbx_$server_msg_t mbx_recieve_msg_buf; -static mbx_$server_msg_t *mbx_ret_ptr; -static int mbx_ret_len; -static short mbx_chan; - -#include "ngspice/ipcproto.h" - -/*---------------------------------------------------------------------------*/ - -/* -ipc_transport_initialize_server - -This function creates an Aegis mailbox, and if successful, -calls ipc_get_line to wait for the first record sent which is -assumed to be the batch output filename. -*/ - - - -Ipc_Status_t ipc_transport_initialize_server (server_name, m, p, - batch_filename) - char *server_name; /* The mailbox pathname */ - Ipc_Mode_t m; /* Mode - interactive or batch */ - Ipc_Protocol_t p; /* Protocol type */ - char *batch_filename; /* Batch filename returned */ -{ - int len; -/* extern void *malloc(); */ - - assert (p == IPC_PROTOCOL_V1); - - mbx_$create_server (server_name, strlen (server_name), mbx_$serv_msg_max, - 1, &mbx_handle, &status); - - if (status.all != status_$ok) { - fprintf (stderr, - "ERROR: IPC: Error creating mailbox server \"%s\"\n", - server_name); - error_$print (status); - mbx_state = IPC_MBX_UNINITIALIZED; - return IPC_STATUS_ERROR; - } else { - mbx_state = IPC_MBX_INITIALIZED; - /* - * First record is the name of the batch filename - whether we're in - * batch mode or not: - */ - return ipc_get_line (batch_filename, &len, IPC_WAIT); - } - /* - * shouldn't get here - */ - assert (0); - return IPC_STATUS_ERROR; -} -/*---------------------------------------------------------------------------*/ -Ipc_Status_t extract_msg (str, len) - char *str; - int *len; -{ - *len = mbx_ret_len - mbx_$serv_msg_hdr_len; - assert (*len >= 0); - - /* - * null terminate before copy: - */ - mbx_ret_ptr->data [*len] = '\0'; - strcpy (str, mbx_ret_ptr->data); - - return IPC_STATUS_OK; -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_transport_get_line - -This function reads data sent by a client over the mailbox -channel. It also handles the initial opening of the -mailbox channel when requested by a client. -*/ - - - -Ipc_Status_t ipc_transport_get_line (str, len, wait) - char *str; /* The string text read from IPC channel */ - int *len; /* The length of str */ - Ipc_Wait_t wait; /* Blocking or non-blocking */ -{ - if (mbx_state == IPC_MBX_UNINITIALIZED) { - fprintf (stderr, - "ERROR: IPC: Attempted to read from non-initialized mailbox\n"); - return IPC_STATUS_ERROR; - } - - assert ((mbx_state == IPC_MBX_CONNECTED_TO_CLIENT) || - (mbx_state == IPC_MBX_INITIALIZED)); - - for (;;) { - if (wait == IPC_WAIT) { - mbx_$get_rec (mbx_handle, &mbx_recieve_msg_buf, mbx_$serv_msg_max, - &mbx_ret_ptr, &mbx_ret_len, &status); - } else { - mbx_$get_conditional (mbx_handle, &mbx_recieve_msg_buf, - mbx_$serv_msg_max, &mbx_ret_ptr, &mbx_ret_len, - &status); - if (status.all == mbx_$channel_empty) { - return IPC_STATUS_NO_DATA; - } - } - - if (status.all != status_$ok) { - fprintf (stderr, "ERROR: IPC: Error reading from mailbox\n"); - error_$print (status); - return IPC_STATUS_ERROR; - } - - switch (mbx_ret_ptr->mt) { - case mbx_$channel_open_mt: - if (mbx_state == IPC_MBX_CONNECTED_TO_CLIENT) { - /* - * we're already connected to a client... refuse the connection - */ - mbx_send_msg_buf.mt = mbx_$reject_open_mt; - } else { - mbx_send_msg_buf.mt = mbx_$accept_open_mt; - mbx_state = IPC_MBX_CONNECTED_TO_CLIENT; - } - mbx_send_msg_buf.cnt = mbx_$serv_msg_hdr_len; - mbx_chan = mbx_ret_ptr->chan; - mbx_send_msg_buf.chan = mbx_chan; - - mbx_$put_rec (mbx_handle, &mbx_send_msg_buf, mbx_$serv_msg_hdr_len, - &status); - - if (status.all != status_$ok) { - fprintf (stderr, "ERROR: IPC: Error writing to mailbox\n"); - error_$print (status); - return IPC_STATUS_ERROR; - } - - /* - * check to see if there was a message buried in the open request: - */ - if (mbx_ret_len > mbx_$serv_msg_hdr_len) { - return extract_msg (str, len); - } - break; - case mbx_$eof_mt: - mbx_chan = mbx_ret_ptr->chan; - mbx_$deallocate(mbx_handle, mbx_chan, &status); - - if (status.all != status_$ok) { - fprintf (stderr, "ERROR: IPC: Error deallocating mailbox\n"); - error_$print (status); - return IPC_STATUS_ERROR; - } - - mbx_state = IPC_MBX_INITIALIZED; - return IPC_STATUS_EOF; - break; - case mbx_$data_mt: - assert (mbx_state == IPC_MBX_CONNECTED_TO_CLIENT); - return extract_msg (str, len); - break; - case mbx_$data_partial_mt: - fprintf (stderr, "ERROR: IPC: Recieved partial data message - ignored\n"); - break; - default: - fprintf (stderr, "ERROR: IPC: Bad message type (0x%x) recieved\n", - mbx_ret_ptr->mt); - } - } - return IPC_STATUS_ERROR; -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_transport_terminate_server - -This function calls ipc\_transport\_get\_line until it -receives an EOF from the client, which concludes the -communication. -*/ - - -Ipc_Status_t ipc_transport_terminate_server () -{ - char buffer[300]; - int len; - Ipc_Status_t status; - - do { - status = ipc_transport_get_line (buffer, &len, IPC_WAIT); - } while ((status != IPC_STATUS_ERROR) && - (status != IPC_STATUS_EOF)); - return status; -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_transport_send_line - -This function sends a message to the current client through -the mailbox channel. -*/ - - -Ipc_Status_t ipc_transport_send_line (str, len) - char *str; /* The bytes to send */ - int len; /* The number of bytes from str to send */ -{ - long cnt; - - if (mbx_state != IPC_MBX_CONNECTED_TO_CLIENT) { - fprintf (stderr, - "ERROR: IPC: Attempted to write to non-open mailbox\n"); - return IPC_STATUS_ERROR; - } - - mbx_send_msg_buf.mt = mbx_$data_mt; - if (mbx_$serv_msg_hdr_len + len > mbx_$serv_msg_max) { - fprintf (stderr, - "ERROR: IPC: send_line message too long - truncating\n"); - len = mbx_$serv_msg_max - mbx_$serv_msg_hdr_len; - } - - mbx_send_msg_buf.cnt = mbx_$serv_msg_hdr_len + len; - mbx_send_msg_buf.chan = mbx_chan; - memcpy (mbx_send_msg_buf.data, str, len); - - cnt = mbx_send_msg_buf.cnt; - mbx_$put_rec (mbx_handle, &mbx_send_msg_buf, cnt, &status); - - if (status.all != status_$ok) { - fprintf (stderr, "ERROR: IPC: Error writing to mailbox\n"); - error_$print (status); - return IPC_STATUS_ERROR; - } - return IPC_STATUS_OK; -} - -#else - -int intDummy1; - -#endif /* IPC_AEGIS_MAILBOXES */ diff --git a/src/xspice/ipc/ipcsockets.c b/src/xspice/ipc/ipcsockets.c deleted file mode 100644 index 54f6303c7..000000000 --- a/src/xspice/ipc/ipcsockets.c +++ /dev/null @@ -1,756 +0,0 @@ -/*============================================================================= - - FILE IPCsockets.c - -Public Domain - -Georgia Tech Research Corporation -Atlanta, Georgia 30332 -PROJECT A-8503 - - AUTHOR - Stefan Roth July 1991 - - MODIFICATIONS - none - - SUMMARY - Generic Interprocess Communication module - Provides compatibility for the new SPICE simulator to both the MSPICE user - interface and BCP (via ATESSE v.1 style AEGIS mailboxes) and the new ATESSE - v.2 Simulator Interface and BCP (via BSD Sockets). This file contains the - BSD sockets version. - The Simulator is the server, while the SI and BCP will be the clients. - - - INTERFACES - - FILE ROUTINE CALLED - - IPC.c ipc_get_line(); - - - REFERENCED FILES - - Outputs to stderr. - - -=============================================================================*/ - - -/*============================================================================= - - DESCRIPTION OF FUNCTIONALITY: - - Outline of Initialize_Server function: - create socket; - bind name to socket; - getsockname; - listen; - sock_state = IPC_SOCK_INITIALIZED; - return ipc_get_line (); - - - Format of a message line: - bytes description - ----- ------------------- - 0 recognition character for beginning of line; value is BOL_CHAR. - 1-4 message length (not including bytes 0-4); 32 bits in htonl - format; - if value = -1, then EOF and socket should be closed. - 5-N+5 message body of length specified in bytes 1-4. - - The bytes before the message body are the message header. The header - length is specified as SOCK_MSG_HDR_LEN bytes. - - - Outline of Get_Line function: - read 5 characters; - verify that first char is BOL_CHAR; - interpret message length (N) from bytes 1-4; - do error checking on message header bytes; - read N characters as message body; - do error checking on message body read; - - - Outline of Send_Line function: - write BOL_CHAR; - write 4-byte message body length - write message body (N bytes) - do error checking after each write operation - - - Outline of Terminate_Server function: - Continue to read lines (with ipc_transport_get_line) and ignore - them until socket EOF is reached; - Close the socket. - - -=============================================================================*/ - -#include "ngspice/ngspice.h" - -#ifdef IPC_UNIX_SOCKETS - -/*=== INCLUDE FILES ===*/ - -#include -#include - -#include "ngspice/ipc.h" -#include "ngspice/ipctiein.h" - - -/*=== TYPE DEFINITIONS ===*/ - -typedef enum { - IPC_SOCK_UNINITIALIZED, - IPC_SOCK_INITIALIZED, - IPC_SOCK_CONNECTED_TO_CLIENT -} Ipc_Sock_State_t; - - -/*=== LOCAL VARIABLES ===*/ - -static int sock_desc; /* socket descriptor */ -static int msg_stream; /* socket stream */ -static Ipc_Sock_State_t sock_state = IPC_SOCK_UNINITIALIZED; - - -/*=== INCLUDE FILES ===*/ - -#include "ngspice/ipcproto.h" - -/*============================================================================= - -FUNCTION ipc_transport_initialize_server - -AUTHORS - - July 1991 Stefan Roth - -MODIFICATIONS - - NONE - -SUMMARY - - Creates and opens the BSD socket of the server. Listens for requests - by a client and then reads the first line message. - -INTERFACES - - Called by: (IPC.c) ipc_initialize_server(); - -RETURNED VALUE - - Ipc_Status_t - returns status of the socket connection. - -GLOBAL VARIABLES - - NONE - -NON-STANDARD FEATURES - - NONE - -=============================================================================*/ - -Ipc_Status_t -ipc_transport_initialize_server ( - char *server_name, /* not used */ - Ipc_Mode_t mode, /* not used */ - Ipc_Protocol_t protocol, /* IN - only used in assert */ - char *batch_filename ) /* OUT - returns a value */ - /* Note that unused parameters are required to maintain compatibility */ - /* with version 1 (mailboxes) functions of the same names. */ -{ - struct sockaddr_in server; /* Server specifications for socket*/ - socklen_t server_length; /* Size of server structure */ - int port_num; /* Port number converted from server_name */ - - NG_IGNORE(mode); - NG_IGNORE(protocol); - - /* assert (protocol == IPC_PROTOCOL_V2); */ /* allow v1 protocol - wbk */ - assert (sock_state == IPC_SOCK_UNINITIALIZED); - - /* convert server_name (from atesse_xspice invocation line) to a port */ - /* number */ - port_num = atoi(server_name); - if((port_num > 0) && (port_num < 1024)) { - /* Reserved port number */ - perror ("ERROR: IPC Port numbers below 1024 are reserved"); - sock_state = IPC_SOCK_UNINITIALIZED; - return IPC_STATUS_ERROR; - } - - - sock_desc = socket (AF_INET, SOCK_STREAM, 0); - - if (sock_desc < 0) { - /* Unsuccessful socket opening */ - perror ("ERROR: IPC Creating socket"); - sock_state = IPC_SOCK_UNINITIALIZED; - return IPC_STATUS_ERROR; - } - - /* Socket opened successfully */ - - server.sin_family = AF_INET; - server.sin_addr.s_addr = INADDR_ANY; - server.sin_port = SOCKET_PORT; - - server_length = sizeof (server); - if (bind (sock_desc, (struct sockaddr *)&server, server_length) - < 0) { - fprintf (stderr, "ERROR: IPC: Bind unsuccessful\n"); - perror ("ERROR: IPC"); - sock_state = IPC_SOCK_UNINITIALIZED; - return IPC_STATUS_ERROR; - } - - if (getsockname (sock_desc, (struct sockaddr *)&server, &server_length) - < 0) { - fprintf (stderr, "ERROR: IPC: getting socket name\n"); - perror ("ERROR: IPC"); - sock_state = IPC_SOCK_UNINITIALIZED; - return IPC_STATUS_ERROR; - } - - fprintf (stderr, "Socket port %d.\n", ntohs(server.sin_port)); - - listen (sock_desc, 5); - - sock_state = IPC_SOCK_INITIALIZED; - - /* Socket ok to use now */ - - /* - * First record is the name of the batch filename if we're in batch mode. - */ - - if(g_ipc.mode == IPC_MODE_BATCH) { - int len; - return ipc_get_line (batch_filename, &len, IPC_WAIT); - } - - /* Return success */ - return IPC_STATUS_OK; - -} /* end ipc_transport_initialize_server */ - - - -/*============================================================================= - -FUNCTION bytes_to_integer - -AUTHORS - - July 1991 Stefan Roth - -MODIFICATIONS - - NONE - -SUMMARY - - Convert four bytes at START in the string STR - to a 32-bit unsigned integer. The string is assumed - to be in network byte order and the returned value - is converted to host byte order (with ntohl). - -INTERFACES - - Local to this file. - Called by: ipc_transport_get_line(); - -RETURNED VALUE - - u_long - unsigned 32 bit integer - -GLOBAL VARIABLES - - NONE - -NON-STANDARD FEATURES - - NONE - -=============================================================================*/ - -/* FIXME, - * this is seriously broken, - * once it was probably based upon htonl(), - * yet with broken types - * then the game has changed and strtoul() was used - * with a ascii representation of the length - * (probably as a hacky workaround, because it proved unreliable) - * but the buffer is not terminated properly - * Fix this when needed, currently this functionality looks like - * an unused ancient artefact - * Fix it with regard to ipc_transport_get_line() and ipc_transport_send_line() - * and in concert with the actual user at the other side of the socket - */ -static u_long -bytes_to_integer ( - char *str, /* IN - string that contains the bytes to convert */ - int start ) /* IN - index into string where bytes are */ -{ - uint32_t u; /* Value to be returned */ - char buff[4]; /* Transfer str into buff to word align reqd data */ - int index; /* Index into str and buff for transfer */ - - /* Get the str+start character and cast it into a u_long and put - the value through the network-to-host-short converter and store - it in the variable u. */ - - index = 0; - while (index < (int) sizeof(u)) { - buff[index] = str[index+start]; - index++; - } -/* u = ntohl (*((u_long *) buff)); */ - u = (uint32_t) strtoul(buff, NULL, 10); - - return u; -} /* end bytes_to_integer */ - - - -/*============================================================================= - -FUNCTION handle_socket_eof - -AUTHORS - - July 1991 Stefan Roth - -MODIFICATIONS - - NONE - -SUMMARY - - Do processing when the socket reaches EOF or when a message from the - client states that EOF has been reached. - -INTERFACES - - Local to this file. - Called by: ipc_transport_get_line(); - -RETURNED VALUE - - Ipc_Status_t - always IPC_STATUS_EOF - -GLOBAL VARIABLES - - NONE - -NON-STANDARD FEATURES - - NONE - -=============================================================================*/ - - -static Ipc_Status_t -handle_socket_eof (void) -{ - close (msg_stream); - close (sock_desc); - - sock_state = IPC_SOCK_UNINITIALIZED; - - return IPC_STATUS_EOF; -} /* handle_socket_eof */ - - - -/*============================================================================= - -FUNCTION read_sock - -AUTHORS - - July 1991 Stefan Roth - -MODIFICATIONS - - NONE - -SUMMARY - - Read N bytes from a socket. Only returns when the read had an error, - when 0 bytes (EOF) could be read, or LENGTH bytes are read. - -INTERFACES - - Local to this file. - Called by: ipc_transport_get_line(); - -RETURNED VALUE - - int - Returns the total number of bytes read. - -GLOBAL VARIABLES - - NONE - -NON-STANDARD FEATURES - - NONE - -=============================================================================*/ - - -static int -read_sock ( - int stream, /* IN - Socket stream */ - char *buffer, /* OUT - buffer to store incoming data */ - int length, /* IN - Number of bytes to be read */ - Ipc_Wait_t wait, /* IN - type of read operation */ - int flags ) /* IN - Original socket flags for blocking read */ -{ - int count; /* Number of bytes read with last `read` */ - int totalcount; /* total number of bytes read */ - char *buf2; - -/* count = 0; */ -/* while (count < length) { */ -/* buffer[count] = 'x'; */ -/* count++; */ -/* } */ - count = (int) read (stream, buffer, (size_t) length); - if (wait == IPC_NO_WAIT) { - fcntl (stream, F_SETFL, flags); /* Revert to blocking read */ - } - if ((count <= 0) || (count == length)) { - /* If error or if read in reqd number of bytes: */ - return count; - } else { - /* Only got some of the bytes requested */ - totalcount = count; - buf2 = &buffer[totalcount]; - length = length - count; - while (length > 0) { - count = (int) read (stream, buf2, (size_t) length); - if (count <= 0) /* EOF or read error */ - break; - totalcount = totalcount + count; - buf2 = &buffer[totalcount]; - length = length - count; - } - if (length != 0) { - fprintf (stderr, "WARNING: READ_SOCK read %d bytes instead of %d\n", - totalcount, totalcount + length); - } - return totalcount; - } -} /* end read_sock */ - - - -/*============================================================================= - -FUNCTION ipc_transport_get_line - -AUTHORS - - July 1991 Stefan Roth - -MODIFICATIONS - - NONE - -SUMMARY - - Main function for reading one line from a socket. Requires that the - socket be open. Lines are mostly SPICE code, but commands may also - be embedded in the socket data and they are interpreted by this function. - Therefore, this function may cause the socket to be closed. - -INTERFACES - - Called by: ipc_transport_terminate_server(); - (IPC.c) ipc_get_line(); - -RETURNED VALUE - - Ipc_Status_t - returns status of the read operation - -GLOBAL VARIABLES - - NONE - -NON-STANDARD FEATURES - - NONE - -=============================================================================*/ - - -Ipc_Status_t -ipc_transport_get_line ( - char *str, /* returns the result, null terminated */ - int *len, /* length of str passed IN and passed OUT */ - Ipc_Wait_t wait ) /* IN - wait or dont wait on incoming msg */ -{ - int count = 0; /* number of bytes read */ - int message_length; /* extracted from message header */ - - if (sock_state == IPC_SOCK_UNINITIALIZED) { - fprintf (stderr, - "ERROR: IPC: Attempted to read from uninitialized socket\n"); - return IPC_STATUS_ERROR; - } - - assert ((sock_state == IPC_SOCK_CONNECTED_TO_CLIENT) || - (sock_state == IPC_SOCK_INITIALIZED)); - - if (sock_state == IPC_SOCK_INITIALIZED) { - /* We have an open socket but have not connected to a client. */ - /* Accept a connection from a client. */ - msg_stream = accept (sock_desc, (struct sockaddr *)0, (socklen_t*)0); - - if (msg_stream == -1) { - fprintf (stderr, "ERROR: IPC: Server accepting request\n"); - perror ("ERROR: IPC"); - return IPC_STATUS_ERROR; - } - sock_state = IPC_SOCK_CONNECTED_TO_CLIENT; - } - /*-----------------------------------------------------------------------*/ - /* First read in the message header. */ - { - int flags; - flags = fcntl(msg_stream, F_GETFL, NULL); /* Blocking read mode */ - - if (wait == IPC_WAIT) { - /* Block here and wait for the next message */ - count = read_sock (msg_stream, str, SOCK_MSG_HDR_LEN, wait, flags); - if (count == 0) { - /* EOF, will this ever happen? */ - /* fprintf (stderr, "WARNING: IPC: Reached eof on socket\n"); */ - return handle_socket_eof (); - } - } else if (wait == IPC_NO_WAIT) { - /* Read message, but do not wait if none available. */ - - fcntl (msg_stream, F_SETFL, flags | O_NDELAY); - count = read_sock (msg_stream, str, SOCK_MSG_HDR_LEN, wait, flags); - - if (count == 0) { - /* EOF, will this ever happen? */ - /* fprintf (stderr, "WARNING: IPC: Reached eof on socket\n"); */ - return handle_socket_eof (); - } else if (count == -1) { - if (errno == EWOULDBLOCK) { - return IPC_STATUS_NO_DATA; - } - } - - } else { - /* Serious problem, since it is not reading anything. */ - fprintf (stderr, - "ERROR: IPC: invalid wait arg to ipc_transport_get_line\n"); - } - } - - /* Do more error checking on the read in values of the message header: */ - if (count == -1) { - fprintf (stderr, "ERROR: IPC: Reading from socket\n"); - perror ("ERROR: IPC"); - return IPC_STATUS_ERROR; - } else if (str[0] != BOL_CHAR) { - fprintf (stderr, - "ERROR: IPC: Did not find beginning of message header (%c)\n", - str[0]); - return IPC_STATUS_ERROR; - } else if ((message_length = (int) bytes_to_integer (str, 1)) == -1) { - /* fprintf (stderr, "WARNING: IPC: Reached eof on socket\n"); */ - return handle_socket_eof (); - } else if (message_length == 0) { - *len = 0; - return IPC_STATUS_NO_DATA; - -/* Invalid test... delete - wbk - } else if (message_length > *len) { - fprintf (stderr, - "ERROR: IPC: Buffer (%d) is too short for message (%d)\n", - *len, message_length); - return IPC_STATUS_ERROR; -*/ - - } - - /*-----------------------------------------------------------------------*/ - /* Now read in the message body. */ - /* Always block here since the message header was already read and */ - /* we must get the body. */ - - *len = message_length; - count = read_sock (msg_stream, str, message_length, IPC_WAIT, 0); - if (count == 0) { - /* EOF, will this ever happen? */ - /* fprintf (stderr, */ - /* "WARNING: IPC: Reached eof in message body on socket\n");*/ - return handle_socket_eof (); - } else if (count == -1) { - fprintf (stderr, "ERROR: IPC: reading message body from socket\n"); - perror ("ERROR: IPC"); - return IPC_STATUS_ERROR; - } - - /* Looks like we have a valid message here. Put in the string terminator. */ - *len = count; - str[count] = '\0'; - - return IPC_STATUS_OK; - -} /* end ipc_transport_get_line */ - - - -/*============================================================================= - -FUNCTION ipc_transport_send_line - -AUTHORS - - July 1991 Stefan Roth - -MODIFICATIONS - - NONE - -SUMMARY - Send a line of information. First sends a message header and - then the actual message body. - Error checking is done to make reasonably sure that the data was sent. - - -INTERFACES - - Called by: (IPC.c) ipc_flush (); - -RETURNED VALUE - - Ipc_Status_t - returns status of the send operation (typically - IPC_STATUS_ERROR or IPC_STATUS_OK). - - -GLOBAL VARIABLES - - NONE - -NON-STANDARD FEATURES - - NONE - -=============================================================================*/ - - -Ipc_Status_t -ipc_transport_send_line ( - char *str, /* IN - String to write */ - int len ) /* IN - Number of characters out of STR to write */ -{ - int count; /* Counts how many bytes were actually written */ - u_long u; /* 32-bit placeholder for transmission of LEN */ - char hdr_buff[5]; /* Buffer for building header message in */ - int i; /* Temporary counter */ - char *char_ptr; /* Pointer for int to bytes conversion */ - - if (sock_state != IPC_SOCK_CONNECTED_TO_CLIENT) { - fprintf (stderr, "ERROR: IPC: Attempt to write to non-open socket\n"); - return IPC_STATUS_ERROR; - } - - /* Write message body header with length: */ - hdr_buff[0] = BOL_CHAR; - u = htonl ((uint32_t) len); - char_ptr = (char *) &u; - for(i = 0; i < 4; i++) - hdr_buff[i+1] = char_ptr[i]; - - count = (int) write (msg_stream, hdr_buff, 5); - if (count != 5) { - fprintf (stderr, "ERROR: IPC: (%d) send line error 1\n", count); - return IPC_STATUS_ERROR; - } - - /* Write message body: */ - count = (int) write (msg_stream, str, (size_t) len); - if (count != len) { - fprintf (stderr, "ERROR: IPC: (%d) send line error 2\n", count); - return IPC_STATUS_ERROR; - } - - return IPC_STATUS_OK; -} /* end ipc_transport_send_line */ - - - -/*============================================================================= - -FUNCTION ipc_transport_terminate_server - -AUTHORS - - July 1991 Stefan Roth - -MODIFICATIONS - - NONE - -SUMMARY - - This function reads all pending incoming messages and discards them. - Reading continues until a read error occurs or EOF is reached, at which - time the socket is closed. - Note that this function does not actually close the socket. This is - done in ipc_transport_get_line, which is called in this function. - - In this function, the incoming line length is limited. See buffer below. - -INTERFACES - - Called by: (IPC.c) ipc_terminate_server(); - -RETURNED VALUE - - Ipc_Status_t - returns status of last read operation (always - IPC_STATUS_ERROR or IPC_STATUS_EOF). - -GLOBAL VARIABLES - - NONE - -NON-STANDARD FEATURES - - NONE - -=============================================================================*/ - - -Ipc_Status_t -ipc_transport_terminate_server (void) -{ - char buffer[17000]; /* temp buffer for incoming data */ - int len; /* placeholder var to as arg to function */ - Ipc_Status_t status; /* value to be returned from function */ - int max_size; /* Max length of buffer */ - - max_size = sizeof (buffer); - do { - len = max_size; - status = ipc_transport_get_line (buffer, &len, IPC_WAIT); - } while ((status != IPC_STATUS_ERROR) && - (status != IPC_STATUS_EOF)); - return status; -} - -#endif /* IPC_UNIX_SOCKETS */ diff --git a/src/xspice/ipc/ipcstdio.c b/src/xspice/ipc/ipcstdio.c deleted file mode 100644 index 229fff3ba..000000000 --- a/src/xspice/ipc/ipcstdio.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Steve Tynor - * - * Generic Interprocess Communication module - * - * Used for debugging in absense of IPC interface. - * - */ - -#include "ngspice/ngspice.h" - -#ifdef IPC_DEBUG_VIA_STDIO - -#include - - -#include "ngspice/ipc.h" - -#include "ngspice/ipcproto.h" - -#include /* 12/1/97 jg */ - -/*---------------------------------------------------------------------------*/ -Ipc_Status_t ipc_transport_initialize_server ( - char *server_name, - Ipc_Mode_t m, - Ipc_Protocol_t p, - char *batch_filename ) -{ - NG_IGNORE(server_name); - NG_IGNORE(p); - NG_IGNORE(batch_filename); - - assert (m == IPC_MODE_INTERACTIVE); - printf ("INITIALIZE_SERVER\n"); - return IPC_STATUS_OK; -} - -/*---------------------------------------------------------------------------*/ -Ipc_Status_t ipc_transport_get_line ( - char *str, - int *len, - Ipc_Wait_t wait ) -{ - NG_IGNORE(wait); - - printf ("GET_LINE\n"); - fgets (str, 512, stdin); - char *tmp = strchr(str, '\n'); - if (tmp) - *tmp = '\0'; - *len = (int) strlen (str); - return IPC_STATUS_OK; -} - -/*---------------------------------------------------------------------------*/ -Ipc_Status_t ipc_transport_send_line ( - char *str, - int len ) -{ - int i; - - printf ("SEND_LINE: /"); - for (i = 0; i < len; i++) - putchar (str[i]); - printf ("/\n"); - return IPC_STATUS_OK; -} - -/*---------------------------------------------------------------------------*/ -Ipc_Status_t ipc_transport_terminate_server (void) -{ -return IPC_STATUS_OK; -} - - -#endif /* IPC_DEBUG_VIA_STDIO */ diff --git a/src/xspice/ipc/ipctiein.c b/src/xspice/ipc/ipctiein.c deleted file mode 100644 index d104158bb..000000000 --- a/src/xspice/ipc/ipctiein.c +++ /dev/null @@ -1,520 +0,0 @@ -/*============================================================================ -FILE IPCtiein.c - -MEMBER OF process XSPICE - -Public Domain - -Georgia Tech Research Corporation -Atlanta, Georgia 30332 -PROJECT A-8503 - -AUTHORS - - 9/12/91 Bill Kuhn - -MODIFICATIONS - - - -SUMMARY - - Provides a protocol independent interface between the simulator - and the IPC method used to interface to CAE packages. - -INTERFACES - - g_ipc (global variable) - - ipc_handle_stop() - ipc_handle_returni() - ipc_handle_mintime() - ipc_handle_vtrans() - ipc_send_stdout() - ipc_send_stderr() - ipc_send_std_files() - ipc_screen_name() - ipc_get_devices() - ipc_free_devices() - ipc_check_pause_stop() - -REFERENCED FILES - - None. - -NON-STANDARD FEATURES - - None. - -============================================================================*/ - - -#define CONFIG - -#include "ngspice/ngspice.h" -#include "ngspice/inpdefs.h" -#include "ngspice/gendefs.h" -#include "ngspice/cktdefs.h" -#include "bjt/bjtdefs.h" -#include "jfet/jfetdefs.h" -#include "mos1/mos1defs.h" -#include "mos2/mos2defs.h" -#include "mos3/mos3defs.h" -#include "ngspice/mifproto.h" -#include "ngspice/ipc.h" -#include "ngspice/ipctiein.h" - - - -/* -Global variable g_ipc is used by the SPICE mods that take care of -interprocess communications activities. -*/ - - -Ipc_Tiein_t g_ipc = { - IPC_FALSE, /* enabled */ - IPC_MODE_INTERACTIVE, /* mode */ - IPC_ANAL_DCOP, /* analysis mode */ - IPC_FALSE, /* parse_error */ - IPC_FALSE, /* run_error */ - IPC_FALSE, /* errchk_sent */ - IPC_FALSE, /* returni */ - 0.0, /* mintime */ - 0.0, /* lasttime */ - 0.0, /* cpu time */ - NULL, /* send array */ - NULL, /* log file */ - { /* vtrans struct */ - 0, /* size */ - NULL, /* vsrc_name array */ - NULL, /* device_name array */ - }, - IPC_FALSE, /* stop analysis */ -}; - - - -/* -ipc_handle_stop - -This function sets a flag in the g_ipc variable to signal that -a stop message has been received over the IPC channel. -*/ - -void ipc_handle_stop(void) -{ - g_ipc.stop_analysis = IPC_TRUE; -} - - -/* -ipc_handle_returni - -This function sets a flag in the g_ipc variable to signal that -a message has been received over the IPC channel specifying that -current values are to be returned in the results data sets. -*/ - -void ipc_handle_returni(void) -{ - g_ipc.returni = IPC_TRUE; -} - - -/* -ipc_handle_mintime - -This function sets a value in the g_ipc variable that specifies -how often data is to be returned as it is computed. If the -simulator takes timestep backups, data may still be returned -more often that that specified by 'mintime' so that glitches -are not missed. -*/ - -void ipc_handle_mintime(double time) -{ - g_ipc.mintime = time; -} - - - -/* -ipc_handle_vtrans - -This function processes arguments from a #VTRANS card received over -the IPC channel. The data on the card specifies that a particular -zero-valued voltage source name should be translated to the specified -instance name for which it was setup to monitor currents. -*/ - -void ipc_handle_vtrans( - char *vsrc, /* The name of the voltage source to be translated */ - char *dev) /* The device name the vsource name should be translated to */ -{ - int i; - int size; - - - if(g_ipc.vtrans.size == 0) { - g_ipc.vtrans.size = 1; - g_ipc.vtrans.vsrc_name = TMALLOC(char *, 1); - g_ipc.vtrans.device_name = TMALLOC(char *, 1); - g_ipc.vtrans.vsrc_name[0] = MIFcopy(vsrc); - g_ipc.vtrans.device_name[0] = MIFcopy(dev); - } - else { - g_ipc.vtrans.size++; - - size = g_ipc.vtrans.size; - i = g_ipc.vtrans.size - 1; - - g_ipc.vtrans.vsrc_name = TREALLOC(char *, g_ipc.vtrans.vsrc_name, size); - g_ipc.vtrans.device_name = TREALLOC(char *, g_ipc.vtrans.device_name, size); - g_ipc.vtrans.vsrc_name[i] = MIFcopy(vsrc); - g_ipc.vtrans.device_name[i] = MIFcopy(dev); - } -} - - - -/* -ipc_send_stdout - -This function sends the data written to stdout over the IPC channel. -This stream was previously redirected to a temporary file during -the simulation. -*/ - -void ipc_send_stdout(void) -{ - int c; - int len; - - char buf[IPC_MAX_LINE_LEN+1]; - - /* rewind the redirected stdout stream */ - rewind(stdout); - - /* Begin reading from the top of file and send lines */ - /* over the IPC channel. */ - - /* Don't send newlines. Also, if line is > IPC_MAX_LINE_LEN chars */ - /* we must wrap it because Mspice can't handle it */ - - len = 0; - while( (c=fgetc(stdout)) != EOF) { - if(c != '\n') { - buf[len] = (char) c; - len++; - } - if((c == '\n') || (len == IPC_MAX_LINE_LEN)) { - buf[len] = '\0'; - ipc_send_line(buf); - len = 0; - } - } - if(len > 0) { - buf[len] = '\0'; - ipc_send_line(buf); - } - - /* Finally, rewind file again to discard the data already sent */ - rewind(stdout); -} - - -/* -ipc_send_stderr - -This function sends the data written to stderr over the IPC channel. -This stream was previously redirected to a temporary file during -the simulation. -*/ - -void ipc_send_stderr(void) -{ - int c; - int len; - - char buf[IPC_MAX_LINE_LEN+1]; - - /* rewind the redirected stderr stream */ - rewind(stderr); - - /* Begin reading from the top of file and send lines */ - /* over the IPC channel. */ - - /* Don't send newlines. Also, if line is > IPC_MAX_LINE_LEN chars */ - /* we must wrap it because Mspice can't handle it */ - - len = 0; - while( (c=fgetc(stderr)) != EOF) { - if(c != '\n') { - buf[len] = (char) c; - len++; - } - if((c == '\n') || (len == IPC_MAX_LINE_LEN)) { - buf[len] = '\0'; - ipc_send_line(buf); - len = 0; - } - } - if(len > 0) { - buf[len] = '\0'; - ipc_send_line(buf); - } - - /* Finally, rewind file again to discard the data already sent */ - rewind(stderr); -} - - -/* -ipc_send_std_files - -This function sends the data written to stdout and stderr over the -IPC channel. These streams were previously redirected to temporary -files during the simulation. -*/ - -Ipc_Status_t ipc_send_std_files(void) -{ - ipc_send_stdout(); - ipc_send_stderr(); - - return(ipc_flush()); -} - - - -/* -ipc_screen_name - -This function screens names of instances and nodes to limit the -data returned over the IPC channel. -*/ - -Ipc_Boolean_t ipc_screen_name(char *name, char *mapped_name) -{ - char *endp; - int i; - int len; - long l; - - /* Return FALSE if name is in a subcircuit */ - for(i = 0; name[i] != '\0'; i++) { - if(name[i] == ':') - return(IPC_FALSE); - } - - /* Determine if name is numeric and what value is */ - l = strtol(name, &endp, 10); - - /* If numeric */ - if(*endp == '\0') { - /* Return FALSE if >100,000 -> added by ms_server in ATESSE 1.0 */ - if(l >= 100000) - return(IPC_FALSE); - /* Otherwise, copy name to mapped name and return true */ - else { - strcpy(mapped_name,name); - return(IPC_TRUE); - } - } - - /* If node is an internal node from a semiconductor (indicated by a */ - /* trailing #collector, #source, ...), do not return its current. */ - /* Otherwise, map to upper case and eliminate trailing "#branch" if any. */ - for(i = 0; name[i]; i++) { - if(name[i] == '#') { - if(strcmp(name + i, "#branch") == 0) - break; - else - return(IPC_FALSE); - } - else { - if(islower_c(name[i])) - mapped_name[i] = toupper_c(name[i]); - else - mapped_name[i] = name[i]; - } - } - mapped_name[i] = '\0'; - len = i; - - /* If len != 8 or 6'th char not equal to $, then doesn't need vtrans */ - /* Otherwise, translate to device name that it monitors */ - if(len != 8) - return(IPC_TRUE); - else if(name[5] != '$') - return(IPC_TRUE); - else { - /* Scan list of prefixes in VTRANS table and convert name */ - for(i = 0; i < g_ipc.vtrans.size; i++) { - if(strncmp(mapped_name, g_ipc.vtrans.vsrc_name[i], 5) == 0) { - strcpy(mapped_name, g_ipc.vtrans.device_name[i]); - return(IPC_TRUE); - } - } - return(IPC_TRUE); - } - -} - - - -/* -ipc_get_devices - -This function is used to setup the OUTinterface data structure that -determines what instances will have data returned over the IPC channel. -*/ - - -int ipc_get_devices( - CKTcircuit *ckt, /* The circuit structure */ - char *device, /* The device name as it appears in the info struct */ - char ***names, /* Array of name strings to be built */ - double **modtypes) /* Array of types to be built */ -{ - int index; - int num_instances; - GENmodel *model; - GENinstance *here; - char *inst_name; - int inst_name_len; - int i; - - BJTmodel *BJTmod; - JFETmodel *JFETmod; - MOS1model *MOS1mod; - MOS2model *MOS2mod; - MOS3model *MOS3mod; - - /* Initialize local variables */ - num_instances = 0; - - /* Get the index into the circuit structure linked list of models */ - index = INPtypelook(device); - - /* Iterate through all models of this type */ - for(model = ckt->CKThead[index]; model; model = model->GENnextModel) { - - /* Iterate through all instance of this model */ - for(here = model->GENinstances; here; here = here->GENnextInstance) { - - /* Get the name of the instance */ - inst_name = here->GENname; - inst_name_len = (int) strlen(inst_name); - - /* Skip if it is a inside a subcircuit */ - for(i = 0; i < inst_name_len; i++) - if(inst_name[i] == ':') - break; - if(i < inst_name_len) - continue; - - /* Otherwise, add the name to the list */ - num_instances++; - if(num_instances == 1) - *names = TMALLOC(char *, 1); - else - *names = TREALLOC(char *, *names, num_instances); - (*names)[num_instances-1] = MIFcopy(inst_name); - - /* Then get the type if it is a Q J or M */ - if(num_instances == 1) - *modtypes = TMALLOC(double, 1); - else - *modtypes = TREALLOC(double, *modtypes, num_instances); - - if(strcmp(device,"BJT") == 0) { - BJTmod = (BJTmodel *) model; - (*modtypes)[num_instances-1] = BJTmod->BJTtype; - } - else if(strcmp(device,"JFET") == 0) { - JFETmod = (JFETmodel *) model; - (*modtypes)[num_instances-1] = JFETmod->JFETtype; - } - else if(strcmp(device,"Mos1") == 0) { - MOS1mod = (MOS1model *) model; - (*modtypes)[num_instances-1] = MOS1mod->MOS1type; - } - else if(strcmp(device,"Mos2") == 0) { - MOS2mod = (MOS2model *) model; - (*modtypes)[num_instances-1] = MOS2mod->MOS2type; - } - else if(strcmp(device,"Mos3") == 0) { - MOS3mod = (MOS3model *) model; - (*modtypes)[num_instances-1] = MOS3mod->MOS3type; - } - else { - (*modtypes)[num_instances-1] = 1.0; - } - - } /* end for all instances */ - } /* end for all models */ - - return(num_instances); -} - - - -/* -ipc_free_devices - -This function frees temporary data created by ipc_get_devices(). -*/ - - -void ipc_free_devices( - int num_items, /* Number of things to free */ - char **names, /* Array of name strings to be built */ - double *modtypes) /* Array of types to be built */ -{ - int i; - - for(i = 0; i < num_items; i++) - { - FREE(names[i]); - names[i] = NULL; - } - - if(num_items > 0) - { - FREE(names); - FREE(modtypes); - - names = NULL; - modtypes = NULL; - } -} - - -/* -ipc_check_pause_stop - -This function is called at various times during a simulation to check -for incoming messages of the form >STOP or >PAUSE signaling that -simulation should be stopped or paused. Processing of the messages -is handled by ipc_get_line(). -*/ - -void ipc_check_pause_stop(void) -{ - char buf[1025]; - int len; - - /* If already seen stop analysis, don't call ipc_get_line, just return. */ - /* This is provided so that the function can be called multiple times */ - /* during the process of stopping */ - if(g_ipc.stop_analysis) - return; - - /* Otherwise do a non-blocking call to ipc_get_line() to check for messages. */ - /* We assume that the only possible messages at this point are >PAUSE */ - /* and >STOP, so we don't do anything with the returned text if any */ - ipc_get_line(buf, &len, IPC_NO_WAIT); -} - diff --git a/visualc/sharedspice.vcxproj b/visualc/sharedspice.vcxproj index 461f74e6a..d8f8ff189 100644 --- a/visualc/sharedspice.vcxproj +++ b/visualc/sharedspice.vcxproj @@ -794,8 +794,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 - - @@ -2612,11 +2610,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 - - - - - diff --git a/visualc/vngspice-fftw.vcxproj b/visualc/vngspice-fftw.vcxproj index 59239b20a..fb9c4eabf 100644 --- a/visualc/vngspice-fftw.vcxproj +++ b/visualc/vngspice-fftw.vcxproj @@ -1011,8 +1011,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 - - @@ -2832,11 +2830,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 238bb520b..b4e342411 100644 --- a/visualc/vngspice.vcxproj +++ b/visualc/vngspice.vcxproj @@ -1026,8 +1026,6 @@ - - @@ -2847,11 +2845,6 @@ - - - - - From 6004d9aef901b0e3c9e93a5aea8b38734b6f8b0d Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 21 Oct 2025 22:17:35 +0200 Subject: [PATCH 057/161] Improve comments --- src/include/ngspice/cktdefs.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/include/ngspice/cktdefs.h b/src/include/ngspice/cktdefs.h index 6aa65744d..60a07db02 100644 --- a/src/include/ngspice/cktdefs.h +++ b/src/include/ngspice/cktdefs.h @@ -206,11 +206,11 @@ struct CKTcircuit { int CKTtranMaxIter; /* iteration limit for each timepoint for tran*/ /* (itl4) */ - int CKTbreakSize; /* ??? */ - int CKTbreak; /* ??? */ - double CKTsaveDelta; /* ??? */ - double CKTminBreak; /* ??? */ - double *CKTbreaks; /* List of breakpoints ??? */ + int CKTbreakSize; /* number of breakpoints in table *CKTbreaks */ + int CKTbreak; /* if 1, a breakpoint may be set (only used in isrcacct.c) */ + double CKTsaveDelta; /* previous delta, before breakpoints set a new delta */ + double CKTminBreak; /* minimum time difference between breakpoints */ + double *CKTbreaks; /* List of breakpoints as an array of doubles */ double CKTabstol; /* --- */ double CKTpivotAbsTol; /* --- */ double CKTpivotRelTol; /* --- */ From 31a8486c03ca76cbc517b1ad1d4f091d0ffa6dc8 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 21 Oct 2025 22:18:12 +0200 Subject: [PATCH 058/161] make nthreads local --- src/spicelib/analysis/cktsetup.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/spicelib/analysis/cktsetup.c b/src/spicelib/analysis/cktsetup.c index 8b5141f50..985739c64 100644 --- a/src/spicelib/analysis/cktsetup.c +++ b/src/spicelib/analysis/cktsetup.c @@ -23,7 +23,6 @@ Author: 1985 Thomas L. Quarles #ifdef USE_OMP #include #include "ngspice/cpextern.h" -int nthreads; #endif #define CKALLOC(var,size,type) \ @@ -36,7 +35,9 @@ CKTsetup(CKTcircuit *ckt) { int i; int error; - +#ifdef USE_OMP + int nthreads = 2; +#endif #ifdef XSPICE /* gtri - begin - Setup for adding rshunt option resistors */ CKTnode *node; From 89c03ca6405e25c87ead5a031ccf119d9f49295b Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 25 Oct 2025 15:37:08 +0200 Subject: [PATCH 059/161] fix bug no 819, which has been introduced by d5ef8a366 ("Remove all entries connected to IPC, an outdated (>30 years) method to link ngspice to a now defunct controller (ATESSE).", 2025-10-21) --- src/spicelib/analysis/noisean.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/spicelib/analysis/noisean.c b/src/spicelib/analysis/noisean.c index de15daaf8..3eeca41f2 100644 --- a/src/spicelib/analysis/noisean.c +++ b/src/spicelib/analysis/noisean.c @@ -182,9 +182,8 @@ NOISEan(CKTcircuit* ckt, int restart) EVTop_save(ckt, MIF_TRUE, 0.0); } else - { // start of no XSPICE event-driven instances #endif - + { // start of no XSPICE event-driven instances #ifdef KLU if (ckt->CKTmatrix->CKTkluMODE) { From 329343a31e5ce3cd63d20bb3942bcb694672f4ca Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 25 Oct 2025 15:40:37 +0200 Subject: [PATCH 060/161] Fix a bug. --- src/frontend/inpcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 4edecffa8..ae6cab075 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -3446,7 +3446,7 @@ static void inp_stripcomments_deck(struct card *c, bool cf) found_control = TRUE; if (ciprefix(".endc", c->line)) found_control = FALSE; - inp_stripcomments_line(c->line, found_control | cf, FALSE); + inp_stripcomments_line(c->line, found_control || cf, FALSE); } } From 564a97e6939b45c13d5af8ed650f06f0e96a84c6 Mon Sep 17 00:00:00 2001 From: dwarning Date: Sat, 8 Nov 2025 09:13:16 +0100 Subject: [PATCH 061/161] correct rthca connection --- src/spicelib/devices/vdmos/vdmosbindCSC.c | 12 ++++++------ src/spicelib/devices/vdmos/vdmosset.c | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/spicelib/devices/vdmos/vdmosbindCSC.c b/src/spicelib/devices/vdmos/vdmosbindCSC.c index 1d85b47df..860dee0c6 100644 --- a/src/spicelib/devices/vdmos/vdmosbindCSC.c +++ b/src/spicelib/devices/vdmos/vdmosbindCSC.c @@ -74,8 +74,8 @@ VDMOSbindCSC (GENmodel *inModel, CKTcircuit *ckt) CREATE_KLU_BINDING_TABLE(VDMOSTcasetempPtr, VDMOSTcasetempBinding, VDMOStcaseNode, VDMOStempNode); CREATE_KLU_BINDING_TABLE(VDMOSTemptcasePtr, VDMOSTemptcaseBinding, VDMOStempNode, VDMOStcaseNode); CREATE_KLU_BINDING_TABLE(VDMOSTptpPtr, VDMOSTptpBinding, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */ - CREATE_KLU_BINDING_TABLE(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStempNode); - CREATE_KLU_BINDING_TABLE(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStempNode, VDMOStNodePrime); + CREATE_KLU_BINDING_TABLE(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStcaseNode); + CREATE_KLU_BINDING_TABLE(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStcaseNode, VDMOStNodePrime); CREATE_KLU_BINDING_TABLE(VDMOSCktTcktTPtr, VDMOSCktTcktTBinding, VDMOSvcktTbranch, VDMOSvcktTbranch); /* Vsrc=cktTemp to gnd */ CREATE_KLU_BINDING_TABLE(VDMOSCktTtpPtr, VDMOSCktTtpBinding, VDMOSvcktTbranch, VDMOStNodePrime); CREATE_KLU_BINDING_TABLE(VDMOSTpcktTPtr, VDMOSTpcktTBinding, VDMOStNodePrime, VDMOSvcktTbranch); @@ -149,8 +149,8 @@ VDMOSbindCSCComplex (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTcasetempPtr, VDMOSTcasetempBinding, VDMOStcaseNode, VDMOStempNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTemptcasePtr, VDMOSTemptcaseBinding, VDMOStempNode, VDMOStcaseNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTptpPtr, VDMOSTptpBinding, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */ - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStempNode); - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStempNode, VDMOStNodePrime); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStcaseNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStcaseNode, VDMOStNodePrime); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSCktTcktTPtr, VDMOSCktTcktTBinding, VDMOSvcktTbranch, VDMOSvcktTbranch); /* Vsrc=cktTemp to gnd */ CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSCktTtpPtr, VDMOSCktTtpBinding, VDMOSvcktTbranch, VDMOStNodePrime); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTpcktTPtr, VDMOSTpcktTBinding, VDMOStNodePrime, VDMOSvcktTbranch); @@ -224,8 +224,8 @@ VDMOSbindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTcasetempPtr, VDMOSTcasetempBinding, VDMOStcaseNode, VDMOStempNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTemptcasePtr, VDMOSTemptcaseBinding, VDMOStempNode, VDMOStcaseNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTptpPtr, VDMOSTptpBinding, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */ - CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStempNode); - CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStempNode, VDMOStNodePrime); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStcaseNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStcaseNode, VDMOStNodePrime); CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSCktTcktTPtr, VDMOSCktTcktTBinding, VDMOSvcktTbranch, VDMOSvcktTbranch); /* Vsrc=cktTemp to gnd */ CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSCktTtpPtr, VDMOSCktTtpBinding, VDMOSvcktTbranch, VDMOStNodePrime); CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTpcktTPtr, VDMOSTpcktTBinding, VDMOStNodePrime, VDMOSvcktTbranch); diff --git a/src/spicelib/devices/vdmos/vdmosset.c b/src/spicelib/devices/vdmos/vdmosset.c index ab59ede32..2719535bf 100644 --- a/src/spicelib/devices/vdmos/vdmosset.c +++ b/src/spicelib/devices/vdmos/vdmosset.c @@ -479,8 +479,8 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ TSTALLOC(VDMOSTcasetempPtr, VDMOStcaseNode, VDMOStempNode); TSTALLOC(VDMOSTemptcasePtr, VDMOStempNode, VDMOStcaseNode); TSTALLOC(VDMOSTptpPtr, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */ - TSTALLOC(VDMOSTptcasePtr, VDMOStNodePrime, VDMOStempNode); - TSTALLOC(VDMOSTcasetpPtr, VDMOStempNode, VDMOStNodePrime); + TSTALLOC(VDMOSTptcasePtr, VDMOStNodePrime, VDMOStcaseNode); + TSTALLOC(VDMOSTcasetpPtr, VDMOStcaseNode, VDMOStNodePrime); TSTALLOC(VDMOSCktTcktTPtr, VDMOSvcktTbranch, VDMOSvcktTbranch); /* Vsrc=cktTemp to gnd */ TSTALLOC(VDMOSCktTtpPtr, VDMOSvcktTbranch, VDMOStNodePrime); TSTALLOC(VDMOSTpcktTPtr, VDMOStNodePrime, VDMOSvcktTbranch); From f9cd5f1471da4e83cfcf4e811fb773f7e5df24ca Mon Sep 17 00:00:00 2001 From: dwarning Date: Sat, 8 Nov 2025 21:15:32 +0100 Subject: [PATCH 062/161] correct gate and source resistor temperature update --- src/spicelib/devices/vdmos/vdmostemp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/spicelib/devices/vdmos/vdmostemp.c b/src/spicelib/devices/vdmos/vdmostemp.c index 53d92a548..202a4611a 100644 --- a/src/spicelib/devices/vdmos/vdmostemp.c +++ b/src/spicelib/devices/vdmos/vdmostemp.c @@ -56,9 +56,15 @@ void VDMOStempUpdate(VDMOSmodel *inModel, VDMOSinstance *here, double Temp, CKTc else here->VDMOSdrainResistance = model->VDMOSdrainResistance / here->VDMOSm * (1.0 + (model->VDMOStrd1 * dt) + (model->VDMOStrd2 * dt * dt)); - here->VDMOSgateConductance = here->VDMOSgateConductance / (1.0 + (model->VDMOStrg1 * dt) + (model->VDMOStrg2 * dt * dt)); + if (model->VDMOSgateResistance > 0) + here->VDMOSgateConductance = here->VDMOSm / model->VDMOSgateResistance / (1.0 + (model->VDMOStrg1 * dt) + (model->VDMOStrg2 * dt * dt)); + else + here->VDMOSgateConductance = 0.0; - here->VDMOSsourceConductance = here->VDMOSsourceConductance / (1.0 + (model->VDMOStrs1 * dt) + (model->VDMOStrs2 * dt * dt)); + if (model->VDMOSsourceResistance > 0) + here->VDMOSsourceConductance = here->VDMOSm / model->VDMOSsourceResistance / (1.0 + (model->VDMOStrs1 * dt) + (model->VDMOStrs2 * dt * dt)); + else + here->VDMOSsourceConductance = 0.0; if (model->VDMOSqsGiven) here->VDMOSqsResistance = model->VDMOSqsResistance / here->VDMOSm * pow(ratio, model->VDMOStexp1); From ce94dd1587aa53954df780ea3e8a1ae93d2d93d2 Mon Sep 17 00:00:00 2001 From: dwarning Date: Sun, 9 Nov 2025 08:21:45 +0100 Subject: [PATCH 063/161] vdmos: in case temp and dtemp is given - use dtemp and omit temp --- src/spicelib/devices/vdmos/vdmosset.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/spicelib/devices/vdmos/vdmosset.c b/src/spicelib/devices/vdmos/vdmosset.c index 2719535bf..58e6cd300 100644 --- a/src/spicelib/devices/vdmos/vdmosset.c +++ b/src/spicelib/devices/vdmos/vdmosset.c @@ -259,6 +259,13 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, here->VDMOSstates = *states; *states += VDMOSnumStates; + if ((here->VDMOStempGiven) && (here->VDMOSdtempGiven)) { + SPfrontEnd->IFerrorf(ERR_WARNING, + "%s: temp and dtemp instance parameter given - using dtemp", + here->VDMOSname); + here->VDMOStempGiven = FALSE; + } + if (!here->VDMOSicVDSGiven) { here->VDMOSicVDS = 0; } From 5836f9c4871d0dec8f1cadd9854fb5e98e3920c8 Mon Sep 17 00:00:00 2001 From: dwarning Date: Mon, 10 Nov 2025 15:17:56 +0100 Subject: [PATCH 064/161] vdmos convtest needs type for vd - load hack not needed anymore --- src/spicelib/devices/vdmos/vdmosconv.c | 5 +++-- src/spicelib/devices/vdmos/vdmosload.c | 10 ---------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/spicelib/devices/vdmos/vdmosconv.c b/src/spicelib/devices/vdmos/vdmosconv.c index c51a94a0a..6b6dfca42 100644 --- a/src/spicelib/devices/vdmos/vdmosconv.c +++ b/src/spicelib/devices/vdmos/vdmosconv.c @@ -82,8 +82,9 @@ VDMOSconvTest(GENmodel *inModel, CKTcircuit *ckt) * initialization */ - vd = *(ckt->CKTrhsOld+here->VDIOposPrimeNode)- - *(ckt->CKTrhsOld + here->VDMOSdNode); + vd = model->VDMOStype * ( + *(ckt->CKTrhsOld+here->VDIOposPrimeNode)- + *(ckt->CKTrhsOld + here->VDMOSdNode)); delvd=vd- *(ckt->CKTstate0 + here->VDIOvoltage); diff --git a/src/spicelib/devices/vdmos/vdmosload.c b/src/spicelib/devices/vdmos/vdmosload.c index 5e29a989a..4cc60314f 100644 --- a/src/spicelib/devices/vdmos/vdmosload.c +++ b/src/spicelib/devices/vdmos/vdmosload.c @@ -84,16 +84,6 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) else Check_th = 0; - /* FIXME: - this is not a fix, but a hack: - with selfheat, op and op for ac don't work, NaN in self heating evaluation of - first iteration in CKTop(). Calling CKTop() from acan uses flag MODEDCOP, - changing this to MODETRANOP, as used by CKTop() called from dctran, then op is o.k. - */ - if (selfheat) - if(ckt->CKTmode == 528) /* includes MODEDCOP */ - ckt->CKTmode = 544; /* includes MODETRANOP */ - /* first, we compute a few useful values - these could be * pre-computed, but for historical reasons are still done * here. They may be moved at the expense of instance size From 1ef57ffc420409ddceb08fe6365db45bc6506808 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 12 Nov 2025 11:21:13 +0100 Subject: [PATCH 065/161] Add a variable 'debug-out-short' to enable a shortened debug-out.txt, useful when large circuits are monitored, which otherwise may result in GigaBit size of data. --- src/frontend/inp.c | 36 +++++++++++++++++++--------------- src/frontend/inpcom.c | 45 +++++++++++++++++++++++-------------------- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/src/frontend/inp.c b/src/frontend/inp.c index 603132760..97bcc16ad 100644 --- a/src/frontend/inp.c +++ b/src/frontend/inp.c @@ -993,19 +993,21 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) tc->linenum, tc->line); } } - fprintf(fdo, "**************** uncommented deck **************\n\n"); - /* always print first line */ - fprintf(fdo, "%6s %6d %6d %s\n", deck->linesource, deck->linenum_orig, deck->linenum, deck->line); - /* here without out-commented lines */ - for (tc = deck->nextcard; tc; tc = tc->nextcard) { - if (*(tc->line) == '*') - continue; - fprintf(fdo, "%6s %6d %6d %s\n", tc->linesource, tc->linenum_orig, tc->linenum, tc->line); + if (!cp_getvar("debug-out-short", CP_BOOL, NULL, 0)) { + fprintf(fdo, "**************** uncommented deck **************\n\n"); + /* always print first line */ + fprintf(fdo, "%6s %6d %6d %s\n", deck->linesource, deck->linenum_orig, deck->linenum, deck->line); + /* here without out-commented lines */ + for (tc = deck->nextcard; tc; tc = tc->nextcard) { + if (*(tc->line) == '*') + continue; + fprintf(fdo, "%6s %6d %6d %s\n", tc->linesource, tc->linenum_orig, tc->linenum, tc->line); + } + fprintf(fdo, "\n****************** complete deck ***************\n\n"); + /* now completely */ + for (tc = deck; tc; tc = tc->nextcard) + fprintf(fdo, "%6s %6d %6d %s\n", tc->linesource, tc->linenum_orig, tc->linenum, tc->line); } - fprintf(fdo, "\n****************** complete deck ***************\n\n"); - /* now completely */ - for (tc = deck; tc; tc = tc->nextcard) - fprintf(fdo, "%6s %6d %6d %s\n", tc->linesource, tc->linenum_orig, tc->linenum, tc->line); fclose(fdo); } else @@ -1209,10 +1211,12 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) continue; fprintf(fdo, "%6d %6d %s\n", tc->linenum_orig, tc->linenum, tc->line); } - fprintf(fdo, "\n****************** complete deck ***************\n\n"); - /* now completely */ - for (tc = deck; tc; tc = tc->nextcard) - fprintf(fdo, "%6d %6d %s\n", tc->linenum_orig, tc->linenum, tc->line); + if (!cp_getvar("debug-out-short", CP_BOOL, NULL, 0)) { + fprintf(fdo, "\n****************** complete deck ***************\n\n"); + /* now completely */ + for (tc = deck; tc; tc = tc->nextcard) + fprintf(fdo, "%6d %6d %s\n", tc->linenum_orig, tc->linenum, tc->line); + } fclose(fdo); } else diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index ae6cab075..c388d667e 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -1257,32 +1257,35 @@ struct card *inp_readall(FILE *fp, const char *dir_name, const char* file_name, t->linenum, t->line); } } - fprintf(fd, - "\n\n**************** uncommented deck " - "**************\n\n"); - /* always print first line */ - fprintf(fd, "%6s %6d %6d %s\n", cc->linesource, cc->linenum_orig, cc->linenum, - cc->line); - /* here without out-commented lines */ - for (t = cc->nextcard; t; t = t->nextcard) { - if (*(t->line) == '*') - continue; - fprintf(fd, "%6s %6d %6d %s\n", - t->linesource, t->linenum_orig, t->linenum, t->line); - } - fprintf(fd, + if (!cp_getvar("debug-out-short", CP_BOOL, NULL, 0)) { + fprintf(fd, + "\n\n**************** uncommented deck " + "**************\n\n"); + /* always print first line */ + fprintf(fd, "%6s %6d %6d %s\n", cc->linesource, cc->linenum_orig, cc->linenum, + cc->line); + /* here without out-commented lines */ + for (t = cc->nextcard; t; t = t->nextcard) { + if (*(t->line) == '*') + continue; + fprintf(fd, "%6s %6d %6d %s\n", + t->linesource, t->linenum_orig, t->linenum, t->line); + } + fprintf(fd, "\n\n****************** complete deck " "***************\n\n"); - /* now completely */ - for (t = cc; t; t = t->nextcard) - fprintf(fd, "%6s %6d %6d %s\n", - t->linesource, t->linenum_orig,t->linenum, t->line); + /* now completely */ + for (t = cc; t; t = t->nextcard) + fprintf(fd, "%6s %6d %6d %s\n", + t->linesource, t->linenum_orig, t->linenum, t->line); + } fclose(fd); fprintf(stdout, - "max line length %d, max subst. per line %d, number " - "of lines %d\n", - (int) max_line_length, no_braces, dynmaxline); + "max line length %d, max subst. per line %d, number " + "of lines %d\n", + (int)max_line_length, no_braces, dynmaxline); + } else fprintf(stderr, From c896fed4147bc2f50a66b7375e314dbd0c777a1f Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 12 Nov 2025 11:23:24 +0100 Subject: [PATCH 066/161] Update to commit 172fb6d66 ("Fix Bug 817 - "Global models are not visible from with subcircuits". Remove code that can miscount the number of nodes to be renamed.", 2025-10-08) Keep checking for x lines with nesting. This re-enables simulating large cxircuits (e.g. SRAMs) with deeply nested subcircuit calls. --- src/frontend/subckt.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/frontend/subckt.c b/src/frontend/subckt.c index 52eb230f5..dfb798f64 100644 --- a/src/frontend/subckt.c +++ b/src/frontend/subckt.c @@ -97,7 +97,7 @@ struct bxx_buffer; static void finishLine(struct bxx_buffer *dst, char *src, char *scname); static int settrans(char *formal, int flen, char *actual, const char *subname); static char *gettrans(const char *name, const char *name_end, bool *isglobal); -static int numnodes(const char *line); +static int numnodes(const char* line, struct subs* subs); static int numdevs(char *s); static wordlist *modtranslate(struct card *deck, char *subname, wordlist *new_modnames); static void devmodtranslate(struct card *deck, char *subname, wordlist * const orig_modnames); @@ -1173,11 +1173,15 @@ translate_inst_name(struct bxx_buffer *buffer, const char *scname, const char *n static int translate(struct card *deck, char *formal, int flen, char *actual, char *scname, const char *subname, struct subs *subs, wordlist const *modnames) { + struct card *c; struct bxx_buffer buffer; char *next_name, *name, *t, *nametofree, *paren_ptr; int nnodes, i, dim; int rtn = 0; + + NG_IGNORE(modnames); + #ifdef XSPICE bool got_vnam = FALSE; #endif @@ -1387,7 +1391,7 @@ translate(struct card *deck, char *formal, int flen, char *actual, char *scname, * Ignore controlling nodes as they get special treatment for POLY. */ - nnodes = numnodes(c->line); + nnodes = numnodes(c->line, subs); while (--nnodes >= 0) { name = gettok_node(&s); if (name == NULL) { @@ -1477,7 +1481,7 @@ translate(struct card *deck, char *formal, int flen, char *actual, char *scname, tfree(name); bxx_putc(&buffer, ' '); - nnodes = numnodes(c->line); + nnodes = numnodes(c->line, subs); while (--nnodes >= 0) { name = gettok_node(&s); if (name == NULL) { @@ -1690,18 +1694,26 @@ gettrans(const char *name, const char *name_end, bool *isglobal) /* Control nodes for E and G sources are not counted as they vary in * the case of POLY. The count returned by get_number_terminals() includes * devices for K (mutual inductors) and W (current-controlled switch). - */ - + * x lines are special, when nested and containing parameters. + * Therefore the old code is kept.*/ static int -numnodes(const char *line) +numnodes(const char* line, struct subs* subs) { switch (*line) { - case 'e': - case 'g': - case 'w': - return 2; - case 'k': - return 0; + case 'e': + case 'g': + case 'w': + return 2; + case 'k': + return 0; + case 'x': + { + const char* xname_e = skip_back_ws(strchr(line, '\0'), line); + const char* xname = skip_back_non_ws(xname_e, line); + for (; subs; subs = subs->su_next) + if (eq_substr(xname, xname_e, subs->su_name)) + return subs->su_numargs; + } } return get_number_terminals((char *)line); } From 804658601eefd1622033b115efbea7c4bc2695d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81rp=C3=A1d=20B=C5=B1rmen?= Date: Wed, 12 Nov 2025 14:13:07 +0100 Subject: [PATCH 067/161] Minor change in VDMOS that helps VADistiller. --- src/spicelib/devices/vdmos/vdmosload.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/spicelib/devices/vdmos/vdmosload.c b/src/spicelib/devices/vdmos/vdmosload.c index 4cc60314f..fd464fd20 100644 --- a/src/spicelib/devices/vdmos/vdmosload.c +++ b/src/spicelib/devices/vdmos/vdmosload.c @@ -363,7 +363,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) double t2 = exp((vgst-shift)/slope); vgst = slope * log(1 + t2); double dvgstdvgs = t2/(t2+1); - + if (vgst <= vdss) { /* saturation region */ cdrain = betap * vgst*vgst * .5; @@ -639,22 +639,23 @@ bypass: if (selfheat) { - + double gthjc = 1/model->VDMOSrthjc; + double gthca = 1/model->VDMOSrthca; (*(here->VDMOSDtempPtr) += dIrd_dT); (*(here->VDMOSDPtempPtr) += GmT - dIrd_dT); (*(here->VDMOSSPtempPtr) += -GmT); (*(here->VDMOSGPtempPtr) += 0.0); - (*(here->VDMOSTemptempPtr) += -gTtt - dIrd_dT*Vrd + 1/model->VDMOSrthjc + gcTt); + (*(here->VDMOSTemptempPtr) += -gTtt - dIrd_dT*Vrd + gthjc + gcTt); (*(here->VDMOSTempgpPtr) += -gTtg); (*(here->VDMOSTempdPtr) += -dIth_dVrd); (*(here->VDMOSTempdpPtr) += -gTtdp + dIth_dVrd); (*(here->VDMOSTempspPtr) += -gTtsp); - (*(here->VDMOSTemptcasePtr) += -1/model->VDMOSrthjc); - (*(here->VDMOSTcasetempPtr) += -1/model->VDMOSrthjc); - (*(here->VDMOSTcasetcasePtr) += 1/model->VDMOSrthjc + 1/model->VDMOSrthca); - (*(here->VDMOSTptpPtr) += 1/model->VDMOSrthca); - (*(here->VDMOSTptcasePtr) += -1/model->VDMOSrthca); - (*(here->VDMOSTcasetpPtr) += -1/model->VDMOSrthca); + (*(here->VDMOSTemptcasePtr) += -gthjc); + (*(here->VDMOSTcasetempPtr) += -gthjc); + (*(here->VDMOSTcasetcasePtr) += gthjc + gthca); + (*(here->VDMOSTptpPtr) += gthca); + (*(here->VDMOSTptcasePtr) += -gthca); + (*(here->VDMOSTcasetpPtr) += -gthca); (*(here->VDMOSCktTtpPtr) += 1.0); (*(here->VDMOSTpcktTPtr) += 1.0); } From 2bc63e71aee7d1fac7d61ac4aac4a460f97a5613 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81rp=C3=A1d=20B=C5=B1rmen?= Date: Thu, 13 Nov 2025 15:31:40 +0100 Subject: [PATCH 068/161] VDMOS scaling fixed. --- src/spicelib/devices/vdmos/vdmosacld.c | 6 ++++-- src/spicelib/devices/vdmos/vdmosload.c | 13 ++++++++----- src/spicelib/devices/vdmos/vdmosnoi.c | 5 +++-- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/spicelib/devices/vdmos/vdmosacld.c b/src/spicelib/devices/vdmos/vdmosacld.c index 5e5315611..4a4826994 100644 --- a/src/spicelib/devices/vdmos/vdmosacld.c +++ b/src/spicelib/devices/vdmos/vdmosacld.c @@ -48,7 +48,8 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt) GmT = model->VDMOStype * here->VDMOSgmT; cgT = model->VDMOStype * here->VDMOScgT; cdT = model->VDMOStype * here->VDMOScdT; - cTt = model->VDMOScthj; + // Everything is computed for m parallel instances... so scale cthj accordingly + cTt = here->VDMOSm * model->VDMOScthj; gTtg = here->VDMOSgtempg; gTtdp = here->VDMOSgtempd; gTtt = here->VDMOSgtempT; @@ -57,7 +58,8 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt) GmT = -model->VDMOStype * here->VDMOSgmT; cgT = -model->VDMOStype * here->VDMOScgT; cdT = -model->VDMOStype * here->VDMOScdT; - cTt = -model->VDMOScthj; + // Everything is computed for m parallel instances... so scale cthj accordingly + cTt = - here->VDMOSm * model->VDMOScthj; gTtg = -here->VDMOSgtempg; gTtdp = -here->VDMOSgtempd; gTtt = -here->VDMOSgtempT; diff --git a/src/spicelib/devices/vdmos/vdmosload.c b/src/spicelib/devices/vdmos/vdmosload.c index fd464fd20..ac15a251b 100644 --- a/src/spicelib/devices/vdmos/vdmosload.c +++ b/src/spicelib/devices/vdmos/vdmosload.c @@ -462,10 +462,12 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) * you must add in the other half from previous time * and the constant part */ - DevCapVDMOS(vgd, cgdmin, cgdmax, a, cgs, + // Everything is computed for m parallel instances... scale ggdmin, cgdmax, and cgs accordingly + DevCapVDMOS(vgd, here->VDMOSm*cgdmin, here->VDMOSm*cgdmax, a, here->VDMOSm*cgs, (ckt->CKTstate0 + here->VDMOScapgs), (ckt->CKTstate0 + here->VDMOScapgd)); - *(ckt->CKTstate0 + here->VDMOScapth) = model->VDMOScthj; /* always constant */ + // Everything is computed for m parallel instances... so scale cthj accordingly + *(ckt->CKTstate0 + here->VDMOScapth) = here->VDMOSm * model->VDMOScthj; /* always constant */ vgs1 = *(ckt->CKTstate1 + here->VDMOSvgs); vgd1 = vgs1 - *(ckt->CKTstate1 + here->VDMOSvds); @@ -604,7 +606,7 @@ bypass: vCktTemp *= ckt->CKTsrcFact; *(ckt->CKTrhs + here->VDMOSvcktTbranch)+= vCktTemp; } - + /* * load y matrix */ @@ -639,8 +641,9 @@ bypass: if (selfheat) { - double gthjc = 1/model->VDMOSrthjc; - double gthca = 1/model->VDMOSrthca; + // Everything is computed for m parallel instances... so scale gthjc and gthja accordingly + double gthjc = here->VDMOSm / model->VDMOSrthjc; + double gthca = here->VDMOSm / model->VDMOSrthca; (*(here->VDMOSDtempPtr) += dIrd_dT); (*(here->VDMOSDPtempPtr) += GmT - dIrd_dT); (*(here->VDMOSSPtempPtr) += -GmT); diff --git a/src/spicelib/devices/vdmos/vdmosnoi.c b/src/spicelib/devices/vdmos/vdmosnoi.c index 273d4f34e..8896bd54d 100644 --- a/src/spicelib/devices/vdmos/vdmosnoi.c +++ b/src/spicelib/devices/vdmos/vdmosnoi.c @@ -110,11 +110,12 @@ VDMOSnoise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, NevalSrc(&noizDens[VDMOSFLNOIZ], NULL, ckt, N_GAIN,inst->VDMOSdNodePrime, inst->VDMOSsNodePrime, (double)0.0); + // VDMOScd is scaled with m, no need to scale coxSquared (which is a constant) + // Should be proportional to m noizDens[VDMOSFLNOIZ] *= model->VDMOSfNcoef * exp(model->VDMOSfNexp * log(MAX(fabs(inst->VDMOScd),N_MINLOG))) / - (data->freq * - inst->VDMOSm * coxSquared); + (data->freq * coxSquared); lnNdens[VDMOSFLNOIZ] = log(MAX(noizDens[VDMOSFLNOIZ],N_MINLOG)); From 6bd5c2d03b376093cbadeaec1433e449c635f03a Mon Sep 17 00:00:00 2001 From: dwarning Date: Sat, 15 Nov 2025 09:50:51 +0100 Subject: [PATCH 069/161] VDMOS: apply m scaling fix for acld as well --- src/spicelib/devices/vdmos/vdmosacld.c | 25 ++++++++++++++----------- src/spicelib/devices/vdmos/vdmosload.c | 14 +++++++------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/spicelib/devices/vdmos/vdmosacld.c b/src/spicelib/devices/vdmos/vdmosacld.c index 4a4826994..920cbd611 100644 --- a/src/spicelib/devices/vdmos/vdmosacld.c +++ b/src/spicelib/devices/vdmos/vdmosacld.c @@ -133,19 +133,22 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt) *(here->VDIORPdPtr +1) -= xceq; if (selfheat) { - *(here->VDMOSDPtempPtr) += GmT; + // Everything is computed for m parallel instances... so scale gthjc and gthja accordingly + double gthjc = here->VDMOSm / model->VDMOSrthjc; + double gthca = here->VDMOSm / model->VDMOSrthca; + *(here->VDMOSDPtempPtr) += GmT; *(here->VDMOSSPtempPtr) += -GmT; - *(here->VDMOSTemptempPtr) += gTtt + 1/model->VDMOSrthjc; - *(here->VDMOSTempgpPtr) += gTtg; - *(here->VDMOSTempdpPtr) += gTtdp; - *(here->VDMOSTempspPtr) += gTtsp; - *(here->VDMOSTemptcasePtr) += -1/model->VDMOSrthjc; - *(here->VDMOSTcasetempPtr) += -1/model->VDMOSrthjc; - *(here->VDMOSTcasetcasePtr) += 1/model->VDMOSrthjc + 1/model->VDMOSrthca; - *(here->VDMOSTptpPtr) += 1/model->VDMOSrthca; - *(here->VDMOSTptcasePtr) += -1/model->VDMOSrthca; - *(here->VDMOSTcasetpPtr) += -1/model->VDMOSrthca; + *(here->VDMOSTemptempPtr) += gTtt + gthjc; + *(here->VDMOSTempgpPtr) += gTtg; + *(here->VDMOSTempdpPtr) += gTtdp; + *(here->VDMOSTempspPtr) += gTtsp; + *(here->VDMOSTemptcasePtr) += -gthjc; + *(here->VDMOSTcasetempPtr) += -gthjc; + *(here->VDMOSTcasetcasePtr) += gthjc + gthca; + *(here->VDMOSTptpPtr) += gthca; + *(here->VDMOSTptcasePtr) += -gthca; + *(here->VDMOSTcasetpPtr) += -gthca; *(here->VDMOSCktTtpPtr) += 1.0; *(here->VDMOSTpcktTPtr) += 1.0; diff --git a/src/spicelib/devices/vdmos/vdmosload.c b/src/spicelib/devices/vdmos/vdmosload.c index ac15a251b..5e93d9174 100644 --- a/src/spicelib/devices/vdmos/vdmosload.c +++ b/src/spicelib/devices/vdmos/vdmosload.c @@ -67,16 +67,17 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) /* loop through all the VDMOS device models */ for (; model != NULL; model = VDMOSnextModel(model)) { - /* VDMOS capacitance parameters */ - const double cgdmin = model->VDMOScgdmin; - const double cgdmax = model->VDMOScgdmax; - const double a = model->VDMOSa; - const double cgs = model->VDMOScgs; /* loop through all the instances of the model */ for (here = VDMOSinstances(model); here != NULL; here = VDMOSnextInstance(here)) { + /* VDMOS capacitance parameters */ + const double cgdmin = here->VDMOSm * model->VDMOScgdmin; + const double cgdmax = here->VDMOSm * model->VDMOScgdmax; + const double a = model->VDMOSa; + const double cgs = here->VDMOSm * model->VDMOScgs; + Temp = here->VDMOStemp; selfheat = (here->VDMOSthermal) && (model->VDMOSrthjcGiven); if (selfheat) @@ -462,8 +463,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) * you must add in the other half from previous time * and the constant part */ - // Everything is computed for m parallel instances... scale ggdmin, cgdmax, and cgs accordingly - DevCapVDMOS(vgd, here->VDMOSm*cgdmin, here->VDMOSm*cgdmax, a, here->VDMOSm*cgs, + DevCapVDMOS(vgd, cgdmin, cgdmax, a, cgs, (ckt->CKTstate0 + here->VDMOScapgs), (ckt->CKTstate0 + here->VDMOScapgd)); // Everything is computed for m parallel instances... so scale cthj accordingly From 817236252911951db2e14db2389e7dab1b2365e3 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 15 Nov 2025 19:49:07 +0100 Subject: [PATCH 070/161] Using cbrt() instead of exp(log...) might be more efficient --- src/spicelib/analysis/cktterr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/spicelib/analysis/cktterr.c b/src/spicelib/analysis/cktterr.c index 9852b2acf..f2868e6ac 100644 --- a/src/spicelib/analysis/cktterr.c +++ b/src/spicelib/analysis/cktterr.c @@ -69,7 +69,9 @@ CKTterr(int qcap, CKTcircuit *ckt, double *timeStep) del = ckt->CKTtrtol * tol/MAX(ckt->CKTabstol,factor * fabs(diff[0])); if(ckt->CKTorder == 2) { del = sqrt(del); - } else if (ckt->CKTorder > 2) { + } else if (ckt->CKTorder == 3) { + del = cbrt(del); + } else if (ckt->CKTorder > 3) { del = exp(log(del)/ckt->CKTorder); } *timeStep = MIN(*timeStep,del); From f3871c3ea2c03f55765802588f835baf4177727a Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 15 Nov 2025 19:50:04 +0100 Subject: [PATCH 071/161] Try to equalise the last two time steps before a breakpoint, if the second step would be smaller than CKTdelta otherwise. --- src/spicelib/analysis/dctran.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/spicelib/analysis/dctran.c b/src/spicelib/analysis/dctran.c index 035105a79..4c55678d5 100644 --- a/src/spicelib/analysis/dctran.c +++ b/src/spicelib/analysis/dctran.c @@ -525,6 +525,7 @@ resume: } #ifndef XSPICE + /* Force the breakpoint if appropriate */ else if(ckt->CKTtime + ckt->CKTdelta >= ckt->CKTbreaks[0]) { ckt->CKTsaveDelta = ckt->CKTdelta; ckt->CKTdelta = ckt->CKTbreaks[0] - ckt->CKTtime; @@ -534,6 +535,15 @@ resume: #endif ckt->CKTbreak = 1; /* why? the current pt. is not a bkpt. */ } + /* Try to equalise the last two time steps before the breakpoint, + if the second step would be smaller than CKTdelta otherwise.*/ + else if (ckt->CKTtime + 1.9 * ckt->CKTdelta > ckt->CKTbreaks[0]) { + ckt->CKTsaveDelta = ckt->CKTdelta; + ckt->CKTdelta = (ckt->CKTbreaks[0] - ckt->CKTtime) / 2.; +#ifdef STEPDEBUG + fprintf(stdout, "Delta equalising step at time %e with delta %e\n", ckt->CKTtime, ckt->CKTdelta); +#endif + } #endif /* !XSPICE */ @@ -574,6 +584,15 @@ resume: ckt->CKTsaveDelta = ckt->CKTdelta; ckt->CKTdelta = ckt->CKTbreaks[0] - ckt->CKTtime; } + /* Try to equalise the last two time steps before the breakpoint, + if the second step would be smaller than CKTdelta otherwise.*/ + else if (ckt->CKTtime + 1.9 * ckt->CKTdelta > ckt->CKTbreaks[0]) { + ckt->CKTsaveDelta = ckt->CKTdelta; + ckt->CKTdelta = (ckt->CKTbreaks[0] - ckt->CKTtime) / 2.; +#ifdef STEPDEBUG + fprintf(stdout, "Delta equalising step at time %e with delta %e\n", ckt->CKTtime, ckt->CKTdelta); +#endif + } #ifdef SHARED_MODULE /* Either directly go to next time step, or modify ckt->CKTdelta depending on From bc7d68884ec50196c99cf16034ee853011a2bde5 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 16 Nov 2025 12:12:48 +0100 Subject: [PATCH 072/161] Remove variable and flag 'use_numparams'. Not using numparam has not been a supported option for the last 20 years. --- src/frontend/subckt.c | 139 +++++++++++++++++------------------------- 1 file changed, 56 insertions(+), 83 deletions(-) diff --git a/src/frontend/subckt.c b/src/frontend/subckt.c index dfb798f64..a0fed2696 100644 --- a/src/frontend/subckt.c +++ b/src/frontend/subckt.c @@ -135,9 +135,6 @@ struct subs { * list of translated names (i.e. after subckt expansion) */ -/* flag indicating use of the experimental numparams library */ -static bool use_numparams = FALSE; - static char start[32], sbend[32], invoke[32], model[32]; static void @@ -224,48 +221,41 @@ inp_subcktexpand(struct card *deck) { if (!cp_getvar("modelline", CP_STRING, model, sizeof(model))) strcpy(model, ".model"); -/* use_numparams = cp_getvar("numparams", CP_BOOL, NULL, 0); */ - - use_numparams = TRUE; // tprint(deck); /* deck has .control sections already removed, but not comments */ - if (use_numparams) { - #ifdef TRACE - fprintf(stderr, "Numparams is processing this deck:\n"); - for (c = deck; c; c = c->nextcard) { - if (ciprefix("*", c->line)) - continue; - fprintf(stderr, "%3d:%s\n", c->linenum, c->line); - } -#endif - - nupa_signal(NUPADECKCOPY); - /* get the subckt names from the deck */ - for (c = deck; c; c = c->nextcard) { /* first Numparam pass */ - if (ciprefix(".subckt", c->line)) { - nupa_scan(c); - } - } - - /* now copy instances */ - for (c = deck; c; c = c->nextcard) { /* first Numparam pass */ - if (*(c->line) == '*') { - continue; - } - c->line = nupa_copy(c); - } - -#ifdef TRACE - fprintf(stderr, "Numparams transformed deck:\n"); - for (c = deck; c; c = c->nextcard) { - if (ciprefix("*", c->line)) - continue; - fprintf(stderr, "%3d:%s\n", c->linenum, c->line); - } -#endif - + fprintf(stderr, "Numparams is processing this deck:\n"); + for (c = deck; c; c = c->nextcard) { + if (ciprefix("*", c->line)) + continue; + fprintf(stderr, "%3d:%s\n", c->linenum, c->line); } +#endif + + nupa_signal(NUPADECKCOPY); + /* get the subckt names from the deck */ + for (c = deck; c; c = c->nextcard) { /* first Numparam pass */ + if (ciprefix(".subckt", c->line)) { + nupa_scan(c); + } + } + + /* now copy instances */ + for (c = deck; c; c = c->nextcard) { /* first Numparam pass */ + if (*(c->line) == '*') { + continue; + } + c->line = nupa_copy(c); + } + +#ifdef TRACE + fprintf(stderr, "Numparams transformed deck:\n"); + for (c = deck; c; c = c->nextcard) { + if (ciprefix("*", c->line)) + continue; + fprintf(stderr, "%3d:%s\n", c->linenum, c->line); + } +#endif /* Get all the model names so we can deal with BJTs, etc. * Stick all the model names into the doubly-linked wordlist modnames. @@ -374,36 +364,34 @@ inp_subcktexpand(struct card *deck) { if (ciprefix(invoke, c->line)) { fprintf(cp_err, "Error: unknown subckt: %s\n", c->line); fprintf(cp_err, " in line no. %d from file %s\n", c->linenum_orig, c->linesource); - if (use_numparams) - nupa_signal(NUPAEVALDONE); + + nupa_signal(NUPAEVALDONE); return NULL; } - if (use_numparams) { - /* the NUMPARAM final line translation pass */ - nupa_signal(NUPASUBDONE); - for (c = deck; c; c = c->nextcard) - /* 'param' .meas statements can have dependencies on measurement values */ - /* need to skip evaluating here and evaluate after other .meas statements */ - if (ciprefix(".meas", c->line) && strstr(c->line, "param")) { - ; - } else { - nupa_eval(c); - } + /* the NUMPARAM final line translation pass */ + nupa_signal(NUPASUBDONE); + for (c = deck; c; c = c->nextcard) + /* 'param' .meas statements can have dependencies on measurement values */ + /* need to skip evaluating here and evaluate after other .meas statements */ + if (ciprefix(".meas", c->line) && strstr(c->line, "param")) { + ; + } else { + nupa_eval(c); + } #ifdef TRACE - fprintf(stderr, "Numparams converted deck:\n"); - for (c = deck; c; c = c->nextcard) { - if (ciprefix("*", c->line)) - continue; - fprintf(stderr, "%3d:%s\n", c->linenum, c->line); - } + fprintf(stderr, "Numparams converted deck:\n"); + for (c = deck; c; c = c->nextcard) { + if (ciprefix("*", c->line)) + continue; + fprintf(stderr, "%3d:%s\n", c->linenum, c->line); + } #endif - /*nupa_list_params(stdout);*/ - nupa_copy_inst_dico(); - nupa_signal(NUPAEVALDONE); - } + /*nupa_list_params(stdout);*/ + nupa_copy_inst_dico(); + nupa_signal(NUPAEVALDONE); return (deck); /* return the spliced deck. */ } @@ -535,13 +523,8 @@ doit(struct card *deck, wordlist *modnames) { else deck = c; - if (use_numparams == FALSE) { - line_free_x(ends, FALSE); /* drop the .ends card */ - prev_of_ends->nextcard = NULL; - } else { - ends->line[0] = '*'; /* comment the .ends card */ - ends->nextcard = NULL; - } + ends->line[0] = '*'; /* comment the .ends card */ + ends->nextcard = NULL; } else { @@ -760,18 +743,8 @@ doit(struct card *deck, wordlist *modnames) { error = 1; /* Now splice the decks together. */ - - if (use_numparams == FALSE) { - line_free_x(c, FALSE); /* drop the invocation */ - if (prev_of_c) - prev_of_c->nextcard = su_deck; - else - deck = su_deck; - } else { - c->line[0] = '*'; /* comment the invocation */ - c->nextcard = su_deck; - } - + c->line[0] = '*'; /* comment the invocation */ + c->nextcard = su_deck; c = su_deck; while (c->nextcard) c = c->nextcard; From 6dfaf3f11c3c371964e759c1c496e9534ea4a727 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 17 Nov 2025 14:12:42 +0100 Subject: [PATCH 073/161] Enable guessing the vector type or SP analysis in batch mode. --- src/frontend/outitf.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/frontend/outitf.c b/src/frontend/outitf.c index 6ca75d8d5..282616cef 100644 --- a/src/frontend/outitf.c +++ b/src/frontend/outitf.c @@ -970,8 +970,9 @@ fileInit(runDesc *run) } /* Trying to guess the type of a vector, using either their special names - or special parameter names for @ vecors. FIXME This guessing may fail - due to the many options, especially for the @ vectors. */ + or special parameter names for @ vectors. FIXME This guessing may fail + due to the many options, especially for the @ vectors. pltypename + may be run->type in batch mode or the plot name in control mode. */ static int guess_type(const char *name, char* pltypename) { @@ -1040,13 +1041,15 @@ static void fileInit_pass2(runDesc *run) { int i, type; + bool keepbranch = cp_getvar("keep#branch", CP_BOOL, NULL, 0); for (i = 0; i < run->numData; i++) { char *name = run->data[i].name; - type = guess_type(name, NULL); + /* Use run->type to detect SP analysis */ + type = guess_type(name, run->type); if (type == SV_CURRENT && !keepbranch) { char *branch = strstr(name, "#branch"); @@ -1185,6 +1188,7 @@ plotInit(runDesc *run) else name = copy(dd->name); + /* Use pl->pl_typename to detect SP analysis */ v = dvec_alloc(name, guess_type(name, pl->pl_typename), run->isComplex From 83bf3ae46bf56a50f0a55bed0884b170d474f96b Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 17 Nov 2025 18:41:12 +0100 Subject: [PATCH 074/161] Remove a double entry --- src/frontend/outitf.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/frontend/outitf.c b/src/frontend/outitf.c index 282616cef..8e9bcd9ce 100644 --- a/src/frontend/outitf.c +++ b/src/frontend/outitf.c @@ -26,7 +26,6 @@ Modified: 2000 AlansFixes, 2013/2015 patch by Krzysztof Blaszkowski #include "variable.h" #include #include "ngspice/cktdefs.h" -#include "ngspice/inpdefs.h" #include "breakp2.h" #include "runcoms.h" #include "plotting/graf.h" From 6304f0124baf73fac494e0788509e886699edf48 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 17 Nov 2025 23:56:50 +0100 Subject: [PATCH 075/161] Remove unused functions from the IFfrontEnd struct. --- src/frontend/outitf.c | 72 ++----------------------------------- src/frontend/outitf.h | 9 ----- src/include/ngspice/ifsim.h | 15 -------- src/main.c | 13 ++----- src/sharedspice.c | 6 ---- 5 files changed, 4 insertions(+), 111 deletions(-) diff --git a/src/frontend/outitf.c b/src/frontend/outitf.c index 8e9bcd9ce..91cb49624 100644 --- a/src/frontend/outitf.c +++ b/src/frontend/outitf.c @@ -118,20 +118,6 @@ OUTpBeginPlot(CKTcircuit *circuitPtr, JOB *analysisPtr, } -int -OUTwBeginPlot(CKTcircuit *circuitPtr, JOB *analysisPtr, - IFuid analName, - IFuid refName, int refType, - int numNames, IFuid *dataNames, int dataType, runDesc **plotPtr) -{ - - return (beginPlot(analysisPtr, circuitPtr, "circuit name", - analName, refName, refType, numNames, - dataNames, dataType, TRUE, - plotPtr)); -} - - static int beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analName, char *refName, int refType, int numNames, char **dataNames, int dataType, bool windowed, runDesc **runp) { @@ -148,10 +134,9 @@ beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analNam bool savenointernals = FALSE; char *an_name; int initmem; - /*to resume a run saj - *All it does is reassign the file pointer and return (requires *runp to be NULL if this is not needed) - */ + /*to resume a run, Reassign the file pointer and return + (requires *runp to be NULL if this is not needed)*/ if (dataType == 666 && numNames == 666) { run = *runp; run->writeOut = ft_getOutReq(&run->fp, &run->runPlot, &run->binary, @@ -801,38 +786,6 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr) } /* end of function OUTpData */ - -int OUTwReference(runDesc*plotPtr, IFvalue *valuePtr, void **refPtr) -{ - NG_IGNORE(refPtr); - NG_IGNORE(valuePtr); - NG_IGNORE(plotPtr); - - return OK; -} - - -int -OUTwData(runDesc *plotPtr, int dataIndex, IFvalue *valuePtr, void *refPtr) -{ - NG_IGNORE(refPtr); - NG_IGNORE(valuePtr); - NG_IGNORE(dataIndex); - NG_IGNORE(plotPtr); - - return OK; -} - - -int -OUTwEnd(runDesc *plotPtr) -{ - NG_IGNORE(plotPtr); - - return OK; -} - - int OUTendPlot(runDesc *plotPtr) { @@ -852,27 +805,6 @@ OUTendPlot(runDesc *plotPtr) } -int -OUTbeginDomain(runDesc *plotPtr, IFuid refName, int refType, IFvalue *outerRefValue) -{ - NG_IGNORE(outerRefValue); - NG_IGNORE(refType); - NG_IGNORE(refName); - NG_IGNORE(plotPtr); - - return (OK); -} - - -int -OUTendDomain(runDesc *plotPtr) -{ - NG_IGNORE(plotPtr); - - return (OK); -} - - int OUTattributes(runDesc *plotPtr, IFuid varName, int param, IFvalue *value) { diff --git a/src/frontend/outitf.h b/src/frontend/outitf.h index efb333119..cf4895d7e 100644 --- a/src/frontend/outitf.h +++ b/src/frontend/outitf.h @@ -50,17 +50,8 @@ int OUTpBeginPlot(CKTcircuit *circuitPtr, JOB *analysisPtr, IFuid analName, IFuid refName, int refType, int numNames, IFuid *dataNames, int dataType, runDesc **plotPtr); -int OUTwBeginPlot(CKTcircuit *circuitPtr, JOB *analysisPtr, - IFuid analName, - IFuid refName, int refType, - int numNames, IFuid *dataNames, int dataType, runDesc **plotPtr); int OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr); -int OUTwReference(runDesc *plotPtr, IFvalue *valuePtr, void **refPtr); -int OUTwData(runDesc *plotPtr, int dataIndex, IFvalue *valuePtr, void *refPtr); -int OUTwEnd(runDesc *plotPtr); int OUTendPlot(runDesc *plotPtr); -int OUTbeginDomain(runDesc *plotPtr, IFuid refName, int refType, IFvalue *outerRefValue); -int OUTendDomain(runDesc *plotPtr); int OUTattributes(runDesc *plotPtr, IFuid varName, int param, IFvalue *value); int OUTstopnow(void); void OUTerror(int flags, char *format, IFuid *names); diff --git a/src/include/ngspice/ifsim.h b/src/include/ngspice/ifsim.h index cf019be2e..ca2f0787f 100644 --- a/src/include/ngspice/ifsim.h +++ b/src/include/ngspice/ifsim.h @@ -455,23 +455,8 @@ struct IFfrontEnd { /* start pointwise output plot */ int (*OUTpData) (runDesc *, IFvalue *, IFvalue *); /* data for pointwise plot */ - int (*OUTwBeginPlot) (CKTcircuit *, JOB *, - IFuid, - IFuid, int, - int, IFuid *, int, runDesc **); - /* start windowed output plot */ - int (*OUTwReference) (runDesc *, IFvalue *, void **); - /* independent vector for windowed plot */ - int (*OUTwData) (runDesc *, int, IFvalue *, void *); - /* data for windowed plot */ - int (*OUTwEnd) (runDesc *); - /* signal end of windows */ int (*OUTendPlot) (runDesc *); /* end of plot */ - int (*OUTbeginDomain) (runDesc *, IFuid, int, IFvalue *); - /* start nested domain */ - int (*OUTendDomain) (runDesc *); - /* end nested domain */ int (*OUTattributes) (runDesc *, IFuid, int, IFvalue *); /* specify output attributes of node */ }; diff --git a/src/main.c b/src/main.c index 723855c7a..c547d5475 100644 --- a/src/main.c +++ b/src/main.c @@ -200,11 +200,8 @@ struct comm *cp_coms = spcp_coms; extern int OUTpBeginPlot(CKTcircuit *, JOB *, IFuid, IFuid, int, int, IFuid *, int, runDesc **); extern int OUTpData(runDesc *, IFvalue *, IFvalue *); -extern int OUTwBeginPlot(CKTcircuit *, JOB *, IFuid, IFuid, int, int, IFuid *, int, runDesc **); -extern int OUTwReference(runDesc *, IFvalue *, void **); -extern int OUTwData(runDesc *, int, IFvalue *, void *), OUTwEnd(runDesc *), OUTendPlot(runDesc *); -extern int OUTbeginDomain(runDesc *, IFuid, int, IFvalue *); -extern int OUTendDomain(runDesc *), OUTstopnow(void); +extern int OUTendPlot(runDesc *); +extern int OUTstopnow(void); extern void OUTerror(int, char *, IFuid *); #ifdef __GNUC__ @@ -224,13 +221,7 @@ IFfrontEnd nutmeginfo = { OUTerrorf, OUTpBeginPlot, OUTpData, - OUTwBeginPlot, - OUTwReference, - OUTwData, - OUTwEnd, OUTendPlot, - OUTbeginDomain, - OUTendDomain, OUTattributes }; diff --git a/src/sharedspice.c b/src/sharedspice.c index 5049fd12a..b7c660c87 100644 --- a/src/sharedspice.c +++ b/src/sharedspice.c @@ -258,13 +258,7 @@ IFfrontEnd nutmeginfo = { OUTerrorf, OUTpBeginPlot, OUTpData, - OUTwBeginPlot, - OUTwReference, - OUTwData, - OUTwEnd, OUTendPlot, - OUTbeginDomain, - OUTendDomain, OUTattributes }; From 59a64f57d6a1cf94070f97e2745e9812e2c0c708 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 18 Nov 2025 16:01:19 +0100 Subject: [PATCH 076/161] Update: add frequency measurement and temperature dependency. --- examples/mos/ro_17_4.cir | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/examples/mos/ro_17_4.cir b/examples/mos/ro_17_4.cir index c4dccaa89..930ccb04a 100644 --- a/examples/mos/ro_17_4.cir +++ b/examples/mos/ro_17_4.cir @@ -42,33 +42,36 @@ mp17 2 18 1 1 p1 l=0.1u w=10u ad=5p pd=6u as=5p ps=6u mn17 2 18 0 0 n1 l=0.1u w=5u ad=5p pd=6u as=5p ps=6u c1 18 0 .1p -* .ic v(2)=1.0 v(3)=1.0 v(4)=1.0 -* .ic v(2)=2.0 v(3)=0.0 v(4)=2.0 -* .ic v(2)=2.0 v(3)=0.0 v(4)=2.0 v(5)=0.0 v(6)=2.0 -* .ic v(7)=0.0 v(8)=2.0 v(9)=0.0 v(10)=2.0 v(11)=0.0 v(12)=2.0 -* .ic v(13)=0.0 v(14)=2.0 v(15)=0.0 v(16)=2.0 v(17)=0.0 v(18)=2.0 -* .ic V(10)=5 v(2)=5 v(3)=5 v(4)=5 v(5)=5 v(6)=5 - -* .ic v(18)=1 - .tran .1ns 150ns uic -* .option xmu = 0.49 -* .print tran v(5) - .control * reduce current ringing option xmu = 0.49 -* set xmu=0.49 -set num_threads=8 set noinit -run +run ; temp is 27°C * current and output in a single plot plot v(18) 1000*(-I(vdd)) ylimit -1 6 +meas tran tdiff TRIG v(18) VAL=0.5 RISE=10 TARG v(18) VAL=0.5 RISE=20 +let freq = 10/tdiff +let delay = tdiff/17 +print freq delay +echo +echo + +set temp=100 +run ; temp is 100°C + +* current and output in a single plot +plot v(18) 1000*(-I(vdd)) ylimit -1 6 + +meas tran tdiff TRIG v(18) VAL=0.5 RISE=10 TARG v(18) VAL=0.5 RISE=20 +let freq = 10/tdiff +let delay = tdiff/17 +print freq delay .endc * Short channel models from CMOS Circuit Design, Layout, and Simulation, From f1378f2e5a5cd730aceedc4663675872c5e54940 Mon Sep 17 00:00:00 2001 From: dwarning Date: Thu, 20 Nov 2025 15:09:04 +0100 Subject: [PATCH 077/161] general vdmos update --- src/spicelib/devices/vdmos/vdmosacld.c | 5 +- src/spicelib/devices/vdmos/vdmosbindCSC.c | 30 ++--- src/spicelib/devices/vdmos/vdmosconv.c | 4 +- src/spicelib/devices/vdmos/vdmosdefs.h | 18 +-- src/spicelib/devices/vdmos/vdmosload.c | 142 +++++++++++++--------- src/spicelib/devices/vdmos/vdmosset.c | 22 ++-- 6 files changed, 126 insertions(+), 95 deletions(-) diff --git a/src/spicelib/devices/vdmos/vdmosacld.c b/src/spicelib/devices/vdmos/vdmosacld.c index 920cbd611..fd90caa66 100644 --- a/src/spicelib/devices/vdmos/vdmosacld.c +++ b/src/spicelib/devices/vdmos/vdmosacld.c @@ -138,7 +138,6 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt) double gthca = here->VDMOSm / model->VDMOSrthca; *(here->VDMOSDPtempPtr) += GmT; *(here->VDMOSSPtempPtr) += -GmT; - *(here->VDMOSTemptempPtr) += gTtt + gthjc; *(here->VDMOSTempgpPtr) += gTtg; *(here->VDMOSTempdpPtr) += gTtdp; @@ -149,8 +148,8 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt) *(here->VDMOSTptpPtr) += gthca; *(here->VDMOSTptcasePtr) += -gthca; *(here->VDMOSTcasetpPtr) += -gthca; - *(here->VDMOSCktTtpPtr) += 1.0; - *(here->VDMOSTpcktTPtr) += 1.0; + *(here->VDMOSDevTtpPtr) += 1.0; + *(here->VDMOSTpdevTPtr) += 1.0; *(here->VDMOSTemptempPtr + 1) += xcTt; *(here->VDMOSDPtempPtr + 1) += xcdT; diff --git a/src/spicelib/devices/vdmos/vdmosbindCSC.c b/src/spicelib/devices/vdmos/vdmosbindCSC.c index 860dee0c6..bd24b856d 100644 --- a/src/spicelib/devices/vdmos/vdmosbindCSC.c +++ b/src/spicelib/devices/vdmos/vdmosbindCSC.c @@ -67,8 +67,8 @@ VDMOSbindCSC (GENmodel *inModel, CKTcircuit *ckt) CREATE_KLU_BINDING_TABLE(VDMOSTempdPtr, VDMOSTempdBinding, VDMOStempNode, VDMOSdNode); CREATE_KLU_BINDING_TABLE(VDIOPosPrimetempPtr, VDIOPosPrimetempBinding, VDIOposPrimeNode, VDMOStempNode); CREATE_KLU_BINDING_TABLE(VDMOSDtempPtr, VDMOSDtempBinding, VDMOSdNode, VDMOStempNode); - CREATE_KLU_BINDING_TABLE(VDMOStempSPtr, VDMOStempSBinding, VDMOStempNode, VDMOSsNode); - CREATE_KLU_BINDING_TABLE(VDMOSSTempPtr, VDMOSSTempBinding, VDMOSsNode, VDMOStempNode); + CREATE_KLU_BINDING_TABLE(VDMOSTempsPtr, VDMOStempSBinding, VDMOStempNode, VDMOSsNode); + CREATE_KLU_BINDING_TABLE(VDMOSStempPtr, VDMOSSTempBinding, VDMOSsNode, VDMOStempNode); CREATE_KLU_BINDING_TABLE(VDMOSTcasetcasePtr, VDMOSTcasetcaseBinding, VDMOStcaseNode, VDMOStcaseNode); /* Rthjc between tj and tcase*/ CREATE_KLU_BINDING_TABLE(VDMOSTcasetempPtr, VDMOSTcasetempBinding, VDMOStcaseNode, VDMOStempNode); @@ -76,9 +76,9 @@ VDMOSbindCSC (GENmodel *inModel, CKTcircuit *ckt) CREATE_KLU_BINDING_TABLE(VDMOSTptpPtr, VDMOSTptpBinding, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */ CREATE_KLU_BINDING_TABLE(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStcaseNode); CREATE_KLU_BINDING_TABLE(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStcaseNode, VDMOStNodePrime); - CREATE_KLU_BINDING_TABLE(VDMOSCktTcktTPtr, VDMOSCktTcktTBinding, VDMOSvcktTbranch, VDMOSvcktTbranch); /* Vsrc=cktTemp to gnd */ - CREATE_KLU_BINDING_TABLE(VDMOSCktTtpPtr, VDMOSCktTtpBinding, VDMOSvcktTbranch, VDMOStNodePrime); - CREATE_KLU_BINDING_TABLE(VDMOSTpcktTPtr, VDMOSTpcktTBinding, VDMOStNodePrime, VDMOSvcktTbranch); + CREATE_KLU_BINDING_TABLE(VDMOSDevTdevTPtr, VDMOSDevTdevTBinding, VDMOSvdevTbranch, VDMOSvdevTbranch); /* Vsrc=devTemp to gnd */ + CREATE_KLU_BINDING_TABLE(VDMOSDevTtpPtr, VDMOSDevTtpBinding, VDMOSvdevTbranch, VDMOStNodePrime); + CREATE_KLU_BINDING_TABLE(VDMOSTpdevTPtr, VDMOSTpdevTBinding, VDMOStNodePrime, VDMOSvdevTbranch); } } } @@ -142,8 +142,8 @@ VDMOSbindCSCComplex (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTempdPtr, VDMOSTempdBinding, VDMOStempNode, VDMOSdNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDIOPosPrimetempPtr, VDIOPosPrimetempBinding, VDIOposPrimeNode, VDMOStempNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSDtempPtr, VDMOSDtempBinding, VDMOSdNode, VDMOStempNode); - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOStempSPtr, VDMOStempSBinding, VDMOStempNode, VDMOSsNode); - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSSTempPtr, VDMOSSTempBinding, VDMOSsNode, VDMOStempNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTempsPtr, VDMOStempSBinding, VDMOStempNode, VDMOSsNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSStempPtr, VDMOSSTempBinding, VDMOSsNode, VDMOStempNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTcasetcasePtr, VDMOSTcasetcaseBinding, VDMOStcaseNode, VDMOStcaseNode); /* Rthjc between tj and tcase*/ CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTcasetempPtr, VDMOSTcasetempBinding, VDMOStcaseNode, VDMOStempNode); @@ -151,9 +151,9 @@ VDMOSbindCSCComplex (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTptpPtr, VDMOSTptpBinding, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */ CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStcaseNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStcaseNode, VDMOStNodePrime); - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSCktTcktTPtr, VDMOSCktTcktTBinding, VDMOSvcktTbranch, VDMOSvcktTbranch); /* Vsrc=cktTemp to gnd */ - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSCktTtpPtr, VDMOSCktTtpBinding, VDMOSvcktTbranch, VDMOStNodePrime); - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTpcktTPtr, VDMOSTpcktTBinding, VDMOStNodePrime, VDMOSvcktTbranch); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSDevTdevTPtr, VDMOSDevTdevTBinding, VDMOSvdevTbranch, VDMOSvdevTbranch); /* Vsrc=devTemp to gnd */ + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSDevTtpPtr, VDMOSDevTtpBinding, VDMOSvdevTbranch, VDMOStNodePrime); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTpdevTPtr, VDMOSTpdevTBinding, VDMOStNodePrime, VDMOSvdevTbranch); } } } @@ -217,8 +217,8 @@ VDMOSbindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTempdPtr, VDMOSTempdBinding, VDMOStempNode, VDMOSdNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(VDIOPosPrimetempPtr, VDIOPosPrimetempBinding, VDIOposPrimeNode, VDMOStempNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSDtempPtr, VDMOSDtempBinding, VDMOSdNode, VDMOStempNode); - CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOStempSPtr, VDMOStempSBinding, VDMOStempNode, VDMOSsNode); - CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSSTempPtr, VDMOSSTempBinding, VDMOSsNode, VDMOStempNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTempsPtr, VDMOStempSBinding, VDMOStempNode, VDMOSsNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSStempPtr, VDMOSSTempBinding, VDMOSsNode, VDMOStempNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTcasetcasePtr, VDMOSTcasetcaseBinding, VDMOStcaseNode, VDMOStcaseNode); /* Rthjc between tj and tcase*/ CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTcasetempPtr, VDMOSTcasetempBinding, VDMOStcaseNode, VDMOStempNode); @@ -226,9 +226,9 @@ VDMOSbindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTptpPtr, VDMOSTptpBinding, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */ CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStcaseNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStcaseNode, VDMOStNodePrime); - CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSCktTcktTPtr, VDMOSCktTcktTBinding, VDMOSvcktTbranch, VDMOSvcktTbranch); /* Vsrc=cktTemp to gnd */ - CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSCktTtpPtr, VDMOSCktTtpBinding, VDMOSvcktTbranch, VDMOStNodePrime); - CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTpcktTPtr, VDMOSTpcktTBinding, VDMOStNodePrime, VDMOSvcktTbranch); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSDevTdevTPtr, VDMOSDevTdevTBinding, VDMOSvdevTbranch, VDMOSvdevTbranch); /* Vsrc=devTemp to gnd */ + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSDevTtpPtr, VDMOSDevTtpBinding, VDMOSvdevTbranch, VDMOStNodePrime); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTpdevTPtr, VDMOSTpdevTBinding, VDMOStNodePrime, VDMOSvdevTbranch); } } } diff --git a/src/spicelib/devices/vdmos/vdmosconv.c b/src/spicelib/devices/vdmos/vdmosconv.c index 6b6dfca42..49e0ccde8 100644 --- a/src/spicelib/devices/vdmos/vdmosconv.c +++ b/src/spicelib/devices/vdmos/vdmosconv.c @@ -83,8 +83,8 @@ VDMOSconvTest(GENmodel *inModel, CKTcircuit *ckt) */ vd = model->VDMOStype * ( - *(ckt->CKTrhsOld+here->VDIOposPrimeNode)- - *(ckt->CKTrhsOld + here->VDMOSdNode)); + *(ckt->CKTrhsOld+here->VDIOposPrimeNode)- + *(ckt->CKTrhsOld + here->VDMOSdNode)); delvd=vd- *(ckt->CKTstate0 + here->VDIOvoltage); diff --git a/src/spicelib/devices/vdmos/vdmosdefs.h b/src/spicelib/devices/vdmos/vdmosdefs.h index 28e42b74b..5409a520f 100644 --- a/src/spicelib/devices/vdmos/vdmosdefs.h +++ b/src/spicelib/devices/vdmos/vdmosdefs.h @@ -50,7 +50,7 @@ typedef struct sVDMOSinstance { int VDMOStNodePrime; /* number of the internal temp node between voltage source and Rthca */ int VDIOposPrimeNode; /* number of the internal node of the body diode */ - int VDMOSvcktTbranch; /* equation number of branch equation added for cktTemp source */ + int VDMOSvdevTbranch; /* equation number of branch equation added for cktTemp source */ double VDMOSm; /* parallel device multiplier */ @@ -229,8 +229,8 @@ typedef struct sVDMOSinstance { double *VDMOSTempdPtr; double *VDIOPosPrimetempPtr; double *VDMOSDtempPtr; - double *VDMOStempSPtr; - double *VDMOSSTempPtr; + double *VDMOSTempsPtr; + double *VDMOSStempPtr; double *VDMOSTcasetcasePtr; /* for Rthjc */ double *VDMOSTcasetempPtr; @@ -238,9 +238,9 @@ typedef struct sVDMOSinstance { double *VDMOSTptpPtr; /* for Rthca */ double *VDMOSTptcasePtr; double *VDMOSTcasetpPtr; - double *VDMOSCktTcktTPtr; /* for VcktTemp */ - double *VDMOSCktTtpPtr; - double *VDMOSTpcktTPtr; + double *VDMOSDevTdevTPtr; /* for VdevTemp */ + double *VDMOSDevTtpPtr; + double *VDMOSTpdevTPtr; #ifdef KLU BindElement *VDMOSDdBinding ; @@ -287,9 +287,9 @@ typedef struct sVDMOSinstance { BindElement *VDMOSTptpBinding ; BindElement *VDMOSTptcaseBinding ; BindElement *VDMOSTcasetpBinding ; - BindElement *VDMOSCktTcktTBinding ; - BindElement *VDMOSCktTtpBinding ; - BindElement *VDMOSTpcktTBinding ; + BindElement *VDMOSDevTdevTBinding ; + BindElement *VDMOSDevTtpBinding ; + BindElement *VDMOSTpdevTBinding ; #endif } VDMOSinstance ; diff --git a/src/spicelib/devices/vdmos/vdmosload.c b/src/spicelib/devices/vdmos/vdmosload.c index 5e93d9174..f5c0d4e8d 100644 --- a/src/spicelib/devices/vdmos/vdmosload.c +++ b/src/spicelib/devices/vdmos/vdmosload.c @@ -57,10 +57,10 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) int error; int selfheat; - double rd0T, rd1T, dBeta_dT, dIds_dT; + double rd0T, rd1T, dBeta_dT, dIds_dT=0.0; double Vrd=0.0, dIth_dVrd=0.0, dIrd_dT=0.0; - double drd0T_dT, drd1T_dT, drd_dT, dgdrain_dT=0.0; - double dIrd_dgdrain; + double drd0T_dT, drd1T_dT, dgdrain_dT=0.0; + double rsT, Vrs=0.0, dIth_dVrs=0.0, dIrs_dT=0.0, dgsource_dT=0.0; double deldelTemp=0.0, delTemp, delTemp1, Temp, Vds, Vgs; double ceqqth=0.0; double GmT, gTtg, gTtdp, gTtt, gTtsp, gcTt=0.0; @@ -270,7 +270,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) } if (selfheat) delTemp = DEVlimitlog(delTemp, - *(ckt->CKTstate0 + here->VDMOSdelTemp),30,&Check_th); + *(ckt->CKTstate0 + here->VDMOSdelTemp),10,&Check_th); else delTemp = 0.0; #endif /*NODELIMITING*/ @@ -278,7 +278,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) } if (selfheat) { - Temp = here->VDMOStemp + delTemp; + Temp = delTemp + CONSTCtoK; VDMOStempUpdate(model, here, Temp, ckt); } else { Temp = here->VDMOStemp; @@ -287,17 +287,24 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) /* Calculate temperature dependent values for self-heating effect */ if (selfheat) { - double TempRatio = Temp / here->VDMOStemp; - Beta = here->VDMOStTransconductance * pow(TempRatio,model->VDMOSmu); + Beta = here->VDMOStTransconductance; dBeta_dT = Beta * model->VDMOSmu / Temp; - rd0T = here->VDMOSdrainResistance * pow(TempRatio, model->VDMOStexp0); - drd0T_dT = rd0T * model->VDMOStexp0 / Temp; + rd0T = here->VDMOSdrainResistance; + if (model->VDMOStexp0Given) + drd0T_dT = rd0T * model->VDMOStexp0 / Temp; + else + drd0T_dT = model->VDMOSdrainResistance / here->VDMOSm + * (model->VDMOStrd1 + 2 * model->VDMOStrd2 * (Temp - model->VDMOStnom)); rd1T = 0.0; drd1T_dT = 0.0; if (model->VDMOSqsGiven) { - rd1T = here->VDMOSqsResistance * pow(TempRatio, model->VDMOStexp1); + rd1T = here->VDMOSqsResistance; drd1T_dT = rd1T * model->VDMOStexp1 / Temp; } + rsT = 1 / here->VDMOSsourceConductance; + double drsT_dT = model->VDMOSsourceResistance / here->VDMOSm + * (model->VDMOStrs1 + 2 * model->VDMOStrs2 * (Temp - model->VDMOStnom)); + dgsource_dT = -drsT_dT / (rsT*rsT); } else { Beta = here->VDMOStTransconductance; dBeta_dT = 0.0; @@ -307,6 +314,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) drd1T_dT = 0.0; if (model->VDMOSqsGiven) rd1T = here->VDMOSqsResistance; + dgsource_dT = 0.0; } /* @@ -359,25 +367,37 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) double betap = Beta*t0/t1; double dbetapdvgs = -Beta*theta*t0/(t1*t1); double dbetapdvds = Beta*lambda/t1; - double dbetapdT = dBeta_dT*t0/t1; double t2 = exp((vgst-shift)/slope); vgst = slope * log(1 + t2); double dvgstdvgs = t2/(t2+1); - + if (vgst <= vdss) { /* saturation region */ cdrain = betap * vgst*vgst * .5; here->VDMOSgm = betap*vgst*dvgstdvgs + 0.5*dbetapdvgs*vgst*vgst; here->VDMOSgds = .5*dbetapdvds*vgst*vgst; - dIds_dT = dbetapdT * vgst*vgst * .5; } else { /* linear region */ cdrain = betap * vdss * (vgst - .5 * vdss); here->VDMOSgm = betap*vdss*dvgstdvgs + vdss*dbetapdvgs*(vgst-.5*vdss); here->VDMOSgds = vdss*dbetapdvds*(vgst-.5*vdss) + betap*mtr*(vgst-.5*vdss) - .5*vdss*betap*mtr; - dIds_dT = dbetapdT * vdss * (vgst - .5 * vdss); + } + if (selfheat) { + double dvgst_dT = model->VDMOStype * model->VDMOStcvth; + double dvdsat_dT = 0.0; + if (vgst > 0) { + dvdsat_dT = dvgst_dT; + } + double dt1_dT = theta * dvdsat_dT; + double dbetap_dT = t0 * (t1 * dBeta_dT - Beta * dt1_dT) / (t1 * t1); + if (vgst <= vdss) { + dIds_dT = .5 * dbetap_dT * vgst*vgst + betap * vgst * dvgst_dT; + } + else { + dIds_dT = vdss * (dbetap_dT * vgst + betap * dvgst_dT) - dbetap_dT * vdss * .5 * vdss; + } } } @@ -409,7 +429,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) *(ckt->CKTrhsOld + here->VDMOSdNode) - *(ckt->CKTrhsOld + here->VDMOSsNode)); double rd = rd0T + rd1T * (vdsn / (vdsn + fabs(model->VDMOSqsVoltage))); - drd_dT = drd0T_dT + drd1T_dT * (vdsn / (vdsn + fabs(model->VDMOSqsVoltage))); + double drd_dT = drd0T_dT + drd1T_dT * (vdsn / (vdsn + fabs(model->VDMOSqsVoltage))); if (rd > 0) { here->VDMOSdrainConductance = 1 / rd + ckt->CKTgmin; dgdrain_dT = -drd_dT / (rd*rd); @@ -442,10 +462,16 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) - here->VDMOSgtempT * delTemp; Vrd = *(ckt->CKTrhsOld + here->VDMOSdNode) - *(ckt->CKTrhsOld + here->VDMOSdNodePrime); - dIth_dVrd = here->VDMOSdrainConductance * Vrd; - dIrd_dgdrain = Vrd; + dIth_dVrd = here->VDMOSdrainConductance * 2 * Vrd; + double dIrd_dgdrain = Vrd; dIrd_dT = dIrd_dgdrain * dgdrain_dT; here->VDMOScth += here->VDMOSdrainConductance * Vrd*Vrd - dIth_dVrd*Vrd - dIrd_dT*Vrd*delTemp; + + Vrs = *(ckt->CKTrhsOld + here->VDMOSsNode) - *(ckt->CKTrhsOld + here->VDMOSsNodePrime); + dIth_dVrs = here->VDMOSsourceConductance * 2 * Vrs; + double dIrs_dgsource = Vrs; + dIrs_dT = dIrs_dgsource * dgsource_dT; + here->VDMOScth += here->VDMOSsourceConductance * Vrs*Vrs - dIth_dVrs*Vrs - dIrs_dT*Vrs*delTemp; } /* @@ -466,8 +492,11 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) DevCapVDMOS(vgd, cgdmin, cgdmax, a, cgs, (ckt->CKTstate0 + here->VDMOScapgs), (ckt->CKTstate0 + here->VDMOScapgd)); - // Everything is computed for m parallel instances... so scale cthj accordingly - *(ckt->CKTstate0 + here->VDMOScapth) = here->VDMOSm * model->VDMOScthj; /* always constant */ + /* Everything is computed for m parallel instances... so scale cthj accordingly + * Also, take into account Meyer numerical integration style and + * halve the value of cthj that gets stored in the state. + */ + *(ckt->CKTstate0 + here->VDMOScapth) = here->VDMOSm * model->VDMOScthj / 2; /* always constant */ vgs1 = *(ckt->CKTstate1 + here->VDMOSvgs); vgd1 = vgs1 - *(ckt->CKTstate1 + here->VDMOSvds); @@ -550,8 +579,6 @@ bypass: { error = NIintegrate(ckt, &gcTt, &ceqqth, capth, here->VDMOSqth); if (error) return(error); - ceqqth = ceqqth - gcTt*delTemp + ckt->CKTag[0] * - *(ckt->CKTstate0 + here->VDMOSqth); } } @@ -598,15 +625,18 @@ bypass: *(ckt->CKTrhs + here->VDMOSsNodePrime) += cdreq + model->VDMOStype * ceqgs; if (selfheat) { *(ckt->CKTrhs + here->VDMOSdNode) += dIrd_dT * delTemp; + *(ckt->CKTrhs + here->VDMOSsNode) += dIrs_dT * delTemp; *(ckt->CKTrhs + here->VDMOSdNodePrime) += GmT * delTemp - dIrd_dT * delTemp; - *(ckt->CKTrhs + here->VDMOSsNodePrime) += -GmT * delTemp; + *(ckt->CKTrhs + here->VDMOSsNodePrime) += -GmT * delTemp - dIrs_dT * delTemp; *(ckt->CKTrhs + here->VDMOStempNode) += here->VDMOScth - ceqqth; - double vCktTemp = (ckt->CKTtemp-CONSTCtoK); /* ckt temperature */ + double vDevTemp = (ckt->CKTtemp-CONSTCtoK); /* ckt temperature */ + if (here->VDMOStempGiven) + vDevTemp = (here->VDMOStemp-CONSTCtoK); /* device temperature */ if (ckt->CKTmode & MODETRANOP) - vCktTemp *= ckt->CKTsrcFact; - *(ckt->CKTrhs + here->VDMOSvcktTbranch)+= vCktTemp; + vDevTemp *= ckt->CKTsrcFact; + *(ckt->CKTrhs + here->VDMOSvdevTbranch)+= vDevTemp; } - + /* * load y matrix */ @@ -641,26 +671,28 @@ bypass: if (selfheat) { - // Everything is computed for m parallel instances... so scale gthjc and gthja accordingly + /* Everything is computed for m parallel instances... so scale gthjc and gthja accordingly + */ double gthjc = here->VDMOSm / model->VDMOSrthjc; double gthca = here->VDMOSm / model->VDMOSrthca; (*(here->VDMOSDtempPtr) += dIrd_dT); (*(here->VDMOSDPtempPtr) += GmT - dIrd_dT); - (*(here->VDMOSSPtempPtr) += -GmT); - (*(here->VDMOSGPtempPtr) += 0.0); - (*(here->VDMOSTemptempPtr) += -gTtt - dIrd_dT*Vrd + gthjc + gcTt); + (*(here->VDMOSStempPtr) += dIrs_dT); + (*(here->VDMOSSPtempPtr) += -GmT - dIrs_dT); + (*(here->VDMOSTemptempPtr) += -gTtt - dIrd_dT*Vrd - dIrs_dT*Vrs + gthjc + gcTt); (*(here->VDMOSTempgpPtr) += -gTtg); (*(here->VDMOSTempdPtr) += -dIth_dVrd); + (*(here->VDMOSTempsPtr) += -dIth_dVrs); (*(here->VDMOSTempdpPtr) += -gTtdp + dIth_dVrd); - (*(here->VDMOSTempspPtr) += -gTtsp); + (*(here->VDMOSTempspPtr) += -gTtsp + dIth_dVrs); (*(here->VDMOSTemptcasePtr) += -gthjc); (*(here->VDMOSTcasetempPtr) += -gthjc); (*(here->VDMOSTcasetcasePtr) += gthjc + gthca); (*(here->VDMOSTptpPtr) += gthca); (*(here->VDMOSTptcasePtr) += -gthca); (*(here->VDMOSTcasetpPtr) += -gthca); - (*(here->VDMOSCktTtpPtr) += 1.0); - (*(here->VDMOSTpcktTPtr) += 1.0); + (*(here->VDMOSDevTtpPtr) += 1.0); + (*(here->VDMOSTpdevTPtr) += 1.0); } /* body diode model @@ -672,18 +704,18 @@ bypass: double vtebrk, vbrknp; double cdb, cdeq; double capd; - double gd, gdb, gspr; + double gd, gdb, gbpr; double delvd; /* change in diode voltage temporary */ double evrev; double Ith=0.0, dIth_dT=0.0; double dIdio_dT=0.0, dIth_dVdio=0.0; - double vrs=0.0, dIrs_dT=0.0, dIth_dVrs=0.0; + double vrb=0.0, dIrb_dT=0.0, dIth_dVrb=0.0; #ifndef NOBYPASS double tol; /* temporary for tolerance calculations */ #endif - gspr = here->VDIOtConductance; + gbpr = here->VDIOtConductance; vt = CONSTKoverQ * Temp; vte = model->VDIOn * vt; @@ -878,18 +910,18 @@ bypass: load: #endif if (selfheat) { - double dIrs_dgspr, dIth_dIrs; - vrs = *(ckt->CKTrhsOld + here->VDMOSsNode) - *(ckt->CKTrhsOld + here->VDIOposPrimeNode); + double dIrb_dgbpr, dIth_dIrb; + vrb = *(ckt->CKTrhsOld + here->VDMOSsNode) - *(ckt->CKTrhsOld + here->VDIOposPrimeNode); - Ith = vd*cd + vrs*vrs*gspr; + Ith = vd*cd + vrb*vrb*gbpr; dIth_dVdio = cd + vd*gd; - dIth_dVrs = vrs*gspr; + dIth_dVrb = vrb*gbpr; - dIrs_dgspr = vrs; - dIrs_dT = dIrs_dgspr * here->VDIOtConductance_dT; - dIth_dIrs = vrs; - dIth_dT = dIth_dIrs*dIrs_dT + dIdio_dT*vd; + dIrb_dgbpr = vrb; + dIrb_dT = dIrb_dgbpr * here->VDIOtConductance_dT; + dIth_dIrb = vrb; + dIth_dT = dIth_dIrb*dIrb_dT + dIdio_dT*vd; } /* * load current vector @@ -903,28 +935,28 @@ load: *(ckt->CKTrhs + here->VDIOposPrimeNode) += cdeq; } if (selfheat) { - *(ckt->CKTrhs + here->VDIOposPrimeNode) += dIdio_dT*delTemp - dIrs_dT*delTemp; + *(ckt->CKTrhs + here->VDIOposPrimeNode) += dIdio_dT*delTemp - dIrb_dT*delTemp; *(ckt->CKTrhs + here->VDMOSdNode) += -dIdio_dT*delTemp; - *(ckt->CKTrhs + here->VDMOSsNode) += dIrs_dT*delTemp; - *(ckt->CKTrhs + here->VDMOStempNode) += Ith - model->VDMOStype*dIth_dVdio*vd - dIth_dVrs*vrs - dIth_dT*delTemp; + *(ckt->CKTrhs + here->VDMOSsNode) += dIrb_dT*delTemp; + *(ckt->CKTrhs + here->VDMOStempNode) += Ith - model->VDMOStype*dIth_dVdio*vd - dIth_dVrb*vrb - dIth_dT*delTemp; } /* * load matrix */ - *(here->VDMOSSsPtr) += gspr; + *(here->VDMOSSsPtr) += gbpr; *(here->VDMOSDdPtr) += gd; - *(here->VDIORPrpPtr) += (gd + gspr); - *(here->VDIOSrpPtr) -= gspr; + *(here->VDIORPrpPtr) += (gd + gbpr); + *(here->VDIOSrpPtr) -= gbpr; *(here->VDIODrpPtr) -= gd; - *(here->VDIORPsPtr) -= gspr; + *(here->VDIORPsPtr) -= gbpr; *(here->VDIORPdPtr) -= gd; if (selfheat) { - (*(here->VDMOStempSPtr) += -dIth_dVrs); - (*(here->VDIOTempposPrimePtr) += -dIth_dVdio + dIth_dVrs); + (*(here->VDMOSTempsPtr) += -dIth_dVrb); + (*(here->VDIOTempposPrimePtr) += -dIth_dVdio + dIth_dVrb); (*(here->VDMOSTempdPtr) += dIth_dVdio); (*(here->VDMOSTemptempPtr) += -dIth_dT); - (*(here->VDIOPosPrimetempPtr) += dIdio_dT - dIrs_dT); - (*(here->VDMOSSTempPtr) += dIrs_dT); + (*(here->VDIOPosPrimetempPtr) += dIdio_dT - dIrb_dT); + (*(here->VDMOSStempPtr) += dIrb_dT); (*(here->VDMOSDtempPtr) += -dIdio_dT); } } diff --git a/src/spicelib/devices/vdmos/vdmosset.c b/src/spicelib/devices/vdmos/vdmosset.c index 58e6cd300..dfc6a2da3 100644 --- a/src/spicelib/devices/vdmos/vdmosset.c +++ b/src/spicelib/devices/vdmos/vdmosset.c @@ -416,10 +416,10 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, if (error) return(error); here->VDMOStcaseNode = tmp->number; } - if(here->VDMOSvcktTbranch == 0) { - error = CKTmkCur(ckt,&tmp,here->VDMOSname,"VcktTemp"); + if(here->VDMOSvdevTbranch == 0) { + error = CKTmkCur(ckt,&tmp,here->VDMOSname,"VdevTemp"); if(error) return(error); - here->VDMOSvcktTbranch = tmp->number; + here->VDMOSvdevTbranch = tmp->number; } if (here->VDMOStNodePrime == 0) { error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "cktTemp"); @@ -479,8 +479,8 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ TSTALLOC(VDMOSTempdPtr, VDMOStempNode, VDMOSdNode); TSTALLOC(VDIOPosPrimetempPtr, VDIOposPrimeNode, VDMOStempNode); TSTALLOC(VDMOSDtempPtr, VDMOSdNode, VDMOStempNode); - TSTALLOC(VDMOStempSPtr, VDMOStempNode, VDMOSsNode); - TSTALLOC(VDMOSSTempPtr, VDMOSsNode, VDMOStempNode); + TSTALLOC(VDMOSTempsPtr, VDMOStempNode, VDMOSsNode); + TSTALLOC(VDMOSStempPtr, VDMOSsNode, VDMOStempNode); TSTALLOC(VDMOSTcasetcasePtr, VDMOStcaseNode, VDMOStcaseNode); /* Rthjc between tj and tcase*/ TSTALLOC(VDMOSTcasetempPtr, VDMOStcaseNode, VDMOStempNode); @@ -488,9 +488,9 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ TSTALLOC(VDMOSTptpPtr, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */ TSTALLOC(VDMOSTptcasePtr, VDMOStNodePrime, VDMOStcaseNode); TSTALLOC(VDMOSTcasetpPtr, VDMOStcaseNode, VDMOStNodePrime); - TSTALLOC(VDMOSCktTcktTPtr, VDMOSvcktTbranch, VDMOSvcktTbranch); /* Vsrc=cktTemp to gnd */ - TSTALLOC(VDMOSCktTtpPtr, VDMOSvcktTbranch, VDMOStNodePrime); - TSTALLOC(VDMOSTpcktTPtr, VDMOStNodePrime, VDMOSvcktTbranch); + TSTALLOC(VDMOSDevTdevTPtr, VDMOSvdevTbranch, VDMOSvdevTbranch); /* Vsrc=cktTemp to gnd */ + TSTALLOC(VDMOSDevTtpPtr, VDMOSvdevTbranch, VDMOStNodePrime); + TSTALLOC(VDMOSTpdevTPtr, VDMOStNodePrime, VDMOSvdevTbranch); } } } @@ -533,9 +533,9 @@ VDMOSunsetup(GENmodel *inModel, CKTcircuit *ckt) if (here->VDMOStNodePrime > 0) CKTdltNNum(ckt, here->VDMOStNodePrime); here->VDMOStNodePrime = 0; - if (here->VDMOSvcktTbranch > 0) - CKTdltNNum(ckt, here->VDMOSvcktTbranch); - here->VDMOSvcktTbranch = 0; + if (here->VDMOSvdevTbranch > 0) + CKTdltNNum(ckt, here->VDMOSvdevTbranch); + here->VDMOSvdevTbranch = 0; } } From ee8bf7a948a85aa62230aa1867d75dad61e7a066 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 23 Nov 2025 10:37:47 +0100 Subject: [PATCH 078/161] Add a comment --- src/frontend/inp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/frontend/inp.c b/src/frontend/inp.c index 97bcc16ad..c689da971 100644 --- a/src/frontend/inp.c +++ b/src/frontend/inp.c @@ -845,6 +845,7 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) #ifdef OSDI inputdir = dir_name; #endif + /* process each pre_xxx command */ cp_evloop(wl->wl_word); } From d7f5169b0dab1754ec949541d0b777372c4d0665 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 24 Nov 2025 14:02:42 +0100 Subject: [PATCH 079/161] Re-formatting --- src/spicelib/parser/inppas2.c | 330 +++++++++++++++++----------------- 1 file changed, 165 insertions(+), 165 deletions(-) diff --git a/src/spicelib/parser/inppas2.c b/src/spicelib/parser/inppas2.c index cd446f3c2..f569fe056 100644 --- a/src/spicelib/parser/inppas2.c +++ b/src/spicelib/parser/inppas2.c @@ -34,7 +34,7 @@ void INPpas2(CKTcircuit *ckt, struct card *data, INPtables * tab, TSKtask *task) char *groundname = "0"; char *gname; CKTnode *gnode; - int error; /* used by the macros defined above */ + int error; /* used by the macros defined above */ #ifdef HAS_PROGREP int linecount = 0, actcount = 0; #endif @@ -45,28 +45,28 @@ void INPpas2(CKTcircuit *ckt, struct card *data, INPtables * tab, TSKtask *task) #endif error = INPgetTok(&groundname, &gname, 1); - if (error) - data->error = - INPerrCat(data->error, - INPmkTemp - ("can't read internal ground node name!\n")); - + if (error) { + data->error = + INPerrCat(data->error, + INPmkTemp + ("can't read internal ground node name!\n")); + } error = INPgndInsert(ckt, &gname, tab, &gnode); - if (error && error != E_EXISTS) - data->error = - INPerrCat(data->error, - INPmkTemp - ("can't insert internal ground node in symbol table!\n")); - -#ifdef TRACE + if (error && error != E_EXISTS) { + data->error = + INPerrCat(data->error, + INPmkTemp + ("can't insert internal ground node in symbol table!\n")); + } + +#ifdef TRACE printf("Examining this deck:\n"); for (current = data; current != NULL; current = current->nextcard) { - printf("%s\n", current->line); + printf("%s\n", current->line); } printf("\n"); #endif - #ifdef HAS_PROGREP for (current = data; current != NULL; current = current->nextcard) linecount++; @@ -75,195 +75,195 @@ void INPpas2(CKTcircuit *ckt, struct card *data, INPtables * tab, TSKtask *task) for (current = data; current != NULL; current = current->nextcard) { #ifdef TRACE - /* SDB debug statement */ - printf("In INPpas2, examining card %s . . .\n", current->line); + /* SDB debug statement */ + printf("In INPpas2, examining card %s . . .\n", current->line); #endif #ifdef HAS_PROGREP - if (linecount > 0) { - SetAnalyse( "Parse", (int) (1000.*actcount/linecount)); - actcount++; - } + if (linecount > 0) { + SetAnalyse( "Parse", (int) (1000.*actcount/linecount)); + actcount++; + } #endif - Current_parse_line = current->linenum_orig; - Sourcefile = current->linesource; + Current_parse_line = current->linenum_orig; + Sourcefile = current->linesource; - c = *(current->line); - if(islower_c(c)) - c = toupper_c(c); + c = *(current->line); + if(islower_c(c)) + c = toupper_c(c); - switch (c) { + switch (c) { - case ' ': - /* blank line (space leading) */ - case '\t': - /* blank line (tab leading) */ - break; + case ' ': + /* blank line (space leading) */ + case '\t': + /* blank line (tab leading) */ + break; #ifdef XSPICE - /* gtri - add - wbk - 10/23/90 - add case for 'A' devices */ + /* gtri - add - wbk - 10/23/90 - add case for 'A' devices */ - case 'A': /* Aname */ - MIF_INP2A(ckt, tab, current); - ckt->CKTadevFlag = 1; /* an 'A' device is requested */ - break; + case 'A': /* Aname */ + MIF_INP2A(ckt, tab, current); + ckt->CKTadevFlag = 1; /* an 'A' device is requested */ + break; - /* gtri - end - wbk - 10/23/90 */ + /* gtri - end - wbk - 10/23/90 */ #endif - case 'R': - /* Rname [][][w=][l=] */ - INP2R(ckt, tab, current); - break; + case 'R': + /* Rname [][][w=][l=] */ + INP2R(ckt, tab, current); + break; - case 'C': - /* Cname [IC=] */ - INP2C(ckt, tab, current); - break; + case 'C': + /* Cname [IC=] */ + INP2C(ckt, tab, current); + break; - case 'L': - /* Lname [IC=] */ - INP2L(ckt, tab, current); - break; + case 'L': + /* Lname [IC=] */ + INP2L(ckt, tab, current); + break; - case 'G': - /* Gname */ - INP2G(ckt, tab, current); - break; + case 'G': + /* Gname */ + INP2G(ckt, tab, current); + break; - case 'E': - /* Ename */ - INP2E(ckt, tab, current); - break; + case 'E': + /* Ename */ + INP2E(ckt, tab, current); + break; - case 'F': - /* Fname */ - INP2F(ckt, tab, current); - break; + case 'F': + /* Fname */ + INP2F(ckt, tab, current); + break; - case 'H': - /* Hname */ - INP2H(ckt, tab, current); - break; + case 'H': + /* Hname */ + INP2H(ckt, tab, current); + break; - case 'D': - /* Dname [] [OFF] [IC=] */ - INP2D(ckt, tab, current); - break; + case 'D': + /* Dname [] [OFF] [IC=] */ + INP2D(ckt, tab, current); + break; - case 'J': - /* Jname [] [OFF] + case 'J': + /* Jname [] [OFF] + [IC=,] */ + INP2J(ckt, tab, current); + break; + + case 'Z': + /* Zname [] [OFF] [IC=,] */ - INP2J(ckt, tab, current); - break; + INP2Z(ckt, tab, current); + break; - case 'Z': - /* Zname [] [OFF] - [IC=,] */ - INP2Z(ckt, tab, current); - break; - - case 'M': - /* Mname [L=] - [W=] [AD=] [AS=] [PD=] - [PS=] [NRD=] [NRS=] [OFF] - [IC=,,] */ - INP2M(ckt, tab, current); - break; + case 'M': + /* Mname [L=] + [W=] [AD=] [AS=] [PD=] + [PS=] [NRD=] [NRS=] [OFF] + [IC=,,] */ + INP2M(ckt, tab, current); + break; #ifdef OSDI - case 'N': - /* Nname [...] [] */ - INP2N(ckt, tab, current); - break; + case 'N': + /* Nname [...] [] */ + INP2N(ckt, tab, current); + break; #endif - case 'O': - /* Oname - [IC=,,,] */ - INP2O(ckt, tab, current); - break; + case 'O': + /* Oname + [IC=,,,] */ + INP2O(ckt, tab, current); + break; - case 'V': - /* Vname [ [DC] ] [AC [ [ ] ] ] - [] */ - INP2V(ckt, tab, current); - break; + case 'V': + /* Vname [ [DC] ] [AC [ [ ] ] ] + [] */ + INP2V(ckt, tab, current); + break; - case 'I': - /* Iname [ [DC] ] [AC [ [ ] ] ] - [] */ - INP2I(ckt, tab, current); - break; + case 'I': + /* Iname [ [DC] ] [AC [ [ ] ] ] + [] */ + INP2I(ckt, tab, current); + break; - case 'Q': - /* Qname [] [] [OFF] - [IC=,] */ - INP2Q(ckt, tab, current, gnode); - break; + case 'Q': + /* Qname [] [] [OFF] + [IC=,] */ + INP2Q(ckt, tab, current, gnode); + break; - case 'T': - /* Tname [TD=] - [F= [NL=]][IC=,,,] */ - INP2T(ckt, tab, current); - break; + case 'T': + /* Tname [TD=] + [F= [NL=]][IC=,,,] */ + INP2T(ckt, tab, current); + break; - case 'S': - /* Sname [] [IC] */ - INP2S(ckt, tab, current); - break; + case 'S': + /* Sname [] [IC] */ + INP2S(ckt, tab, current); + break; - case 'W': - /* Wname [] [IC] */ - /* CURRENT CONTROLLED SWITCH */ - INP2W(ckt, tab, current); - break; + case 'W': + /* Wname [] [IC] */ + /* CURRENT CONTROLLED SWITCH */ + INP2W(ckt, tab, current); + break; - case 'U': - /* Uname [l=] [n=] */ - INP2U(ckt, tab, current); - break; + case 'U': + /* Uname [l=] [n=] */ + INP2U(ckt, tab, current); + break; - /* Kspice addition - saj */ - case 'P': - /* Pname ... ... [] */ - /* R= L= G= C= len= */ - INP2P(ckt, tab, current); - break; - case 'Y': - /* Yname R= L= G= C= len= */ - INP2Y(ckt, tab, current); - break; - /* end Kspice */ + /* Kspice addition - saj */ + case 'P': + /* Pname ... ... [] */ + /* R= L= G= C= len= */ + INP2P(ckt, tab, current); + break; + case 'Y': + /* Yname R= L= G= C= len= */ + INP2Y(ckt, tab, current); + break; + /* end Kspice */ - case 'K': - /* Kname Lname Lname */ - INP2K(ckt, tab, current); - break; + case 'K': + /* Kname Lname Lname */ + INP2K(ckt, tab, current); + break; - case '*': case '$': - /* * - a comment - ignore */ - break; + case '*': case '$': + /* * - a comment - ignore */ + break; - case 'B': - /* Bname [V=expr] [I=expr] */ - /* Arbitrary source. */ - INP2B(ckt, tab, current); - break; + case 'B': + /* Bname [V=expr] [I=expr] */ + /* Arbitrary source. */ + INP2B(ckt, tab, current); + break; - case '.': /* . Many possibilities */ - if (INP2dot(ckt,tab,current,task,gnode)) - return; - break; + case '.': /* . Many possibilities */ + if (INP2dot(ckt,tab,current,task,gnode)) + return; + break; - case '\0': - break; + case '\0': + break; - default: - /* the un-implemented device */ - LITERR(" unknown device type - error \n"); - break; - } - } + default: + /* the un-implemented device */ + LITERR(" unknown device type - error \n"); + break; + } + } return; } From 58d7ad791ef4a36e05932d805eb71d10942f83ee Mon Sep 17 00:00:00 2001 From: dwarning Date: Thu, 27 Nov 2025 16:21:31 +0100 Subject: [PATCH 080/161] Add optional switch for separate bottom and sidewall diode model - configuration is dependent from model parameter RSW Further sidewall knee current parameter IKP is implemented. --- src/spicelib/devices/dio/dio.c | 2 + src/spicelib/devices/dio/dioacld.c | 32 ++- src/spicelib/devices/dio/diobindCSC.c | 27 +++ src/spicelib/devices/dio/dioconv.c | 27 ++- src/spicelib/devices/dio/diodefs.h | 61 ++++- src/spicelib/devices/dio/dioload.c | 337 +++++++++++++++++++------- src/spicelib/devices/dio/diomask.c | 6 + src/spicelib/devices/dio/diompar.c | 8 + src/spicelib/devices/dio/dionoise.c | 33 ++- src/spicelib/devices/dio/diopzld.c | 18 +- src/spicelib/devices/dio/diosetup.c | 86 ++++++- src/spicelib/devices/dio/diotemp.c | 20 +- src/spicelib/devices/dio/diotrunc.c | 1 + 13 files changed, 544 insertions(+), 114 deletions(-) diff --git a/src/spicelib/devices/dio/dio.c b/src/spicelib/devices/dio/dio.c index 3c4ff131c..8814c5a1a 100644 --- a/src/spicelib/devices/dio/dio.c +++ b/src/spicelib/devices/dio/dio.c @@ -55,6 +55,7 @@ IFparm DIOmPTable[] = { /* model parameters */ IOPU( "tnom",DIO_MOD_TNOM,IF_REAL, "Parameter measurement temperature"), IOPUR("tref",DIO_MOD_TNOM,IF_REAL, "Parameter measurement temperature"), IOP( "rs", DIO_MOD_RS, IF_REAL, "Ohmic resistance"), + IOP( "rsw", DIO_MOD_RSW, IF_REAL, "Ohmic resistance sidewall"), IOP( "trs", DIO_MOD_TRS, IF_REAL, "Ohmic resistance 1st order temp. coeff."), IOPR( "trs1", DIO_MOD_TRS, IF_REAL, "Ohmic resistance 1st order temp. coeff."), IOP( "trs2", DIO_MOD_TRS2, IF_REAL, "Ohmic resistance 2nd order temp. coeff."), @@ -80,6 +81,7 @@ IFparm DIOmPTable[] = { /* model parameters */ IOP( "ikf", DIO_MOD_IKF, IF_REAL, "Forward Knee current"), IOPR( "ik", DIO_MOD_IKF, IF_REAL, "Forward Knee current"), IOP( "ikr", DIO_MOD_IKR, IF_REAL, "Reverse Knee current"), + IOP( "ikp", DIO_MOD_IKP, IF_REAL, "Forward Sw Knee current"), IOP( "nbv", DIO_MOD_NBV, IF_REAL, "Breakdown Emission Coefficient"), IOPR( "nz", DIO_MOD_NBV, IF_REAL, "Breakdown Emission Coefficient"), IOP("area", DIO_MOD_AREA, IF_REAL, "Area factor"), diff --git a/src/spicelib/devices/dio/dioacld.c b/src/spicelib/devices/dio/dioacld.c index d7e68c41b..62ad65efd 100644 --- a/src/spicelib/devices/dio/dioacld.c +++ b/src/spicelib/devices/dio/dioacld.c @@ -17,7 +17,7 @@ int DIOacLoad(GENmodel *inModel, CKTcircuit *ckt) { DIOmodel *model = (DIOmodel*)inModel; - double gspr; + double gspr, gsprsw; double geq; double xceq; DIOinstance *here; @@ -42,6 +42,23 @@ DIOacLoad(GENmodel *inModel, CKTcircuit *ckt) *(here->DIOposPrimePosPtr ) -= gspr; *(here->DIOposPrimeNegPtr ) -= geq; *(here->DIOposPrimeNegPtr +1 ) -= xceq; + if (model->DIOresistSWGiven) { + gsprsw=here->DIOtConductanceSW; + geq= *(ckt->CKTstate0 + here->DIOconductSW); + xceq= *(ckt->CKTstate0 + here->DIOcapCurrentSW) * ckt->CKTomega; + *(here->DIOposPosPtr) += gsprsw; + *(here->DIOnegNegPtr) += geq; + *(here->DIOnegNegPtr + 1) += xceq; + *(here->DIOposSwPrimePosSwPrimePtr) += (geq + gsprsw); + *(here->DIOposSwPrimePosSwPrimePtr + 1) += xceq; + *(here->DIOposPosSwPrimePtr) -= gsprsw; + *(here->DIOnegPosSwPrimePtr) -= geq; + *(here->DIOnegPosSwPrimePtr + 1) -= xceq; + *(here->DIOposSwPrimePosPtr) -= gsprsw; + *(here->DIOposSwPrimeNegPtr) -= geq; + *(here->DIOposSwPrimeNegPtr + 1) -= xceq; + } + int selfheat = ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given)); if (selfheat) { double dIth_dVrs = here->DIOdIth_dVrs; @@ -60,6 +77,19 @@ DIOacLoad(GENmodel *inModel, CKTcircuit *ckt) double xgcTt= *(ckt->CKTstate0 + here->DIOcqth) * ckt->CKTomega; (*(here->DIOtempTempPtr + 1) += xgcTt); + + if (model->DIOresistSWGiven) { + double dIth_dVrssw = here->DIOdIth_dVrs; + double dIth_dVdioSw = here->DIOdIth_dVdio; + double dIrssw_dT = here->DIOdIrs_dT; + double dIdioSw_dT = *(ckt->CKTstate0 + here->DIOdIdio_dT); + (*(here->DIOtempPosPtr) += -dIth_dVrssw); + (*(here->DIOtempPosSwPrimePtr) += -dIth_dVdioSw + dIth_dVrssw); + (*(here->DIOtempNegPtr) += dIth_dVdioSw); + (*(here->DIOposTempPtr) += dIrssw_dT); + (*(here->DIOposSwPrimeTempPtr) += dIdioSw_dT - dIrssw_dT); + (*(here->DIOnegTempPtr) += -dIdioSw_dT); + } } } } diff --git a/src/spicelib/devices/dio/diobindCSC.c b/src/spicelib/devices/dio/diobindCSC.c index c33557307..a5df3db3d 100644 --- a/src/spicelib/devices/dio/diobindCSC.c +++ b/src/spicelib/devices/dio/diobindCSC.c @@ -32,6 +32,12 @@ DIObindCSC (GENmodel *inModel, CKTcircuit *ckt) CREATE_KLU_BINDING_TABLE(DIOposPosPtr, DIOposPosBinding, DIOposNode, DIOposNode); CREATE_KLU_BINDING_TABLE(DIOnegNegPtr, DIOnegNegBinding, DIOnegNode, DIOnegNode); CREATE_KLU_BINDING_TABLE(DIOposPrimePosPrimePtr, DIOposPrimePosPrimeBinding, DIOposPrimeNode, DIOposPrimeNode); + /* separate sidewall */ + CREATE_KLU_BINDING_TABLE(DIOposPosSwPrimePtr,DIOposPosSwPrimeBinding,DIOposNode,DIOposSwPrimeNode); + CREATE_KLU_BINDING_TABLE(DIOnegPosSwPrimePtr,DIOnegPosSwPrimeBinding,DIOnegNode,DIOposSwPrimeNode); + CREATE_KLU_BINDING_TABLE(DIOposSwPrimePosPtr,DIOposSwPrimePosBinding,DIOposSwPrimeNode,DIOposNode); + CREATE_KLU_BINDING_TABLE(DIOposSwPrimeNegPtr,DIOposSwPrimeNegBinding,DIOposSwPrimeNode,DIOnegNode); + CREATE_KLU_BINDING_TABLE(DIOposSwPrimePosSwPrimePtr,DIOposSwPrimePosSwPrimeBinding,DIOposSwPrimeNode,DIOposSwPrimeNode); if ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given)) { CREATE_KLU_BINDING_TABLE(DIOtempPosPtr, DIOtempPosBinding, DIOtempNode, DIOposNode); CREATE_KLU_BINDING_TABLE(DIOtempPosPrimePtr, DIOtempPosPrimeBinding, DIOtempNode, DIOposPrimeNode); @@ -40,6 +46,9 @@ DIObindCSC (GENmodel *inModel, CKTcircuit *ckt) CREATE_KLU_BINDING_TABLE(DIOposTempPtr, DIOposTempBinding, DIOposNode, DIOtempNode); CREATE_KLU_BINDING_TABLE(DIOposPrimeTempPtr, DIOposPrimeTempBinding, DIOposPrimeNode, DIOtempNode); CREATE_KLU_BINDING_TABLE(DIOnegTempPtr, DIOnegTempBinding, DIOnegNode, DIOtempNode); + /* separate sidewall */ + CREATE_KLU_BINDING_TABLE(DIOtempPosSwPrimePtr, DIOtempPosSwPrimeBinding, DIOtempNode, DIOposSwPrimeNode); + CREATE_KLU_BINDING_TABLE(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode); } } } @@ -68,6 +77,12 @@ DIObindCSCComplex (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposPosPtr, DIOposPosBinding, DIOposNode, DIOposNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOnegNegPtr, DIOnegNegBinding, DIOnegNode, DIOnegNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposPrimePosPrimePtr, DIOposPrimePosPrimeBinding, DIOposPrimeNode, DIOposPrimeNode); + /* separate sidewall */ + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposPosSwPrimePtr,DIOposPosSwPrimeBinding,DIOposNode,DIOposSwPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOnegPosSwPrimePtr,DIOnegPosSwPrimeBinding,DIOnegNode,DIOposSwPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimePosPtr,DIOposSwPrimePosBinding,DIOposSwPrimeNode,DIOposNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimeNegPtr,DIOposSwPrimeNegBinding,DIOposSwPrimeNode,DIOnegNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimePosSwPrimePtr,DIOposSwPrimePosSwPrimeBinding,DIOposSwPrimeNode,DIOposSwPrimeNode); if ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given)) { CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOtempPosPtr, DIOtempPosBinding, DIOtempNode, DIOposNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOtempPosPrimePtr, DIOtempPosPrimeBinding, DIOtempNode, DIOposPrimeNode); @@ -76,6 +91,9 @@ DIObindCSCComplex (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposTempPtr, DIOposTempBinding, DIOposNode, DIOtempNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposPrimeTempPtr, DIOposPrimeTempBinding, DIOposPrimeNode, DIOtempNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOnegTempPtr, DIOnegTempBinding, DIOnegNode, DIOtempNode); + /* separate sidewall */ + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOtempPosSwPrimePtr, DIOtempPosSwPrimeBinding, DIOtempNode, DIOposSwPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode); } } } @@ -104,6 +122,12 @@ DIObindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposPosPtr, DIOposPosBinding, DIOposNode, DIOposNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOnegNegPtr, DIOnegNegBinding, DIOnegNode, DIOnegNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposPrimePosPrimePtr, DIOposPrimePosPrimeBinding, DIOposPrimeNode, DIOposPrimeNode); + /* separate sidewall */ + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposPosSwPrimePtr,DIOposPosSwPrimeBinding,DIOposNode,DIOposSwPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOnegPosSwPrimePtr,DIOnegPosSwPrimeBinding,DIOnegNode,DIOposSwPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimePosPtr,DIOposSwPrimePosBinding,DIOposSwPrimeNode,DIOposNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimeNegPtr,DIOposSwPrimeNegBinding,DIOposSwPrimeNode,DIOnegNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimePosSwPrimePtr,DIOposSwPrimePosSwPrimeBinding,DIOposSwPrimeNode,DIOposSwPrimeNode); if ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given)) { CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOtempPosPtr, DIOtempPosBinding, DIOtempNode, DIOposNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOtempPosPrimePtr, DIOtempPosPrimeBinding, DIOtempNode, DIOposPrimeNode); @@ -112,6 +136,9 @@ DIObindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposTempPtr, DIOposTempBinding, DIOposNode, DIOtempNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposPrimeTempPtr, DIOposPrimeTempBinding, DIOposPrimeNode, DIOtempNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOnegTempPtr, DIOnegTempBinding, DIOnegNode, DIOtempNode); + /* separate sidewall */ + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOtempPosSwPrimePtr, DIOtempPosSwPrimeBinding, DIOtempNode, DIOposSwPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode); } } } diff --git a/src/spicelib/devices/dio/dioconv.c b/src/spicelib/devices/dio/dioconv.c index ed1b0cea6..7e749576e 100644 --- a/src/spicelib/devices/dio/dioconv.c +++ b/src/spicelib/devices/dio/dioconv.c @@ -19,7 +19,7 @@ DIOconvTest(GENmodel *inModel, CKTcircuit *ckt) { DIOmodel *model = (DIOmodel*)inModel; DIOinstance *here; - double delvd,vd,cdhat,cd; + double delvd,vd,cdhat,cd,vdsw,cdhatsw=0.0,cdsw=0.0; double tol; double delTemp, deldelTemp; /* loop through all the diode models */ @@ -46,11 +46,23 @@ DIOconvTest(GENmodel *inModel, CKTcircuit *ckt) deldelTemp = delTemp - *(ckt->CKTstate0 + here->DIOdeltemp); cdhat= *(ckt->CKTstate0 + here->DIOcurrent) + - *(ckt->CKTstate0 + here->DIOconduct) * delvd + - *(ckt->CKTstate0 + here->DIOdIdio_dT) * deldelTemp; + *(ckt->CKTstate0 + here->DIOconduct) * delvd + + *(ckt->CKTstate0 + here->DIOdIdio_dT) * deldelTemp; cd= *(ckt->CKTstate0 + here->DIOcurrent); + if (model->DIOresistSWGiven) { + vdsw = *(ckt->CKTrhsOld+here->DIOposSwPrimeNode)- + *(ckt->CKTrhsOld + here->DIOnegNode); + + delvd=vdsw- *(ckt->CKTstate0 + here->DIOvoltageSW); + + cdhatsw= *(ckt->CKTstate0 + here->DIOcurrentSW) + + *(ckt->CKTstate0 + here->DIOconductSW) * delvd + + *(ckt->CKTstate0 + here->DIOdIdioSW_dT) * deldelTemp; + + cdsw= *(ckt->CKTstate0 + here->DIOcurrentSW); + } /* * check convergence */ @@ -61,6 +73,15 @@ DIOconvTest(GENmodel *inModel, CKTcircuit *ckt) ckt->CKTtroubleElt = (GENinstance *) here; return(OK); /* don't need to check any more device */ } + if (model->DIOresistSWGiven) { + tol=ckt->CKTreltol* + MAX(fabs(cdhatsw),fabs(cdsw))+ckt->CKTabstol; + if (fabs(cdhatsw-cdsw) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + return(OK); /* no reason to continue - we've failed... */ + } + } } } return(OK); diff --git a/src/spicelib/devices/dio/diodefs.h b/src/spicelib/devices/dio/diodefs.h index 80f49a59d..836475538 100644 --- a/src/spicelib/devices/dio/diodefs.h +++ b/src/spicelib/devices/dio/diodefs.h @@ -20,6 +20,9 @@ enum { DIORSNOIZ = 0, DIOIDNOIZ, DIOFLNOIZ, + DIORSSWNOIZ, + DIOIDSWNOIZ, + DIOFLSWNOIZ, DIOTOTNOIZ, /* finally, the number of noise sources */ DIONSRCS @@ -40,6 +43,7 @@ typedef struct sDIOinstance { const int DIOnegNode; /* number of negative node of diode */ const int DIOtempNode; /* number of the temperature node of the diode */ int DIOposPrimeNode; /* number of positive prime node of diode */ + int DIOposSwPrimeNode; /* number of positive prime node of diode sidewall */ double *DIOposPosPrimePtr; /* pointer to sparse matrix at * (positive,positive prime) */ @@ -55,6 +59,17 @@ typedef struct sDIOinstance { * (negative,negative) */ double *DIOposPrimePosPrimePtr; /* pointer to sparse matrix at * (positive prime,positive prime) */ + /* separate sidewall */ + double *DIOposPosSwPrimePtr; /* pointer to sparse matrix at + * (positive,positive prime sidewall) */ + double *DIOnegPosSwPrimePtr; /* pointer to sparse matrix at + * (negative,positive prime sidewall) */ + double *DIOposSwPrimePosPtr; /* pointer to sparse matrix at + * (positive prime sidewall,positive) */ + double *DIOposSwPrimeNegPtr; /* pointer to sparse matrix at + * (positive prime sidewall,negative) */ + double *DIOposSwPrimePosSwPrimePtr; /* pointer to sparse matrix at + * (positive prime sidewall,positive prime sidewall) */ /* self heating */ double *DIOtempPosPtr; @@ -64,8 +79,12 @@ typedef struct sDIOinstance { double *DIOposTempPtr; double *DIOposPrimeTempPtr; double *DIOnegTempPtr; + /* separate sidewall */ + double *DIOtempPosSwPrimePtr; + double *DIOposSwPrimeTempPtr; double DIOcap; /* stores the diode capacitance */ + double DIOcapSW; /* stores the diode Sw capacitance */ double *DIOsens; /* stores the perturbed values of geq and ceq in ac sensitivity analyis */ @@ -114,6 +133,8 @@ typedef struct sDIOinstance { double DIOtGradingCoeff; /* temperature adjusted grading coefficient (MJ) */ double DIOtConductance; /* temperature adjusted series conductance */ double DIOtConductance_dT; /* temperature adjusted series conductance temperature derivative */ + double DIOtConductanceSW; /* temperature adjusted sw series conductance */ + double DIOtConductanceSW_dT; /* temperature adjusted sw series conductance temperature derivative */ double DIOtDepCap; /* temperature adjusted transition point in */ /* the curve matching (Fc * Vj ) */ @@ -129,6 +150,7 @@ typedef struct sDIOinstance { double DIOtTunSatSWCur_dT; /* sidewall tunneling saturation current temperature derivative */ double DIOtVcrit; /* temperature adjusted V crit */ + double DIOtVcritSW; /* temperature adjusted V crit sidewall*/ double DIOtF1; /* temperature adjusted f1 */ double DIOtBrkdwnV; /* temperature adjusted breakdown voltage */ @@ -139,17 +161,21 @@ typedef struct sDIOinstance { double DIOforwardKneeCurrent; /* Forward Knee current */ double DIOreverseKneeCurrent; /* Reverse Knee current */ + double DIOforwardSWKneeCurrent; /* Forward Sw Knee current */ double DIOjunctionCap; /* geometry adjusted junction capacitance */ double DIOjunctionSWCap; /* geometry adjusted junction sidewall capacitance */ double DIOtRecSatCur; /* temperature adjusted recombination saturation current */ double DIOtRecSatCur_dT; /* temperature adjusted recombination saturation current */ double DIOdIth_dVrs; + double DIOdIth_dVrssw; double DIOdIth_dVdio; double DIOdIth_dT; double DIOgcTt; double DIOdIrs_dT; + double DIOdIrssw_dT; double DIOdIdio_dT; + double DIOdIdioSW_dT; double DIOcmetal; /* parasitic metal overlap capacitance */ double DIOcpoly; /* parasitic polysilicon overlap capacitance */ @@ -194,6 +220,12 @@ typedef struct sDIOinstance { BindElement *DIOposPosBinding ; BindElement *DIOnegNegBinding ; BindElement *DIOposPrimePosPrimeBinding ; + /* separate sidewall */ + BindElement *DIOposPosSwPrimeBinding ; + BindElement *DIOnegPosSwPrimeBinding ; + BindElement *DIOposSwPrimePosBinding ; + BindElement *DIOposSwPrimeNegBinding ; + BindElement *DIOposSwPrimePosSwPrimeBinding ; /* self heating */ BindElement *DIOtempPosBinding; BindElement *DIOtempPosPrimeBinding; @@ -216,18 +248,24 @@ typedef struct sDIOinstance { #define DIOvoltage DIOstate #define DIOcurrent DIOstate+1 #define DIOconduct DIOstate+2 -#define DIOcapCharge DIOstate+3 -#define DIOcapCurrent DIOstate+4 +#define DIOvoltageSW DIOstate+3 +#define DIOcurrentSW DIOstate+4 +#define DIOconductSW DIOstate+5 +#define DIOcapCharge DIOstate+6 +#define DIOcapCurrent DIOstate+7 +#define DIOcapChargeSW DIOstate+8 +#define DIOcapCurrentSW DIOstate+9 -#define DIOqth DIOstate+5 /* thermal capacitor charge */ -#define DIOcqth DIOstate+6 /* thermal capacitor current */ +#define DIOqth DIOstate+10 /* thermal capacitor charge */ +#define DIOcqth DIOstate+11 /* thermal capacitor current */ -#define DIOdeltemp DIOstate+7 /* thermal voltage over rth0 */ -#define DIOdIdio_dT DIOstate+8 +#define DIOdeltemp DIOstate+12 /* thermal voltage over rth0 */ +#define DIOdIdio_dT DIOstate+13 +#define DIOdIdioSW_dT DIOstate+14 -#define DIOnumStates 9 +#define DIOnumStates 15 -#define DIOsensxp DIOstate+9 /* charge sensitivities and their derivatives. +#define DIOsensxp DIOstate+12 /* charge sensitivities and their derivatives. * +10 for the derivatives - pointer to the * beginning of the array */ @@ -252,6 +290,7 @@ typedef struct sDIOmodel { /* model structure for a diode */ unsigned DIOresistGiven : 1; unsigned DIOresistTemp1Given : 1; unsigned DIOresistTemp2Given : 1; + unsigned DIOresistSWGiven : 1; unsigned DIOemissionCoeffGiven : 1; unsigned DIOswEmissionCoeffGiven : 1; unsigned DIObrkdEmissionCoeffGiven : 1; @@ -268,6 +307,7 @@ typedef struct sDIOmodel { /* model structure for a diode */ unsigned DIOgradingSWCoeffGiven : 1; unsigned DIOforwardKneeCurrentGiven : 1; unsigned DIOreverseKneeCurrentGiven : 1; + unsigned DIOforwardSWKneeCurrentGiven : 1; unsigned DIOtlevGiven : 1; unsigned DIOtlevcGiven : 1; @@ -324,6 +364,8 @@ typedef struct sDIOmodel { /* model structure for a diode */ double DIOresistTemp1; /* series resistance 1st order temp. coeff. */ double DIOresistTemp2; /* series resistance 2nd order temp. coeff. */ double DIOconductance; /* conductance corresponding to ohmic R */ + double DIOresistSW; /* ohmic series resistance sidewall */ + double DIOconductanceSW; /* conductance corresponding to ohmic R */ double DIOemissionCoeff; /* emission coefficient (N) */ double DIOswEmissionCoeff; /* Sidewall emission coefficient (NS) */ double DIObrkdEmissionCoeff; /* Breakdown emission coefficient (NBV) */ @@ -340,6 +382,7 @@ typedef struct sDIOmodel { /* model structure for a diode */ double DIOgradingSWCoeff; /* Sidewall grading coefficient (mjsw) */ double DIOforwardKneeCurrent; /* Forward Knee current (IKF) */ double DIOreverseKneeCurrent; /* Reverse Knee current (IKR) */ + double DIOforwardSWKneeCurrent; /* Forward Sw Knee current (IKP) */ int DIOtlev; /* Diode temperature equation selector */ int DIOtlevc; /* Diode temperature equation selector */ @@ -428,6 +471,7 @@ enum { DIO_MOD_LEVEL = 100, DIO_MOD_IS, DIO_MOD_RS, + DIO_MOD_RSW, DIO_MOD_N, DIO_MOD_TT, DIO_MOD_CJO, @@ -451,6 +495,7 @@ enum { DIO_MOD_MJSW, DIO_MOD_IKF, DIO_MOD_IKR, + DIO_MOD_IKP, DIO_MOD_FCS, DIO_MOD_TTT1, DIO_MOD_TTT2, diff --git a/src/spicelib/devices/dio/dioload.c b/src/spicelib/devices/dio/dioload.c index e8f1dd755..b8590c155 100644 --- a/src/spicelib/devices/dio/dioload.c +++ b/src/spicelib/devices/dio/dioload.c @@ -24,10 +24,10 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) DIOinstance *here; double arg; double argsw; - double capd; + double capd, capdsw=0.0; double cd, cdb, cdsw, cdb_dT, cdsw_dT; double cdeq; - double cdhat; + double cdhat, cdhatsw=0.0; double ceq; double csat; /* area-scaled saturation current */ double csatsw; /* perimeter-scaled saturation current */ @@ -37,34 +37,33 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) double czeroSW; double czof2SW; double sargSW; - double sqrt_ikr; - double sqrt_ikf; - double ikf_area_m; - double ikr_area_m; + double sqrt_ikx; - double delvd; /* change in diode voltage temporary */ + double delvd, delvdsw=0.0; /* change in diode voltage temporary */ double evd; double evrev; double gd, gdb, gdsw, gen_fac, gen_fac_vd; double t1, evd_rec, cdb_rec, gdb_rec, cdb_rec_dT; double geq; double gspr; /* area-scaled conductance */ + double gsprsw; /* perim-scaled conductance */ double sarg; #ifndef NOBYPASS double tol; /* temporary for tolerence calculations */ #endif - double vd; /* current diode voltage */ + double vd, vdsw=0.0; /* current diode voltage */ double vdtemp; double vt; /* K t / Q */ double vte, vtesw, vtetun, vtebrk; - int Check_dio=0, Check_th; + int Check_dio=0, Check_dio_sw=0, Check_th; int error; int SenCond=0; /* sensitivity condition */ double diffcharge, deplcharge, deplchargeSW, diffcap, deplcap, deplcapSW; double deldelTemp, delTemp, Temp; - double ceqqth=0.0, Ith=0.0, gcTt=0.0, vrs=0.0; + double ceqqth=0.0, Ith=0.0, gcTt=0.0, vrs=0.0, vrssw=0.0; double dIdio_dT, dIth_dVdio=0.0, dIrs_dT=0.0, dIth_dVrs=0.0, dIth_dT=0.0; + double dIdioSw_dT=0.0, dIth_dVdioSw=0.0, dIth_dVrssw=0.0, dIrssw_dT=0.0; double argsw_dT, csat_dT, csatsw_dT; /* loop through all the diode models */ @@ -101,8 +100,10 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) delTemp = 0.0; vt = CONSTKoverQ * here->DIOtemp; vte = model->DIOemissionCoeff * vt; + vtesw = model->DIOswEmissionCoeff * vt; vtebrk = model->DIObrkdEmissionCoeff * vt; gspr = here->DIOtConductance; + gsprsw = here->DIOtConductanceSW; /* * initialization */ @@ -116,9 +117,11 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) if((ckt->CKTsenInfo->SENmode == TRANSEN)&& (ckt->CKTmode & MODEINITTRAN)) { vd = *(ckt->CKTstate1 + here->DIOvoltage); + if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate1 + here->DIOvoltageSW); delTemp = *(ckt->CKTstate1 + here->DIOdeltemp); } else{ vd = *(ckt->CKTstate0 + here->DIOvoltage); + if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate0 + here->DIOvoltageSW); delTemp = *(ckt->CKTstate0 + here->DIOdeltemp); } @@ -128,24 +131,28 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) goto next1; } - Check_dio=1; + Check_dio=1; Check_dio_sw=1; if(ckt->CKTmode & MODEINITSMSIG) { vd= *(ckt->CKTstate0 + here->DIOvoltage); + if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate0 + here->DIOvoltageSW); delTemp = *(ckt->CKTstate0 + here->DIOdeltemp); } else if (ckt->CKTmode & MODEINITTRAN) { vd= *(ckt->CKTstate1 + here->DIOvoltage); + if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate1 + here->DIOvoltageSW); delTemp = *(ckt->CKTstate1 + here->DIOdeltemp); } else if ( (ckt->CKTmode & MODEINITJCT) && (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC) ) { vd=here->DIOinitCond; + if (model->DIOresistSWGiven) vdsw = here->DIOinitCond; } else if ( (ckt->CKTmode & MODEINITJCT) && here->DIOoff) { - vd=0; + vd=vdsw=0; delTemp = 0.0; } else if ( ckt->CKTmode & MODEINITJCT) { vd=here->DIOtVcrit; + vdsw=here->DIOtVcritSW; delTemp = 0.0; } else if ( ckt->CKTmode & MODEINITFIX && here->DIOoff) { - vd=0; + vd=vdsw=0; delTemp = 0.0; } else { #ifndef PREDICTOR @@ -164,10 +171,17 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) *(ckt->CKTstate1 + here->DIOdIdio_dT); *(ckt->CKTstate0+here->DIOqth) = *(ckt->CKTstate1+here->DIOqth); + if (model->DIOresistSWGiven) { + vdsw = DEVpred(ckt,here->DIOvoltageSW); + *(ckt->CKTstate0 + here->DIOdIdioSW_dT) = + *(ckt->CKTstate1 + here->DIOdIdioSW_dT); + } } else { #endif /* PREDICTOR */ vd = *(ckt->CKTrhsOld+here->DIOposPrimeNode)- *(ckt->CKTrhsOld + here->DIOnegNode); + if (model->DIOresistSWGiven) vdsw = *(ckt->CKTrhsOld+here->DIOposSwPrimeNode)- + *(ckt->CKTrhsOld + here->DIOnegNode); if (selfheat) delTemp = *(ckt->CKTrhsOld + here->DIOtempNode); else @@ -185,6 +199,11 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) cdhat= *(ckt->CKTstate0 + here->DIOcurrent) + *(ckt->CKTstate0 + here->DIOconduct) * delvd + *(ckt->CKTstate0 + here->DIOdIdio_dT) * deldelTemp; + if (model->DIOresistSWGiven) { + delvdsw=vdsw - *(ckt->CKTstate0 + here->DIOvoltageSW); + cdhatsw = *(ckt->CKTstate0 + here->DIOconductSW) * delvdsw + + *(ckt->CKTstate0 + here->DIOdIdioSW_dT) * deldelTemp; + } /* * bypass if solution has not changed */ @@ -192,7 +211,7 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) if ((!(ckt->CKTmode & MODEINITPRED)) && (ckt->CKTbypass)) { tol=ckt->CKTvoltTol + ckt->CKTreltol* MAX(fabs(vd),fabs(*(ckt->CKTstate0 +here->DIOvoltage))); - if (fabs(delvd) < tol){ + if (fabs(delvd) < tol) { tol=ckt->CKTreltol* MAX(fabs(cdhat), fabs(*(ckt->CKTstate0 + here->DIOcurrent)))+ ckt->CKTabstol; @@ -202,12 +221,25 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) (fabs(deldelTemp) < (ckt->CKTreltol * MAX(fabs(delTemp), fabs(*(ckt->CKTstate0+here->DIOdeltemp)))+ ckt->CKTvoltTol*1e4))) { - vd= *(ckt->CKTstate0 + here->DIOvoltage); - cd= *(ckt->CKTstate0 + here->DIOcurrent); - gd= *(ckt->CKTstate0 + here->DIOconduct); - delTemp = *(ckt->CKTstate0 + here->DIOdeltemp); - dIdio_dT= *(ckt->CKTstate0 + here->DIOdIdio_dT); - goto load; + if ((!model->DIOresistSWGiven) || (fabs(delvdsw) < ckt->CKTvoltTol + ckt->CKTreltol * + MAX(fabs(vdsw),fabs(*(ckt->CKTstate0+here->DIOvoltageSW))))) { + if ((!model->DIOresistSWGiven) || (fabs(cdhatsw- *(ckt->CKTstate0 + here->DIOcurrentSW)) + < ckt->CKTreltol* MAX(fabs(cdhatsw), + fabs(*(ckt->CKTstate0 + here->DIOcurrentSW)))+ckt->CKTabstol)) { + vd= *(ckt->CKTstate0 + here->DIOvoltage); + cd= *(ckt->CKTstate0 + here->DIOcurrent); + gd= *(ckt->CKTstate0 + here->DIOconduct); + delTemp = *(ckt->CKTstate0 + here->DIOdeltemp); + dIdio_dT= *(ckt->CKTstate0 + here->DIOdIdio_dT); + if (model->DIOresistSWGiven) { + vdsw= *(ckt->CKTstate0 + here->DIOvoltageSW); + cdsw= *(ckt->CKTstate0 + here->DIOcurrentSW); + gdsw= *(ckt->CKTstate0 + here->DIOconductSW); + dIdioSw_dT= *(ckt->CKTstate0 + here->DIOdIdioSW_dT); + } + goto load; + } + } } } } @@ -228,6 +260,20 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) vd = DEVpnjlim(vd,*(ckt->CKTstate0 + here->DIOvoltage), vte,here->DIOtVcrit,&Check_dio); } + if (model->DIOresistSWGiven) { + if ( (model->DIObreakdownVoltageGiven) && + (vdsw < MIN(0,-here->DIOtBrkdwnV+10*vtebrk))) { + vdtemp = -(vdsw+here->DIOtBrkdwnV); + vdtemp = DEVpnjlim(vdtemp, + -(*(ckt->CKTstate0 + here->DIOvoltageSW) + + here->DIOtBrkdwnV),vtebrk, + here->DIOtVcritSW,&Check_dio_sw); + vdsw = -(vdtemp+here->DIOtBrkdwnV); + } else { + vdsw = DEVpnjlim(vdsw,*(ckt->CKTstate0 + here->DIOvoltageSW), + vtesw,here->DIOtVcritSW,&Check_dio_sw); + } + } if (selfheat) delTemp = DEVlimitlog(delTemp, *(ckt->CKTstate0 + here->DIOdeltemp), 100, &Check_th); @@ -253,47 +299,45 @@ next1: csatsw = here->DIOtSatSWCur; csatsw_dT = here->DIOtSatSWCur_dT; gspr = here->DIOtConductance; + gsprsw = here->DIOtConductanceSW; - if (model->DIOsatSWCurGiven) { /* sidewall current */ + if (model->DIOsatSWCurGiven) { /* sidewall current */ + double vds; + if (model->DIOresistSWGiven) + vds = vdsw; /* sidewall voltage used */ + else + vds = vd; /* common voltage used */ - if (model->DIOswEmissionCoeffGiven) { /* current with own characteristic */ + if (model->DIOswEmissionCoeffGiven) { /* with own characteristic */ - vtesw = model->DIOswEmissionCoeff * vt; + if (vds >= -3*vtesw) { /* forward */ - if (vd >= -3*vtesw) { /* forward */ - - evd = exp(vd/vtesw); + evd = exp(vds/vtesw); cdsw = csatsw*(evd-1); gdsw = csatsw*evd/vtesw; - cdsw_dT = csatsw_dT * (evd - 1) - csatsw * vd * evd / (vtesw * Temp); + cdsw_dT = csatsw_dT * (evd - 1) - csatsw * vds * evd / (vtesw * Temp); - } else if((!(model->DIObreakdownVoltageGiven)) || - vd >= -here->DIOtBrkdwnV) { /* reverse */ + } else if ((!(model->DIObreakdownVoltageGiven)) || + vds >= -here->DIOtBrkdwnV) { /* reverse */ - argsw = 3*vtesw/(vd*CONSTe); + argsw = 3*vtesw/(vds*CONSTe); argsw = argsw * argsw * argsw; argsw_dT = 3 * argsw / Temp; cdsw = -csatsw*(1+argsw); - gdsw = csatsw*3*argsw/vd; + gdsw = csatsw*3*argsw/vds; cdsw_dT = -csatsw_dT - (csatsw_dT*argsw + csatsw*argsw_dT); - } else { /* breakdown */ + } else if (!model->DIOresistSWGiven){ /* breakdown, but not for separate sidewall diode */ double evrev_dT; - evrev = exp(-(here->DIOtBrkdwnV+vd)/vtebrk); - evrev_dT = (here->DIOtBrkdwnV+vd)*evrev/(vtebrk*Temp); + evrev = exp(-(here->DIOtBrkdwnV+vds)/vtebrk); + evrev_dT = (here->DIOtBrkdwnV+vds)*evrev/(vtebrk*Temp); cdsw = -csatsw*evrev; gdsw = csatsw*evrev/vtebrk; cdsw_dT = -(csatsw_dT*evrev + csatsw*evrev_dT); } - } else { /* merge saturation currents and use same characteristic as bottom diode */ - - csat = csat + csatsw; - csat_dT = csat_dT + csatsw_dT; - cdsw_dT = 0.0; - } } @@ -302,12 +346,17 @@ next1: * temperature dependent diode saturation current and derivative */ - if (vd >= -3*vte) { /* bottom current forward */ - + if (vd >= -3*vte) { /* bottom and sidewall current forward with common voltage */ + /* and with common characteristic */ evd = exp(vd/vte); cdb = csat*(evd-1); gdb = csat*evd/vte; cdb_dT = csat_dT * (evd - 1) - csat * vd * evd / (vte * Temp); + if ((model->DIOsatSWCurGiven)&&(!model->DIOswEmissionCoeffGiven)) { + cdsw = csatsw*(evd-1); + gdsw = csatsw*evd/vte; + cdsw_dT = csatsw_dT * (evd - 1) - csatsw * vd * evd / (vte * Temp); + } if (model->DIOrecSatCurGiven) { /* recombination current */ double vterec = model->DIOrecEmissionCoeff*vt; evd_rec = exp(vd/(vterec)); @@ -326,7 +375,7 @@ next1: cdb_dT = cdb_dT + cdb_rec_dT*gen_fac; } - } else if((!(model->DIObreakdownVoltageGiven)) || + } else if ((!(model->DIObreakdownVoltageGiven)) || vd >= -here->DIOtBrkdwnV) { /* reverse */ double darg_dT; @@ -337,8 +386,14 @@ next1: cdb = -csat*(1+arg); gdb = csat*3*arg/vd; cdb_dT = -csat_dT - (csat_dT*arg + csat*darg_dT); + if ((model->DIOsatSWCurGiven)&&(!model->DIOswEmissionCoeffGiven)) { + cdsw = -csatsw*(1+arg); + gdsw = csatsw*3*arg/vd; + cdsw_dT = -csatsw_dT - (csatsw_dT*arg + csatsw*darg_dT); + } } else { /* breakdown */ + double evrev_dT; evrev = exp(-(here->DIOtBrkdwnV+vd)/vtebrk); @@ -346,6 +401,15 @@ next1: cdb = -csat*evrev; gdb = csat*evrev/vtebrk; cdb_dT = -(csat_dT*evrev + csat*evrev_dT); + if ((model->DIOsatSWCurGiven) + &&(!model->DIOresistSWGiven) /* no breakdown for separate sidewall diode */ + &&(!model->DIOswEmissionCoeffGiven)) { + evrev = exp(-(here->DIOtBrkdwnV+vdsw)/vtebrk); + evrev_dT = (here->DIOtBrkdwnV+vdsw)*evrev/(vtebrk*Temp); + cdsw = -csatsw*evrev; + gdsw = csatsw*evrev/vtebrk; + cdsw_dT = -(csatsw_dT*evrev + csatsw*evrev_dT); + } } @@ -373,36 +437,46 @@ next1: } - cd = cdb + cdsw; - gd = gdb + gdsw; - dIdio_dT = cdb_dT + cdsw_dT; - if (vd >= -3*vte) { /* limit forward */ - if( (model->DIOforwardKneeCurrentGiven) && (cd > 1.0e-18) ) { - ikf_area_m = here->DIOforwardKneeCurrent; - sqrt_ikf = sqrt(cd/ikf_area_m); - gd = ((1+sqrt_ikf)*gd - cd*gd/(2*sqrt_ikf*ikf_area_m))/(1+2*sqrt_ikf + cd/ikf_area_m) + ckt->CKTgmin; - cd = cd/(1+sqrt_ikf) + ckt->CKTgmin*vd; - } else { - gd = gd + ckt->CKTgmin; - cd = cd + ckt->CKTgmin*vd; + if ( (model->DIOforwardKneeCurrentGiven) && (cdb > 1.0e-18) ) { + double ikf_area_m = here->DIOforwardKneeCurrent; + sqrt_ikx = sqrt(cdb/ikf_area_m); + gdb = ((1+sqrt_ikx)*gdb - cdb*gdb/(2*sqrt_ikx*ikf_area_m))/(1+2*sqrt_ikx + cdb/ikf_area_m); + cdb = cdb/(1+sqrt_ikx); } } else { /* limit reverse */ - if( (model->DIOreverseKneeCurrentGiven) && (cd < -1.0e-18) ) { - ikr_area_m = here->DIOreverseKneeCurrent; - sqrt_ikr = sqrt(cd/(-ikr_area_m)); - gd = ((1+sqrt_ikr)*gd + cd*gd/(2*sqrt_ikr*ikr_area_m))/(1+2*sqrt_ikr - cd/ikr_area_m) + ckt->CKTgmin; - cd = cd/(1+sqrt_ikr) + ckt->CKTgmin*vd; - } else { - gd = gd + ckt->CKTgmin; - cd = cd + ckt->CKTgmin*vd; + if ( (model->DIOreverseKneeCurrentGiven) && (cdb < -1.0e-18) ) { + double ikr_area_m = here->DIOreverseKneeCurrent; + sqrt_ikx = sqrt(cdb/(-ikr_area_m)); + gdb = ((1+sqrt_ikx)*gdb + cdb*gdb/(2*sqrt_ikx*ikr_area_m))/(1+2*sqrt_ikx - cdb/ikr_area_m); + cdb = cdb/(1+sqrt_ikx); } } + if ( (model->DIOforwardSWKneeCurrentGiven) && (cdsw > 1.0e-18) ) { + double ikp_peri_m = here->DIOforwardSWKneeCurrent; + sqrt_ikx = sqrt(cdsw/ikp_peri_m); + gdsw = ((1+sqrt_ikx)*gdsw - cdsw*gdsw/(2*sqrt_ikx*ikp_peri_m))/(1+2*sqrt_ikx + cdsw/ikp_peri_m); + cdsw = cdsw/(1+sqrt_ikx); + } + + if (!model->DIOresistSWGiven) { + cd = cdb + cdsw + ckt->CKTgmin*vd; + gd = gdb + gdsw + ckt->CKTgmin; + dIdio_dT = cdb_dT + cdsw_dT; + } else { + cd = cdb + ckt->CKTgmin*vd; + gd = gdb + ckt->CKTgmin; + cdsw = cdsw + ckt->CKTgmin*vdsw; + gdsw = gdsw + ckt->CKTgmin; + dIdio_dT = cdb_dT; + dIdioSw_dT = cdsw_dT; + } + if ((ckt->CKTmode & (MODEDCTRANCURVE | MODETRAN | MODEAC | MODEINITSMSIG)) || ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) { /* @@ -421,28 +495,40 @@ next1: deplcap = czof2*(here->DIOtF3+here->DIOtGradingCoeff*vd/here->DIOtJctPot); } czeroSW=here->DIOtJctSWCap; - if (vd < here->DIOtDepSWCap){ - argSW=1-vd/here->DIOtJctSWPot; + double vdx; + if (model->DIOresistSWGiven) + vdx = vdsw; + else + vdx = vd; + if (vdx < here->DIOtDepSWCap){ + argSW=1-vdx/here->DIOtJctSWPot; sargSW=exp(-model->DIOgradingSWCoeff*log(argSW)); deplchargeSW = here->DIOtJctSWPot*czeroSW*(1-argSW*sargSW)/(1-model->DIOgradingSWCoeff); deplcapSW = czeroSW*sargSW; } else { czof2SW=czeroSW/here->DIOtF2SW; - deplchargeSW = czeroSW*here->DIOtF1+czof2SW*(here->DIOtF3SW*(vd-here->DIOtDepSWCap)+ - (model->DIOgradingSWCoeff/(here->DIOtJctSWPot+here->DIOtJctSWPot))*(vd*vd-here->DIOtDepSWCap*here->DIOtDepSWCap)); - deplcapSW = czof2SW*(here->DIOtF3SW+model->DIOgradingSWCoeff*vd/here->DIOtJctSWPot); + deplchargeSW = czeroSW*here->DIOtF1+czof2SW*(here->DIOtF3SW*(vdx-here->DIOtDepSWCap)+ + (model->DIOgradingSWCoeff/(here->DIOtJctSWPot+here->DIOtJctSWPot))*(vdx*vdx-here->DIOtDepSWCap*here->DIOtDepSWCap)); + deplcapSW = czof2SW*(here->DIOtF3SW+model->DIOgradingSWCoeff*vdx/here->DIOtJctSWPot); } diffcharge = here->DIOtTransitTime*cd; - *(ckt->CKTstate0 + here->DIOcapCharge) = - diffcharge + deplcharge + deplchargeSW + (here->DIOcmetal + here->DIOcpoly)*vd; - diffcap = here->DIOtTransitTime*gd; - - capd = diffcap + deplcap + deplcapSW + here->DIOcmetal + here->DIOcpoly; - - here->DIOcap = capd; - + if (!model->DIOresistSWGiven) { + *(ckt->CKTstate0 + here->DIOcapCharge) = + diffcharge + deplcharge + deplchargeSW + (here->DIOcmetal + here->DIOcpoly)*vd; + capd = diffcap + deplcap + deplcapSW + here->DIOcmetal + here->DIOcpoly; + here->DIOcap = capd; + } else { + *(ckt->CKTstate0 + here->DIOcapCharge) = + diffcharge + deplcharge + (here->DIOcmetal + here->DIOcpoly)*vd; + capd = diffcap + deplcap + here->DIOcmetal + here->DIOcpoly; + here->DIOcap = capd; + *(ckt->CKTstate0 + here->DIOcapChargeSW) = + deplcapSW; + capdsw = deplcapSW; + here->DIOcapSW = capdsw; + } /* * store small-signal parameters */ @@ -450,11 +536,18 @@ next1: (!(ckt->CKTmode & MODEUIC)) ) { if (ckt->CKTmode & MODEINITSMSIG){ *(ckt->CKTstate0 + here->DIOcapCurrent) = capd; - + if (model->DIOresistSWGiven) { + *(ckt->CKTstate0 + here->DIOcapCurrentSW) = capdsw; + } if(SenCond){ *(ckt->CKTstate0 + here->DIOcurrent) = cd; *(ckt->CKTstate0 + here->DIOconduct) = gd; *(ckt->CKTstate0 + here->DIOdIdio_dT) = dIdio_dT; + if (model->DIOresistSWGiven) { + *(ckt->CKTstate0 + here->DIOcurrentSW) = cdsw; + *(ckt->CKTstate0 + here->DIOconductSW) = gdsw; + *(ckt->CKTstate0 + here->DIOdIdioSW_dT) = dIdioSw_dT; + } #ifdef SENSDEBUG printf("storing small signal parameters\n"); printf("cd = %.7e,vd = %.7e\n",cd,vd); @@ -469,6 +562,8 @@ next1: */ if(SenCond && (ckt->CKTsenInfo->SENmode == TRANSEN)){ *(ckt->CKTstate0 + here->DIOcurrent) = cd; + if (model->DIOresistSWGiven) + *(ckt->CKTstate0 + here->DIOcurrentSW) = cdsw; #ifdef SENSDEBUG printf("storing parameters for transient sensitivity\n" ); @@ -481,21 +576,29 @@ next1: if (ckt->CKTmode & MODEINITTRAN) { *(ckt->CKTstate1 + here->DIOcapCharge) = *(ckt->CKTstate0 + here->DIOcapCharge); + if (model->DIOresistSWGiven) + *(ckt->CKTstate1 + here->DIOcapChargeSW) = + *(ckt->CKTstate0 + here->DIOcapChargeSW); } error = NIintegrate(ckt,&geq,&ceq,capd,here->DIOcapCharge); if(error) return(error); gd=gd+geq; cd=cd+*(ckt->CKTstate0 + here->DIOcapCurrent); + if (model->DIOresistSWGiven) { + error = NIintegrate(ckt,&geq,&ceq,capdsw,here->DIOcapChargeSW); + if(error) return(error); + gdsw=gdsw+geq; + cdsw=cdsw+*(ckt->CKTstate0 + here->DIOcapCurrentSW); + } if (ckt->CKTmode & MODEINITTRAN) { *(ckt->CKTstate1 + here->DIOcapCurrent) = *(ckt->CKTstate0 + here->DIOcapCurrent); + if (model->DIOresistSWGiven) + *(ckt->CKTstate1 + here->DIOcapCurrentSW) = + *(ckt->CKTstate0 + here->DIOcapCurrentSW); } if (selfheat) { - if (ckt->CKTmode & MODEINITTRAN) { - *(ckt->CKTstate1 + here->DIOqth) = - *(ckt->CKTstate0 + here->DIOqth); - } error = NIintegrate(ckt, &gcTt, &ceqqth, model->DIOcth0, here->DIOqth); if (error) return(error); if (ckt->CKTmode & MODEINITTRAN) { @@ -512,9 +615,16 @@ next1: * check convergence */ if ( (!(ckt->CKTmode & MODEINITFIX)) || (!(here->DIOoff)) ) { - if ((Check_th == 1) || (Check_dio == 1)) { - ckt->CKTnoncon++; - ckt->CKTtroubleElt = (GENinstance *) here; + if (!model->DIOresistSWGiven) { + if ((Check_th == 1) || (Check_dio == 1)) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } + } else { + if ((Check_th == 1) || (Check_dio == 1) || (Check_dio_sw == 1)) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } } } next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd; @@ -522,7 +632,12 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd; *(ckt->CKTstate0 + here->DIOconduct) = gd; *(ckt->CKTstate0 + here->DIOdeltemp) = delTemp; *(ckt->CKTstate0 + here->DIOdIdio_dT) = dIdio_dT; - + if (model->DIOresistSWGiven) { + *(ckt->CKTstate0 + here->DIOvoltageSW) = vdsw; + *(ckt->CKTstate0 + here->DIOcurrentSW) = cdsw; + *(ckt->CKTstate0 + here->DIOconductSW) = gdsw; + *(ckt->CKTstate0 + here->DIOdIdioSW_dT) = dIdioSw_dT; + } if(SenCond) continue; #ifndef NOBYPASS @@ -531,20 +646,37 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd; if (selfheat) { double dIrs_dVrs, dIrs_dgspr, dIth_dIrs; vrs = *(ckt->CKTrhsOld + here->DIOposNode) - *(ckt->CKTrhsOld + here->DIOposPrimeNode); - Ith = vd*cd + vrs*vrs*gspr; /* Diode dissipated power */ dIrs_dVrs = gspr; dIrs_dgspr = vrs; dIrs_dT = dIrs_dgspr * here->DIOtConductance_dT; + Ith = vd*cd + vrs*vrs*gspr; /* Diode dissipated power */ dIth_dVrs = vrs*gspr; dIth_dIrs = vrs; dIth_dVrs = dIth_dVrs + dIth_dIrs*dIrs_dVrs; dIth_dT = dIth_dIrs*dIrs_dT + dIdio_dT*vd; dIth_dVdio = cd + vd*gd; here->DIOdIth_dVrs = dIth_dVrs; - here->DIOdIth_dVdio = dIth_dVdio; - here->DIOdIth_dT = dIth_dT; here->DIOgcTt = gcTt; here->DIOdIrs_dT = dIrs_dT; + here->DIOdIth_dVdio = dIth_dVdio; + here->DIOdIth_dT = dIth_dT; + if (model->DIOresistSWGiven) { + double dIrssw_dVrssw, dIrssw_dgsprsw, dIth_dIrssw; + vrssw = *(ckt->CKTrhsOld + here->DIOposNode) - *(ckt->CKTrhsOld + here->DIOposSwPrimeNode); + dIrssw_dVrssw = gsprsw; + dIrssw_dgsprsw = vrssw; + dIrssw_dT = dIrssw_dgsprsw * here->DIOtConductanceSW_dT; + Ith = Ith + vdsw*cdsw + vrssw*vrssw*gsprsw; /* Diode dissipated power */ + dIth_dVrssw = vrssw*gsprsw; + dIth_dIrssw = vrssw; + dIth_dVrssw = dIth_dVrssw + dIth_dIrssw*dIrssw_dVrssw; + dIth_dT = dIth_dT + dIth_dIrssw*dIrssw_dT + dIdioSw_dT*vdsw; + dIth_dVdioSw = cdsw + vdsw*gdsw; + here->DIOdIth_dVrssw = dIth_dVrssw; + here->DIOdIth_dVdio = dIth_dVdioSw; + here->DIOdIth_dT = dIth_dT; + here->DIOdIrssw_dT = dIrssw_dT; + } } /* * load current vector @@ -558,6 +690,17 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd; *(ckt->CKTrhs + here->DIOnegNode) += -dIdio_dT*delTemp; *(ckt->CKTrhs + here->DIOtempNode) += Ith - dIth_dVdio*vd - dIth_dVrs*vrs - dIth_dT*delTemp - ceqqth; } + if (model->DIOresistSWGiven) { + cdeq=cdsw-gdsw*vdsw; + *(ckt->CKTrhs + here->DIOnegNode) += cdeq; + *(ckt->CKTrhs + here->DIOposSwPrimeNode) -= cdeq; + if (selfheat) { + *(ckt->CKTrhs + here->DIOposNode) += dIrssw_dT*delTemp; + *(ckt->CKTrhs + here->DIOposSwPrimeNode) += dIdioSw_dT*delTemp - dIrssw_dT*delTemp; + *(ckt->CKTrhs + here->DIOnegNode) += -dIdioSw_dT*delTemp; + *(ckt->CKTrhs + here->DIOtempNode) += -dIth_dVdioSw*vdsw - dIth_dVrssw*vrssw; + } + } /* * load matrix */ @@ -577,6 +720,24 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd; (*(here->DIOposPrimeTempPtr) += dIdio_dT - dIrs_dT); (*(here->DIOnegTempPtr) += -dIdio_dT); } + if (model->DIOresistSWGiven) { + *(here->DIOposPosPtr) += gsprsw; + *(here->DIOnegNegPtr) += gdsw; + *(here->DIOposSwPrimePosSwPrimePtr) += (gdsw + gsprsw); + *(here->DIOposPosSwPrimePtr) -= gsprsw; + *(here->DIOnegPosSwPrimePtr) -= gdsw; + *(here->DIOposSwPrimePosPtr) -= gsprsw; + *(here->DIOposSwPrimeNegPtr) -= gdsw; + + if (selfheat) { + (*(here->DIOtempPosPtr) += -dIth_dVrssw); + (*(here->DIOtempPosSwPrimePtr) += -dIth_dVdioSw + dIth_dVrssw); + (*(here->DIOtempNegPtr) += dIth_dVdioSw); + (*(here->DIOposTempPtr) += dIrssw_dT); + (*(here->DIOposSwPrimeTempPtr) += dIdioSw_dT - dIrssw_dT); + (*(here->DIOnegTempPtr) += -dIdioSw_dT); + } + } } } return(OK); diff --git a/src/spicelib/devices/dio/diomask.c b/src/spicelib/devices/dio/diomask.c index dcbdfffc0..1f4e11ce5 100644 --- a/src/spicelib/devices/dio/diomask.c +++ b/src/spicelib/devices/dio/diomask.c @@ -42,6 +42,9 @@ DIOmAsk (CKTcircuit *ckt, GENmodel *inModel, int which, IFvalue *value) case DIO_MOD_RS: value->rValue = model->DIOresist; return(OK); + case DIO_MOD_RSW: + value->rValue = model->DIOresistSW; + return(OK); case DIO_MOD_TRS: value->rValue = model->DIOresistTemp1; return(OK); @@ -93,6 +96,9 @@ DIOmAsk (CKTcircuit *ckt, GENmodel *inModel, int which, IFvalue *value) case DIO_MOD_IKR: value->rValue = model->DIOreverseKneeCurrent; return(OK); + case DIO_MOD_IKP: + value->rValue = model->DIOforwardSWKneeCurrent; + return(OK); case DIO_MOD_NBV: value->rValue = model->DIObrkdEmissionCoeff; return(OK); diff --git a/src/spicelib/devices/dio/diompar.c b/src/spicelib/devices/dio/diompar.c index e68052eb0..498421160 100644 --- a/src/spicelib/devices/dio/diompar.c +++ b/src/spicelib/devices/dio/diompar.c @@ -40,6 +40,10 @@ DIOmParam(int param, IFvalue *value, GENmodel *inModel) model->DIOresist = value->rValue; model->DIOresistGiven = TRUE; break; + case DIO_MOD_RSW: + model->DIOresistSW = value->rValue; + model->DIOresistSWGiven = TRUE; + break; case DIO_MOD_TRS: model->DIOresistTemp1 = value->rValue; model->DIOresistTemp1Given = TRUE; @@ -108,6 +112,10 @@ DIOmParam(int param, IFvalue *value, GENmodel *inModel) model->DIOreverseKneeCurrent = value->rValue; model->DIOreverseKneeCurrentGiven = TRUE; break; + case DIO_MOD_IKP: + model->DIOforwardSWKneeCurrent = value->rValue; + model->DIOforwardSWKneeCurrentGiven = TRUE; + break; case DIO_MOD_NBV: model->DIObrkdEmissionCoeff = value->rValue; model->DIObrkdEmissionCoeffGiven = TRUE; diff --git a/src/spicelib/devices/dio/dionoise.c b/src/spicelib/devices/dio/dionoise.c index fc30d4132..de2ba3793 100644 --- a/src/spicelib/devices/dio/dionoise.c +++ b/src/spicelib/devices/dio/dionoise.c @@ -41,10 +41,13 @@ DIOnoise(int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, static char *DIOnNames[DIONSRCS] = { /* Note that we have to keep the order - consistent with thestrchr definitions in DIOdefs.h */ + consistent with the strchr definitions in DIOdefs.h */ "_rs", /* noise due to rs */ "_id", /* noise due to id */ "_1overf", /* flicker (1/f) noise */ + "_rsw", /* noise due to rsw */ + "_idsw", /* noise due to id sw */ + "_1overfsw", /* flicker (1/f) noise sw */ "" /* total diode noise */ }; @@ -108,10 +111,36 @@ DIOnoise(int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, noizDens[DIOTOTNOIZ] = noizDens[DIORSNOIZ] + noizDens[DIOIDNOIZ] + noizDens[DIOFLNOIZ]; + + if (model->DIOresistSWGiven) { + /* sidewall diode */ + NevalSrcInstanceTemp(&noizDens[DIORSSWNOIZ],&lnNdens[DIORSSWNOIZ], + ckt, THERMNOISE, inst->DIOposSwPrimeNode, inst->DIOposNode, + inst->DIOtConductanceSW, dtemp); + + NevalSrc(&noizDens[DIOIDSWNOIZ],&lnNdens[DIOIDSWNOIZ], + ckt, SHOTNOISE, inst->DIOposSwPrimeNode, inst->DIOnegNode, + *(ckt->CKTstate0 + inst->DIOcurrentSW)); + + NevalSrc(&noizDens[DIOFLSWNOIZ], NULL, ckt, + N_GAIN, inst->DIOposSwPrimeNode, inst->DIOnegNode, + (double) 0.0); + noizDens[DIOFLSWNOIZ] *= model->DIOfNcoef * + exp(model->DIOfNexp * + log(MAX(fabs(*(ckt->CKTstate0 + inst->DIOcurrentSW) / inst->DIOm), N_MINLOG))) / + data->freq * inst->DIOm; + lnNdens[DIOFLSWNOIZ] = + log(MAX(noizDens[DIOFLSWNOIZ], N_MINLOG)); + + noizDens[DIOTOTNOIZ] += noizDens[DIORSSWNOIZ] + + noizDens[DIOIDSWNOIZ] + + noizDens[DIOFLSWNOIZ]; + } + lnNdens[DIOTOTNOIZ] = log(MAX(noizDens[DIOTOTNOIZ], N_MINLOG)); - *OnDens += noizDens[DIOTOTNOIZ]; + *OnDens += noizDens[DIOTOTNOIZ]; if (data->delFreq == 0.0) { diff --git a/src/spicelib/devices/dio/diopzld.c b/src/spicelib/devices/dio/diopzld.c index 8ec036031..44e13b84b 100644 --- a/src/spicelib/devices/dio/diopzld.c +++ b/src/spicelib/devices/dio/diopzld.c @@ -18,7 +18,7 @@ int DIOpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s) { DIOmodel *model = (DIOmodel*)inModel; - double gspr; + double gspr, gsprsw; double geq; double xceq; DIOinstance *here; @@ -43,6 +43,22 @@ DIOpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s) *(here->DIOposPrimePosPtr ) -= gspr; *(here->DIOposPrimeNegPtr ) -= geq + xceq * s->real; *(here->DIOposPrimeNegPtr +1 ) -= xceq * s->imag; + if (model->DIOresistSWGiven) { + gsprsw=here->DIOtConductanceSW; + geq= *(ckt->CKTstate0 + here->DIOconductSW); + xceq= *(ckt->CKTstate0 + here->DIOcapCurrentSW) * ckt->CKTomega; + *(here->DIOposPosPtr) += gsprsw; + *(here->DIOnegNegPtr) += geq + xceq * s->real; + *(here->DIOnegNegPtr + 1) += xceq * s->imag; + *(here->DIOposSwPrimePosSwPrimePtr) += geq + gsprsw + xceq * s->real; + *(here->DIOposSwPrimePosSwPrimePtr + 1) += xceq * s->imag; + *(here->DIOposPosSwPrimePtr) -= gsprsw; + *(here->DIOnegPosSwPrimePtr) -= geq; + *(here->DIOnegPosSwPrimePtr + 1) -= xceq; + *(here->DIOposSwPrimePosPtr) -= gsprsw; + *(here->DIOposSwPrimeNegPtr) -= geq + xceq * s->real; + *(here->DIOposSwPrimeNegPtr + 1) -= xceq * s->imag; + } } } return(OK); diff --git a/src/spicelib/devices/dio/diosetup.c b/src/spicelib/devices/dio/diosetup.c index 98ced6e01..0b40b1b49 100644 --- a/src/spicelib/devices/dio/diosetup.c +++ b/src/spicelib/devices/dio/diosetup.c @@ -117,6 +117,13 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) model->DIOmodName); } } + if(model->DIOforwardSWKneeCurrentGiven) { + if (model->DIOforwardSWKneeCurrent < ckt->CKTepsmin) { + model->DIOforwardSWKneeCurrentGiven = FALSE; + fprintf(stderr, "Warning: %s: IKP too small - model effect disabled!\n", + model->DIOmodName); + } + } if(!model->DIObrkdEmissionCoeffGiven) { model->DIObrkdEmissionCoeff = model->DIOemissionCoeff; } @@ -238,6 +245,24 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) } else { model->DIOconductance = 1/model->DIOresist; } + if((!model->DIOresistSWGiven) || (model->DIOresistSW==0)) { + if (newcompat.ps || newcompat.lt) { + double rsdiode = 0.; + /* to improve convergence (sometimes) */ + if (cp_getvar("diode_rser", CP_REAL, &rsdiode, 0) && rsdiode > 0) { + model->DIOconductanceSW = 1./rsdiode; + model->DIOresistSW = rsdiode; + if (ft_ngdebug) + fprintf(stderr, "Diode sidewall series resistance in model %s set to %e Ohm\n", model->gen.GENmodName, rsdiode); + } + else + model->DIOconductanceSW = 0.0; + } + else + model->DIOconductanceSW = 0.0; + } else { + model->DIOconductanceSW = 1/model->DIOresistSW; + } if (!model->DIOrth0Given) { model->DIOrth0 = 0; @@ -329,6 +354,7 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) } here->DIOforwardKneeCurrent = model->DIOforwardKneeCurrent * here->DIOarea * here->DIOm; here->DIOreverseKneeCurrent = model->DIOreverseKneeCurrent * here->DIOarea * here->DIOm; + here->DIOforwardSWKneeCurrent = model->DIOforwardSWKneeCurrent * here->DIOpj * here->DIOm; here->DIOjunctionCap = model->DIOjunctionCap * here->DIOarea * here->DIOm; here->DIOjunctionSWCap = model->DIOjunctionSWCap * here->DIOpj * here->DIOm; @@ -344,19 +370,41 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) } else if(here->DIOposPrimeNode == 0) { - CKTnode *tmpNode; - IFuid tmpName; + CKTnode *tmpNode; + IFuid tmpName; error = CKTmkVolt(ckt,&tmp,here->DIOname,"internal"); if(error) return(error); here->DIOposPrimeNode = tmp->number; if (ckt->CKTcopyNodesets) { - if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) { - if (tmpNode->nsGiven) { - tmp->nodeset=tmpNode->nodeset; - tmp->nsGiven=tmpNode->nsGiven; - } - } + if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) { + if (tmpNode->nsGiven) { + tmp->nodeset=tmpNode->nodeset; + tmp->nsGiven=tmpNode->nsGiven; + } + } + } + } + + if(!model->DIOresistSWGiven) { + + here->DIOposSwPrimeNode = here->DIOposPrimeNode; + + } else if(here->DIOposSwPrimeNode == 0) { + + CKTnode *tmpNode; + IFuid tmpName; + + error = CKTmkVolt(ckt,&tmp,here->DIOname,"internal_sw"); + if(error) return(error); + here->DIOposSwPrimeNode = tmp->number; + if (ckt->CKTcopyNodesets) { + if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) { + if (tmpNode->nsGiven) { + tmp->nodeset=tmpNode->nodeset; + tmp->nsGiven=tmpNode->nsGiven; + } + } } } @@ -375,6 +423,14 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ TSTALLOC(DIOposPosPtr,DIOposNode,DIOposNode); TSTALLOC(DIOnegNegPtr,DIOnegNode,DIOnegNode); TSTALLOC(DIOposPrimePosPrimePtr,DIOposPrimeNode,DIOposPrimeNode); + if(model->DIOresistSWGiven) { + /* separate sidewall */ + TSTALLOC(DIOposPosSwPrimePtr,DIOposNode,DIOposSwPrimeNode); + TSTALLOC(DIOnegPosSwPrimePtr,DIOnegNode,DIOposSwPrimeNode); + TSTALLOC(DIOposSwPrimePosPtr,DIOposSwPrimeNode,DIOposNode); + TSTALLOC(DIOposSwPrimeNegPtr,DIOposSwPrimeNode,DIOnegNode); + TSTALLOC(DIOposSwPrimePosSwPrimePtr,DIOposSwPrimeNode,DIOposSwPrimeNode); + } if (selfheat) { TSTALLOC(DIOtempPosPtr, DIOtempNode, DIOposNode); @@ -384,6 +440,11 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ TSTALLOC(DIOposTempPtr, DIOposNode, DIOtempNode); TSTALLOC(DIOposPrimeTempPtr, DIOposPrimeNode, DIOtempNode); TSTALLOC(DIOnegTempPtr, DIOnegNode, DIOtempNode); + if(model->DIOresistSWGiven) { + /* separate sidewall */ + TSTALLOC(DIOtempPosSwPrimePtr, DIOtempNode, DIOposSwPrimeNode); + TSTALLOC(DIOposSwPrimeTempPtr, DIOposSwPrimeNode, DIOtempNode); + } } } @@ -410,6 +471,15 @@ DIOunsetup( && here->DIOposPrimeNode != here->DIOposNode) CKTdltNNum(ckt, here->DIOposPrimeNode); here->DIOposPrimeNode = 0; + + if(model->DIOresistSWGiven) { + /* separate sidewall */ + if (here->DIOposSwPrimeNode > 0 + && here->DIOposSwPrimeNode != here->DIOposNode) + CKTdltNNum(ckt, here->DIOposSwPrimeNode); + here->DIOposSwPrimeNode = 0; + } + } } return OK; diff --git a/src/spicelib/devices/dio/diotemp.c b/src/spicelib/devices/dio/diotemp.c index 30a47405b..d39b03de4 100644 --- a/src/spicelib/devices/dio/diotemp.c +++ b/src/spicelib/devices/dio/diotemp.c @@ -29,6 +29,7 @@ void DIOtempUpdate(DIOmodel *inModel, DIOinstance *here, double Temp, CKTcircuit double dt; double factor; double tBreakdownVoltage; + double totalSatCur; double egfet1,arg1,fact1,pbfact1,pbo,gmaold,pboSW,gmaSWold; double fact2,pbfact,arg,egfet,gmanew,gmaSWnew; @@ -196,9 +197,14 @@ void DIOtempUpdate(DIOmodel *inModel, DIOinstance *here, double Temp, CKTcircuit here->DIOtDepSWCap=model->DIOdepletionSWcapCoeff* here->DIOtJctSWPot; /* and Vcrit */ - double totalSatCur = here->DIOtSatCur + here->DIOtSatSWCur; - here->DIOtVcrit = vte * log(vte/(CONSTroot2*totalSatCur)); - + totalSatCur = here->DIOtSatCur + here->DIOtSatSWCur; + if(model->DIOresistSWGiven) { + here->DIOtVcrit = vte * log(vte/(CONSTroot2*here->DIOtSatCur)); + here->DIOtVcritSW = vts * log(vts/(CONSTroot2*here->DIOtSatSWCur)); + } else { + here->DIOtVcrit = vte * log(vte/(CONSTroot2*totalSatCur)); + here->DIOtVcritSW = vts * log(vts/(CONSTroot2*here->DIOtSatSWCur)); + } /* and now to compute the breakdown voltage, again, using * temperature adjusted basic parameters */ if (model->DIObreakdownVoltageGiven){ @@ -253,6 +259,14 @@ void DIOtempUpdate(DIOmodel *inModel, DIOinstance *here, double Temp, CKTcircuit here->DIOtConductance_dT = -model->DIOconductance * here->DIOarea * here->DIOm * (model->DIOresistTemp1 + model->DIOresistTemp2 * dt) / (factor*factor); } + here->DIOtConductanceSW = model->DIOconductanceSW * here->DIOpj * here->DIOm; + if(model->DIOresistSWGiven && model->DIOresistSW!=0.0) { + factor = 1.0 + (model->DIOresistTemp1) * dt + + (model->DIOresistTemp2 * dt * dt); + here->DIOtConductanceSW = model->DIOconductanceSW * here->DIOpj * here->DIOm / factor; + here->DIOtConductanceSW_dT = -model->DIOconductanceSW * here->DIOpj * here->DIOm * + (model->DIOresistTemp1 + model->DIOresistTemp2 * dt) / (factor*factor); + } here->DIOtF2=exp((1+here->DIOtGradingCoeff)*xfc); here->DIOtF3=1-model->DIOdepletionCapCoeff* diff --git a/src/spicelib/devices/dio/diotrunc.c b/src/spicelib/devices/dio/diotrunc.c index 5c64086f9..b940528be 100644 --- a/src/spicelib/devices/dio/diotrunc.c +++ b/src/spicelib/devices/dio/diotrunc.c @@ -21,6 +21,7 @@ DIOtrunc(GENmodel *inModel, CKTcircuit *ckt, double *timeStep) for( ; model != NULL; model = DIOnextModel(model)) { for(here=DIOinstances(model);here!=NULL;here = DIOnextInstance(here)){ CKTterr(here->DIOcapCharge,ckt,timeStep); + if (model->DIOresistSWGiven) CKTterr(here->DIOcapChargeSW,ckt,timeStep); } } return(OK); From 96d055963197d4bb23143eef7546290fba443caf Mon Sep 17 00:00:00 2001 From: dwarning Date: Tue, 2 Dec 2025 20:35:43 +0100 Subject: [PATCH 081/161] This fixed #822 diode discontinuity problem Base recombination current appears in reverse and breakdown region too. --- src/spicelib/devices/dio/dioload.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/spicelib/devices/dio/dioload.c b/src/spicelib/devices/dio/dioload.c index b8590c155..d7243d5b1 100644 --- a/src/spicelib/devices/dio/dioload.c +++ b/src/spicelib/devices/dio/dioload.c @@ -54,7 +54,7 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) double vd, vdsw=0.0; /* current diode voltage */ double vdtemp; double vt; /* K t / Q */ - double vte, vtesw, vtetun, vtebrk; + double vte, vtesw, vtetun, vtebrk, vterec; int Check_dio=0, Check_dio_sw=0, Check_th; int error; int SenCond=0; /* sensitivity condition */ @@ -102,6 +102,7 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) vte = model->DIOemissionCoeff * vt; vtesw = model->DIOswEmissionCoeff * vt; vtebrk = model->DIObrkdEmissionCoeff * vt; + vterec = model->DIOrecEmissionCoeff*vt; gspr = here->DIOtConductance; gsprsw = here->DIOtConductanceSW; /* @@ -358,8 +359,7 @@ next1: cdsw_dT = csatsw_dT * (evd - 1) - csatsw * vd * evd / (vte * Temp); } if (model->DIOrecSatCurGiven) { /* recombination current */ - double vterec = model->DIOrecEmissionCoeff*vt; - evd_rec = exp(vd/(vterec)); + evd_rec = exp(vd/vterec); cdb_rec = here->DIOtRecSatCur*(evd_rec-1); gdb_rec = here->DIOtRecSatCur*evd_rec/vterec; cdb_rec_dT = here->DIOtRecSatCur_dT * (evd_rec - 1) @@ -383,7 +383,15 @@ next1: arg = 3*vte/(vd*CONSTe); arg = arg * arg * arg; darg_dT = 3 * arg / Temp; - cdb = -csat*(1+arg); + if (model->DIOrecSatCurGiven) { + evd_rec = exp((-3*vte)/vterec); + cdb_rec = here->DIOtRecSatCur*(evd_rec-1); + t1 = pow((1-(-3*vte)/here->DIOtJctPot), 2) + 0.005; + gen_fac = pow(t1, here->DIOtGradingCoeff/2); + cdb = -csat*(1+arg) + gen_fac*cdb_rec; + } else { + cdb = -csat*(1+arg); + } gdb = csat*3*arg/vd; cdb_dT = -csat_dT - (csat_dT*arg + csat*darg_dT); if ((model->DIOsatSWCurGiven)&&(!model->DIOswEmissionCoeffGiven)) { @@ -398,12 +406,20 @@ next1: evrev = exp(-(here->DIOtBrkdwnV+vd)/vtebrk); evrev_dT = (here->DIOtBrkdwnV+vd)*evrev/(vtebrk*Temp); - cdb = -csat*evrev; + if (model->DIOrecSatCurGiven) { + evd_rec = exp((-3*vte)/vterec); + cdb_rec = here->DIOtRecSatCur*(evd_rec-1); + t1 = pow((1-(-3*vte)/here->DIOtJctPot), 2) + 0.005; + gen_fac = pow(t1, here->DIOtGradingCoeff/2); + cdb = -csat*evrev + gen_fac*cdb_rec; + } else { + cdb = -csat*evrev; + } gdb = csat*evrev/vtebrk; cdb_dT = -(csat_dT*evrev + csat*evrev_dT); if ((model->DIOsatSWCurGiven) - &&(!model->DIOresistSWGiven) /* no breakdown for separate sidewall diode */ - &&(!model->DIOswEmissionCoeffGiven)) { + &&(!model->DIOswEmissionCoeffGiven) + &&(!model->DIOresistSWGiven)) { /* no breakdown for separate sidewall diode */ evrev = exp(-(here->DIOtBrkdwnV+vdsw)/vtebrk); evrev_dT = (here->DIOtBrkdwnV+vdsw)*evrev/(vtebrk*Temp); cdsw = -csatsw*evrev; From abdd936cb87d1f99291125d3da9379a69901ad75 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 3 Dec 2025 22:51:54 +0100 Subject: [PATCH 082/161] Add missing function prototypes --- src/include/ngspice/sharedspice.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/include/ngspice/sharedspice.h b/src/include/ngspice/sharedspice.h index 146b8bbe9..7f209555b 100644 --- a/src/include/ngspice/sharedspice.h +++ b/src/include/ngspice/sharedspice.h @@ -497,6 +497,19 @@ int ngSpice_nospinit(void); IMPEXP int ngSpice_nospiceinit(void); +/* Locking and unlocking the realloc of output vectors during simulation. May be set +during reading output vectors in the primary thread, while the simulation in the +background thread is moving on. */ +IMPEXP +int ngSpice_LockRealloc(void); + +IMPEXP +int ngSpice_UnlockRealloc(void); + +/* Reset ngspice as far as possible. */ +IMPEXP +int ngSpice_Reset(void); + #ifdef __cplusplus } #endif From f52749afa34e109b2fe73ed40ce0601fa512caad Mon Sep 17 00:00:00 2001 From: dwarning Date: Thu, 11 Dec 2025 10:43:07 +0100 Subject: [PATCH 083/161] Diode model level=2 (Fowler-Nordheim) is not supported. --- src/spicelib/devices/dio/diosetup.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/spicelib/devices/dio/diosetup.c b/src/spicelib/devices/dio/diosetup.c index 0b40b1b49..df9555be8 100644 --- a/src/spicelib/devices/dio/diosetup.c +++ b/src/spicelib/devices/dio/diosetup.c @@ -35,6 +35,10 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) if(!model->DIOlevelGiven) { model->DIOlevel = 1; + } else if (model->DIOlevel == 2) { + SPfrontEnd->IFerrorf(ERR_FATAL, + "%s: Diode model level 2 is not supported.", model->DIOmodName); + return(E_BADPARM); } if(!model->DIOemissionCoeffGiven) { model->DIOemissionCoeff = 1; From ac9ac548d69c16ef191380a899e45ca9053df204 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 19 Dec 2025 12:55:35 +0100 Subject: [PATCH 084/161] Update test description --- examples/transient-noise/noi-ring51-demo.cir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/transient-noise/noi-ring51-demo.cir b/examples/transient-noise/noi-ring51-demo.cir index 50d54eb42..415324c3d 100644 --- a/examples/transient-noise/noi-ring51-demo.cir +++ b/examples/transient-noise/noi-ring51-demo.cir @@ -1,5 +1,5 @@ * 51 stage Ring-Osc. BSIM3, transient noise -* will need 90 sec on a i7 860 with 4 threads +* will need 20 sec on a i9 9900K with 8 threads * for better noise analysis simulation time may be made larger than 200n * closes the loop between inverters xinv1 and xinv5 From 4958221e92f2e0007b288710c80ed6934a8e8f68 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 19 Dec 2025 12:56:11 +0100 Subject: [PATCH 085/161] Update comment to cktnumstates --- src/include/ngspice/cktdefs.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/include/ngspice/cktdefs.h b/src/include/ngspice/cktdefs.h index 60a07db02..0610b34b1 100644 --- a/src/include/ngspice/cktdefs.h +++ b/src/include/ngspice/cktdefs.h @@ -161,8 +161,7 @@ struct CKTcircuit { /* This define should be somewhere else ??? */ #define NODENAME(ckt,nodenum) CKTnodName(ckt,nodenum) - int CKTnumStates; /* Number of sates effectively valid - ??? */ + int CKTnumStates; /* Number of states summed up over all device instances */ long CKTmode; /* Mode of operation of the circuit ??? */ From eea3af64e28d8289ecc401ba15e9ed4e62dcc04e Mon Sep 17 00:00:00 2001 From: dwarning Date: Fri, 19 Dec 2025 14:07:47 +0100 Subject: [PATCH 086/161] KLU bindings for separate sw diode only if sw resistor is given --- src/spicelib/devices/dio/diobindCSC.c | 66 ++++++++++++++++----------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/src/spicelib/devices/dio/diobindCSC.c b/src/spicelib/devices/dio/diobindCSC.c index a5df3db3d..29cee9cff 100644 --- a/src/spicelib/devices/dio/diobindCSC.c +++ b/src/spicelib/devices/dio/diobindCSC.c @@ -32,12 +32,14 @@ DIObindCSC (GENmodel *inModel, CKTcircuit *ckt) CREATE_KLU_BINDING_TABLE(DIOposPosPtr, DIOposPosBinding, DIOposNode, DIOposNode); CREATE_KLU_BINDING_TABLE(DIOnegNegPtr, DIOnegNegBinding, DIOnegNode, DIOnegNode); CREATE_KLU_BINDING_TABLE(DIOposPrimePosPrimePtr, DIOposPrimePosPrimeBinding, DIOposPrimeNode, DIOposPrimeNode); - /* separate sidewall */ - CREATE_KLU_BINDING_TABLE(DIOposPosSwPrimePtr,DIOposPosSwPrimeBinding,DIOposNode,DIOposSwPrimeNode); - CREATE_KLU_BINDING_TABLE(DIOnegPosSwPrimePtr,DIOnegPosSwPrimeBinding,DIOnegNode,DIOposSwPrimeNode); - CREATE_KLU_BINDING_TABLE(DIOposSwPrimePosPtr,DIOposSwPrimePosBinding,DIOposSwPrimeNode,DIOposNode); - CREATE_KLU_BINDING_TABLE(DIOposSwPrimeNegPtr,DIOposSwPrimeNegBinding,DIOposSwPrimeNode,DIOnegNode); - CREATE_KLU_BINDING_TABLE(DIOposSwPrimePosSwPrimePtr,DIOposSwPrimePosSwPrimeBinding,DIOposSwPrimeNode,DIOposSwPrimeNode); + if(model->DIOresistSWGiven) { + /* separate sidewall */ + CREATE_KLU_BINDING_TABLE(DIOposPosSwPrimePtr,DIOposPosSwPrimeBinding,DIOposNode,DIOposSwPrimeNode); + CREATE_KLU_BINDING_TABLE(DIOnegPosSwPrimePtr,DIOnegPosSwPrimeBinding,DIOnegNode,DIOposSwPrimeNode); + CREATE_KLU_BINDING_TABLE(DIOposSwPrimePosPtr,DIOposSwPrimePosBinding,DIOposSwPrimeNode,DIOposNode); + CREATE_KLU_BINDING_TABLE(DIOposSwPrimeNegPtr,DIOposSwPrimeNegBinding,DIOposSwPrimeNode,DIOnegNode); + CREATE_KLU_BINDING_TABLE(DIOposSwPrimePosSwPrimePtr,DIOposSwPrimePosSwPrimeBinding,DIOposSwPrimeNode,DIOposSwPrimeNode); + } if ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given)) { CREATE_KLU_BINDING_TABLE(DIOtempPosPtr, DIOtempPosBinding, DIOtempNode, DIOposNode); CREATE_KLU_BINDING_TABLE(DIOtempPosPrimePtr, DIOtempPosPrimeBinding, DIOtempNode, DIOposPrimeNode); @@ -46,9 +48,11 @@ DIObindCSC (GENmodel *inModel, CKTcircuit *ckt) CREATE_KLU_BINDING_TABLE(DIOposTempPtr, DIOposTempBinding, DIOposNode, DIOtempNode); CREATE_KLU_BINDING_TABLE(DIOposPrimeTempPtr, DIOposPrimeTempBinding, DIOposPrimeNode, DIOtempNode); CREATE_KLU_BINDING_TABLE(DIOnegTempPtr, DIOnegTempBinding, DIOnegNode, DIOtempNode); - /* separate sidewall */ - CREATE_KLU_BINDING_TABLE(DIOtempPosSwPrimePtr, DIOtempPosSwPrimeBinding, DIOtempNode, DIOposSwPrimeNode); - CREATE_KLU_BINDING_TABLE(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode); + if(model->DIOresistSWGiven) { + /* separate sidewall */ + CREATE_KLU_BINDING_TABLE(DIOtempPosSwPrimePtr, DIOtempPosSwPrimeBinding, DIOtempNode, DIOposSwPrimeNode); + CREATE_KLU_BINDING_TABLE(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode); + } } } } @@ -77,12 +81,14 @@ DIObindCSCComplex (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposPosPtr, DIOposPosBinding, DIOposNode, DIOposNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOnegNegPtr, DIOnegNegBinding, DIOnegNode, DIOnegNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposPrimePosPrimePtr, DIOposPrimePosPrimeBinding, DIOposPrimeNode, DIOposPrimeNode); - /* separate sidewall */ - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposPosSwPrimePtr,DIOposPosSwPrimeBinding,DIOposNode,DIOposSwPrimeNode); - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOnegPosSwPrimePtr,DIOnegPosSwPrimeBinding,DIOnegNode,DIOposSwPrimeNode); - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimePosPtr,DIOposSwPrimePosBinding,DIOposSwPrimeNode,DIOposNode); - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimeNegPtr,DIOposSwPrimeNegBinding,DIOposSwPrimeNode,DIOnegNode); - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimePosSwPrimePtr,DIOposSwPrimePosSwPrimeBinding,DIOposSwPrimeNode,DIOposSwPrimeNode); + if(model->DIOresistSWGiven) { + /* separate sidewall */ + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposPosSwPrimePtr,DIOposPosSwPrimeBinding,DIOposNode,DIOposSwPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOnegPosSwPrimePtr,DIOnegPosSwPrimeBinding,DIOnegNode,DIOposSwPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimePosPtr,DIOposSwPrimePosBinding,DIOposSwPrimeNode,DIOposNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimeNegPtr,DIOposSwPrimeNegBinding,DIOposSwPrimeNode,DIOnegNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimePosSwPrimePtr,DIOposSwPrimePosSwPrimeBinding,DIOposSwPrimeNode,DIOposSwPrimeNode); + } if ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given)) { CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOtempPosPtr, DIOtempPosBinding, DIOtempNode, DIOposNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOtempPosPrimePtr, DIOtempPosPrimeBinding, DIOtempNode, DIOposPrimeNode); @@ -91,9 +97,11 @@ DIObindCSCComplex (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposTempPtr, DIOposTempBinding, DIOposNode, DIOtempNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposPrimeTempPtr, DIOposPrimeTempBinding, DIOposPrimeNode, DIOtempNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOnegTempPtr, DIOnegTempBinding, DIOnegNode, DIOtempNode); - /* separate sidewall */ - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOtempPosSwPrimePtr, DIOtempPosSwPrimeBinding, DIOtempNode, DIOposSwPrimeNode); - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode); + if(model->DIOresistSWGiven) { + /* separate sidewall */ + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOtempPosSwPrimePtr, DIOtempPosSwPrimeBinding, DIOtempNode, DIOposSwPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode); + } } } } @@ -122,12 +130,14 @@ DIObindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposPosPtr, DIOposPosBinding, DIOposNode, DIOposNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOnegNegPtr, DIOnegNegBinding, DIOnegNode, DIOnegNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposPrimePosPrimePtr, DIOposPrimePosPrimeBinding, DIOposPrimeNode, DIOposPrimeNode); - /* separate sidewall */ - CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposPosSwPrimePtr,DIOposPosSwPrimeBinding,DIOposNode,DIOposSwPrimeNode); - CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOnegPosSwPrimePtr,DIOnegPosSwPrimeBinding,DIOnegNode,DIOposSwPrimeNode); - CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimePosPtr,DIOposSwPrimePosBinding,DIOposSwPrimeNode,DIOposNode); - CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimeNegPtr,DIOposSwPrimeNegBinding,DIOposSwPrimeNode,DIOnegNode); - CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimePosSwPrimePtr,DIOposSwPrimePosSwPrimeBinding,DIOposSwPrimeNode,DIOposSwPrimeNode); + if(model->DIOresistSWGiven) { + /* separate sidewall */ + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposPosSwPrimePtr,DIOposPosSwPrimeBinding,DIOposNode,DIOposSwPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOnegPosSwPrimePtr,DIOnegPosSwPrimeBinding,DIOnegNode,DIOposSwPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimePosPtr,DIOposSwPrimePosBinding,DIOposSwPrimeNode,DIOposNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimeNegPtr,DIOposSwPrimeNegBinding,DIOposSwPrimeNode,DIOnegNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimePosSwPrimePtr,DIOposSwPrimePosSwPrimeBinding,DIOposSwPrimeNode,DIOposSwPrimeNode); + } if ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given)) { CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOtempPosPtr, DIOtempPosBinding, DIOtempNode, DIOposNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOtempPosPrimePtr, DIOtempPosPrimeBinding, DIOtempNode, DIOposPrimeNode); @@ -136,9 +146,11 @@ DIObindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposTempPtr, DIOposTempBinding, DIOposNode, DIOtempNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposPrimeTempPtr, DIOposPrimeTempBinding, DIOposPrimeNode, DIOtempNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOnegTempPtr, DIOnegTempBinding, DIOnegNode, DIOtempNode); - /* separate sidewall */ - CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOtempPosSwPrimePtr, DIOtempPosSwPrimeBinding, DIOtempNode, DIOposSwPrimeNode); - CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode); + if(model->DIOresistSWGiven) { + /* separate sidewall */ + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOtempPosSwPrimePtr, DIOtempPosSwPrimeBinding, DIOtempNode, DIOposSwPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode); + } } } } From f2ef953246e4d0025d4d344298d5c33ab8e9c39b Mon Sep 17 00:00:00 2001 From: dwarning Date: Fri, 19 Dec 2025 17:03:08 +0100 Subject: [PATCH 087/161] Fix the overlap in state vector for sensitivity states of diode and bjt model. --- src/spicelib/devices/bjt/bjtdefs.h | 10 +++++----- src/spicelib/devices/dio/diodefs.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/spicelib/devices/bjt/bjtdefs.h b/src/spicelib/devices/bjt/bjtdefs.h index a25cf9f51..e2c7b2fbf 100644 --- a/src/spicelib/devices/bjt/bjtdefs.h +++ b/src/spicelib/devices/bjt/bjtdefs.h @@ -380,12 +380,12 @@ typedef struct sBJTinstance { #define BJTnumStates 33 -#define BJTsensxpbe BJTstate+24 /* charge sensitivities and their - derivatives. +25 for the derivatives - +#define BJTsensxpbe BJTstate+33 /* charge sensitivities and their + derivatives. +34 for the derivatives - pointer to the beginning of the array */ -#define BJTsensxpbc BJTstate+26 -#define BJTsensxpsub BJTstate+28 -#define BJTsensxpbx BJTstate+30 +#define BJTsensxpbc BJTstate+35 +#define BJTsensxpsub BJTstate+37 +#define BJTsensxpbx BJTstate+39 #define BJTnumSenStates 8 diff --git a/src/spicelib/devices/dio/diodefs.h b/src/spicelib/devices/dio/diodefs.h index 836475538..298f330b9 100644 --- a/src/spicelib/devices/dio/diodefs.h +++ b/src/spicelib/devices/dio/diodefs.h @@ -265,8 +265,8 @@ typedef struct sDIOinstance { #define DIOnumStates 15 -#define DIOsensxp DIOstate+12 /* charge sensitivities and their derivatives. - * +10 for the derivatives - pointer to the +#define DIOsensxp DIOstate+15 /* charge sensitivities and their derivatives. + * +16 for the derivatives - pointer to the * beginning of the array */ #define DIOnumSenStates 2 From 89a25ac6c197246b9f92dd4650205e3d20cbb190 Mon Sep 17 00:00:00 2001 From: dwarning Date: Fri, 19 Dec 2025 18:20:25 +0100 Subject: [PATCH 088/161] Diode sensitivity analysis: Exclude few parameters and add level 3 geometry parameter. --- src/spicelib/devices/dio/dio.c | 18 +++++++++--------- src/spicelib/devices/dio/dioask.c | 12 ++++++++++++ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/spicelib/devices/dio/dio.c b/src/spicelib/devices/dio/dio.c index 8814c5a1a..2ebeb2e41 100644 --- a/src/spicelib/devices/dio/dio.c +++ b/src/spicelib/devices/dio/dio.c @@ -52,10 +52,10 @@ IFparm DIOmPTable[] = { /* model parameters */ IOP( "jsw", DIO_MOD_JSW, IF_REAL, "Sidewall Saturation current"), IOPR( "isw", DIO_MOD_JSW, IF_REAL, "Sidewall Saturation current"), - IOPU( "tnom",DIO_MOD_TNOM,IF_REAL, "Parameter measurement temperature"), + IOPXU( "tnom",DIO_MOD_TNOM,IF_REAL, "Parameter measurement temperature"), IOPUR("tref",DIO_MOD_TNOM,IF_REAL, "Parameter measurement temperature"), IOP( "rs", DIO_MOD_RS, IF_REAL, "Ohmic resistance"), - IOP( "rsw", DIO_MOD_RSW, IF_REAL, "Ohmic resistance sidewall"), + IOPX( "rsw", DIO_MOD_RSW, IF_REAL, "Ohmic resistance sidewall"), IOP( "trs", DIO_MOD_TRS, IF_REAL, "Ohmic resistance 1st order temp. coeff."), IOPR( "trs1", DIO_MOD_TRS, IF_REAL, "Ohmic resistance 1st order temp. coeff."), IOP( "trs2", DIO_MOD_TRS2, IF_REAL, "Ohmic resistance 2nd order temp. coeff."), @@ -124,15 +124,15 @@ IFparm DIOmPTable[] = { /* model parameters */ IOP( "nr", DIO_MOD_NR, IF_REAL, "Recombination current emission coefficient"), /* SOA parameters */ - IOP( "fv_max", DIO_MOD_FV_MAX, IF_REAL, "maximum voltage in forward direction"), - IOP( "bv_max", DIO_MOD_BV_MAX, IF_REAL, "maximum voltage in reverse direction"), - IOP( "id_max", DIO_MOD_ID_MAX, IF_REAL, "maximum current"), - IOP( "te_max", DIO_MOD_TE_MAX, IF_REAL, "temperature"), - IOP( "pd_max", DIO_MOD_PD_MAX, IF_REAL, "maximum power dissipation"), + IOPX( "fv_max", DIO_MOD_FV_MAX, IF_REAL, "maximum voltage in forward direction"), + IOPX( "bv_max", DIO_MOD_BV_MAX, IF_REAL, "maximum voltage in reverse direction"), + IOPX( "id_max", DIO_MOD_ID_MAX, IF_REAL, "maximum current"), + IOPX( "te_max", DIO_MOD_TE_MAX, IF_REAL, "temperature"), + IOPX( "pd_max", DIO_MOD_PD_MAX, IF_REAL, "maximum power dissipation"), /* self heating */ - IOP("rth0", DIO_MOD_RTH0, IF_REAL, "Self-heating thermal resistance"), - IOP("cth0", DIO_MOD_CTH0, IF_REAL, "Self-heating thermal capacitance"), + IOPX("rth0", DIO_MOD_RTH0, IF_REAL, "Self-heating thermal resistance"), + IOPX("cth0", DIO_MOD_CTH0, IF_REAL, "Self-heating thermal capacitance"), /* scaled parasitic capacitances level 3 model */ IOP( "lm", DIO_MOD_LM, IF_REAL, "Length of metal capacitor (level=3)"), IOP( "lp", DIO_MOD_LP, IF_REAL, "Length of polysilicon capacitor (level=3)"), diff --git a/src/spicelib/devices/dio/dioask.c b/src/spicelib/devices/dio/dioask.c index 5d3a7374b..67009b889 100644 --- a/src/spicelib/devices/dio/dioask.c +++ b/src/spicelib/devices/dio/dioask.c @@ -48,6 +48,18 @@ DIOask (CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value, case DIO_M: value->rValue = here->DIOm; return(OK); + case DIO_LM: + value->rValue = here->DIOlengthMetal; + return(OK); + case DIO_LP: + value->rValue = here->DIOlengthPoly; + return(OK); + case DIO_WM: + value->rValue = here->DIOwidthMetal; + return(OK); + case DIO_WP: + value->rValue = here->DIOwidthPoly; + return(OK); case DIO_THERMAL: value->iValue = here->DIOthermal; return(OK); From 66797fdebc0f557a70f375e976c081d619c8e6bd Mon Sep 17 00:00:00 2001 From: lorenzo Date: Sat, 20 Dec 2025 11:31:24 +0100 Subject: [PATCH 089/161] Fixes a memory corruption bug resulting from improper parsing and accessing of array parameters in OSDI models --- src/osdi/osdiparam.c | 12 +++++++----- src/spicelib/devices/dev.c | 6 +++--- src/spicelib/parser/inpgmod.c | 11 +++++++++++ 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/osdi/osdiparam.c b/src/osdi/osdiparam.c index f4664629d..a129ea9d0 100644 --- a/src/osdi/osdiparam.c +++ b/src/osdi/osdiparam.c @@ -27,7 +27,7 @@ static int osdi_param_access(OsdiParamOpvar *param_info, bool write_value, len = sizeof(double); if (param_info->len) { len *= param_info->len; - val_ptr = &value->v.vec.rVec; + val_ptr = value->v.vec.rVec; } else { val_ptr = &value->rValue; } @@ -36,7 +36,7 @@ static int osdi_param_access(OsdiParamOpvar *param_info, bool write_value, len = sizeof(int); if (param_info->len) { len *= param_info->len; - val_ptr = &value->v.vec.iVec; + val_ptr = value->v.vec.iVec; } else { val_ptr = &value->iValue; } @@ -45,7 +45,7 @@ static int osdi_param_access(OsdiParamOpvar *param_info, bool write_value, len = sizeof(char *); if (param_info->len) { len *= param_info->len; - val_ptr = &value->v.vec.cVec; + val_ptr = value->v.vec.cVec; } else { val_ptr = &value->cValue; } @@ -64,7 +64,9 @@ static int osdi_param_access(OsdiParamOpvar *param_info, bool write_value, static int osdi_write_param(void *dst, IFvalue *value, int param, const OsdiDescriptor *descr) { - if (dst == NULL) { + // value may be NULL as a result of a bad parse from INPgetValue + // catch it before dereferencing it + if (dst == NULL || value == NULL) { return (E_PANIC); } @@ -127,7 +129,7 @@ extern int OSDImParam(int param, IFvalue *value, GENmodel *modelPtr) { static int osdi_read_param(void *src, IFvalue *value, int id, const OsdiDescriptor *descr) { - if (src == NULL) { + if (src == NULL || value == NULL) { return (E_PANIC); } diff --git a/src/spicelib/devices/dev.c b/src/spicelib/devices/dev.c index 7b5268835..3e07b1beb 100644 --- a/src/spicelib/devices/dev.c +++ b/src/spicelib/devices/dev.c @@ -583,10 +583,10 @@ static int osdi_add_device(int n, OsdiRegistryEntry *devs) { DEVicesfl = TREALLOC(int, DEVicesfl, dnum); #endif for (i = 0; i < n; i++) { -#ifdef TRACE - printf("Added device: %s\n", devs[i]->DEVpublic.name); -#endif DEVices[DEVNUM + i] = osdi_create_spicedev(&devs[i]); +#ifdef TRACE + printf("Added device: %s\n", DEVices[DEVNUM + i]->DEVpublic.name); +#endif } DEVNUM += n; relink(); diff --git a/src/spicelib/parser/inpgmod.c b/src/spicelib/parser/inpgmod.c index 64c402d7e..ac3293b45 100644 --- a/src/spicelib/parser/inpgmod.c +++ b/src/spicelib/parser/inpgmod.c @@ -117,9 +117,11 @@ create_model(CKTcircuit *ckt, INPmodel *modtmp, INPtables *tab) #ifdef OSDI /* osdi models don't accept their device type as an argument */ + bool is_osdi = false; if (device->registry_entry){ INPgetNetTok(&line, &parm, 1); /* throw away osdi */ tfree(parm); + is_osdi = true; } #endif @@ -133,6 +135,15 @@ create_model(CKTcircuit *ckt, INPmodel *modtmp, INPtables *tab) IFparm *p = find_model_parameter(parm, device); if (p) { +#ifdef OSDI + if (is_osdi && (p->dataType & IF_VECTOR)){ + // we need to get rid if the leading [ in order to make sure + // that INPgetValue can parse the value properly + // This is because, unlike other SPICEDev, OSDI models receive + // array params in the syntax (param_name=[...]) + ++line; + } +#endif IFvalue *val = INPgetValue(ckt, &line, p->dataType, tab); error = ft_sim->setModelParm(ckt, modtmp->INPmodfast, p->id, val, NULL); if (error) From 50c4272544486bfd66b0a7bb766e47a99e42e192 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Thu, 25 Dec 2025 10:20:20 -0800 Subject: [PATCH 090/161] Add function to verify that subckt port directions are compatible with auto bridging. Use set ps_ports_and_pins=1 to see the port directions. --- src/frontend/udevices.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/frontend/udevices.c b/src/frontend/udevices.c index c2f14ec47..9368ca68d 100644 --- a/src/frontend/udevices.c +++ b/src/frontend/udevices.c @@ -1053,6 +1053,36 @@ void initialize_udevice(char *subckt_line) add_drive_hilo = FALSE; } +static void determine_port_type(void) +{ + bool inp = FALSE, outp = FALSE, tri = FALSE; + char *port_type = NULL; + NAME_ENTRY x = NULL; + + for (x = port_names_list; x; x = x->next) { + inp = (find_name_entry(x->name, input_names_list) ? TRUE : FALSE); + outp = (find_name_entry(x->name, output_names_list) ? TRUE : FALSE); + tri = (find_name_entry(x->name, tristate_names_list) ? TRUE : FALSE); + port_type = "UNKNOWN"; + if (tri) { + if (outp && inp) { + port_type = "INOUT"; + } else if (outp) { + port_type = "OUT"; + } + } else { + if (outp && inp) { + port_type = "OUT"; + } else if (outp) { + port_type = "OUT"; + } else if (inp) { + port_type = "IN"; + } + } + printf("* port: %s %s\n", x->name, port_type); + } +} + void cleanup_udevice(bool global) { if (global) { @@ -1068,6 +1098,9 @@ void cleanup_udevice(bool global) xsubckt_names_list = NULL; return; } + + if (ps_ports_and_pins & 1) determine_port_type(); + cleanup_translated_xlator(); delete_xlator(model_xlatorp); model_xlatorp = NULL; From ab49ea9657f4cfd0a71ce316f2ff9d3048fffd18 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 27 Dec 2025 15:33:29 +0100 Subject: [PATCH 091/161] Fix tiny bug. --- src/spicelib/analysis/optran.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spicelib/analysis/optran.c b/src/spicelib/analysis/optran.c index 0ba875d97..86dceab55 100644 --- a/src/spicelib/analysis/optran.c +++ b/src/spicelib/analysis/optran.c @@ -181,7 +181,7 @@ void com_optran(wordlist* wl) { /* optran deselected by setting opstepsize to 0 */ if (opstepsize == 0) { nooptran = TRUE; - fprintf(stdout, "Note: Optran is deselected"); + fprintf(stdout, "Note: Optran is deselected.\n"); } dataset = TRUE; From fe55cbe69f05b94318f7ce54eafa661c91bd4999 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 27 Dec 2025 15:33:11 +0100 Subject: [PATCH 092/161] Enable optional voltage based truncation error correction. This is selectable as 'option newtrunc' (--enable-Predictor is required) Remove --enable-NEWTRUNC Add three option parameters (default): lteTrtol (500), lteReltol (1e-3), lteAbstol (1e-6) Add new error function for TRAP, similar to GEAR (tentative, to be improved), in ckttrun.c Enable PREDICTOR as default with Visual Studio. --- configure.ac | 8 - src/frontend/com_option.c | 17 +- src/frontend/misccoms.c | 3 - src/include/ngspice/cktdefs.h | 9 +- src/include/ngspice/optdefs.h | 4 + src/include/ngspice/tskdefs.h | 4 +- src/spicelib/analysis/cktdojob.c | 7 +- src/spicelib/analysis/cktntask.c | 11 +- src/spicelib/analysis/cktsopt.c | 28 ++- src/spicelib/analysis/ckttrunc.c | 280 +++++++++++++++----------- src/spicelib/devices/devsup.c | 15 +- src/xspice/icm/analog/delay/cfunc.mod | 9 +- visualc/src/include/ngspice/config.h | 5 +- 13 files changed, 229 insertions(+), 171 deletions(-) diff --git a/configure.ac b/configure.ac index 94f8bf640..0132c507d 100644 --- a/configure.ac +++ b/configure.ac @@ -229,10 +229,6 @@ AC_ARG_ENABLE([predictor], AC_ARG_ENABLE([newpred], [AS_HELP_STRING([--enable-newpred], [Enable NEWPRED whatever it is(?)])]) -# --enable-newtrunc: define NEWTRUNC for the code -AC_ARG_ENABLE([newtrunc], - [AS_HELP_STRING([--enable-newtrunc], [Enable, how we want extrapolate capacitances.])]) - # --enable-sense2: define WANT_SENSE2 for the code AC_ARG_ENABLE([sense2], [AS_HELP_STRING([--enable-sense2], [Use spice2 sensitivity analysis.])]) @@ -1044,10 +1040,6 @@ if test "x$enable_newpred" = xyes; then AC_DEFINE([NEWPRED], [], [Define if you want to discover :)]) AC_MSG_RESULT([NEWPRED enabled]) fi -if test "x$enable_newtrunc" = xyes; then - AC_DEFINE([NEWTRUNC], [], [Do not trigger unwanted traps by default]) - AC_MSG_RESULT([New truncation error calculation enabled]) -fi if test "x$enable_experimental" = xyes; then AC_DEFINE([EXPERIMENTAL_CODE], [], [Define if we want some experimental code]) AC_MSG_RESULT([EXPERIMENTAL_CODE enabled]) diff --git a/src/frontend/com_option.c b/src/frontend/com_option.c index 5ded8146e..9e9dad477 100644 --- a/src/frontend/com_option.c +++ b/src/frontend/com_option.c @@ -77,13 +77,16 @@ com_option(wordlist *wl) printf("gminsteps = %d\n", circuit->CKTnumGminSteps); printf("srcsteps = %d\n", circuit->CKTnumSrcSteps); - printf("\nTruncation error correction:\n"); - printf("trtol = %f\n", circuit->CKTtrtol); -#ifdef NEWTRUNC - printf("ltereltol = %g\n", circuit->CKTlteReltol); - printf("lteabstol = %g\n", circuit->CKTlteAbstol); -#endif /* NEWTRUNC */ - + if (circuit->CKTnewtrunc) { + printf("\nTruncation error correction, voltage based, is selected:\n"); + printf("ltereltol = %g\n", circuit->CKTlteReltol); + printf("lteabstol = %g\n", circuit->CKTlteAbstol); + printf("ltetrtol = %g\n", circuit->CKTlteTrtol); + } + else { + printf("\nTruncation error correction, charge based, is selected:\n"); + printf("trtol = %f\n", circuit->CKTtrtol); + } printf("\nConductances:\n"); printf("gmin (devices) = %g\n", circuit->CKTgmin); printf("diaggmin (stepping) = %g\n", circuit->CKTdiagGmin); diff --git a/src/frontend/misccoms.c b/src/frontend/misccoms.c index b53a7c1e8..c3efbb9cb 100644 --- a/src/frontend/misccoms.c +++ b/src/frontend/misccoms.c @@ -274,9 +274,6 @@ com_version(wordlist *wl) #ifdef PREDICTOR fprintf(cp_out, "** --enable-predictor\n"); #endif -#ifdef NEWTRUNC - fprintf(cp_out, "** --enable-newtrunc\n"); -#endif #ifdef WANT_SENSE2 fprintf(cp_out, "** --enable-sense2\n"); #endif diff --git a/src/include/ngspice/cktdefs.h b/src/include/ngspice/cktdefs.h index 0610b34b1..c12bf91cf 100644 --- a/src/include/ngspice/cktdefs.h +++ b/src/include/ngspice/cktdefs.h @@ -216,11 +216,10 @@ struct CKTcircuit { double CKTreltol; /* --- */ double CKTchgtol; /* --- */ double CKTvoltTol; /* --- */ - /* What is this define for ? */ -#ifdef NEWTRUNC - double CKTlteReltol; - double CKTlteAbstol; -#endif /* NEWTRUNC */ + double CKTlteReltol; /* relative error in voltage based truncation error estimation */ + double CKTlteAbstol; /* absolute error in voltage based truncation error estimation */ + double CKTlteTrtol; /* scaling time step in voltage based truncation error estimation */ + int CKTnewtrunc; /* enable lte (local truncation error) based on voltages */ double CKTgmin; /* .options GMIN */ double CKTgshunt; /* .options RSHUNT */ double CKTcshunt; /* .options CSHUNT */ diff --git a/src/include/ngspice/optdefs.h b/src/include/ngspice/optdefs.h index 3455a2454..25d61eebd 100644 --- a/src/include/ngspice/optdefs.h +++ b/src/include/ngspice/optdefs.h @@ -132,6 +132,10 @@ enum { OPT_KLU_MEMGROW_FACTOR, #endif + OPT_LTERELTOL, + OPT_LTEABSTOL, + OPT_LTETRTOL, + OPT_NEWTRUNC, }; #ifdef XSPICE diff --git a/src/include/ngspice/tskdefs.h b/src/include/ngspice/tskdefs.h index 9d59bd4b4..f59ccec9b 100644 --- a/src/include/ngspice/tskdefs.h +++ b/src/include/ngspice/tskdefs.h @@ -48,10 +48,10 @@ struct TSKtask { double TSKreltol; double TSKchgtol; double TSKvoltTol; -#ifdef NEWTRUNC double TSKlteReltol; double TSKlteAbstol; -#endif /* NEWTRUNC */ + double TSKlteTrtol; + unsigned int TSKnewtrunc:1; /* voltage controlled truncation */ double TSKgmin; double TSKgshunt; /* shunt conductance (CKTdiagGmin) */ double TSKcshunt; /* shunt capacitor to ground */ diff --git a/src/spicelib/analysis/cktdojob.c b/src/spicelib/analysis/cktdojob.c index 627626a2e..b78ca5ff6 100644 --- a/src/spicelib/analysis/cktdojob.c +++ b/src/spicelib/analysis/cktdojob.c @@ -114,14 +114,17 @@ CKTdoJob(CKTcircuit* ckt, int reset, TSKtask* task) ckt->CKTkluMemGrowFactor = task->TSKkluMemGrowFactor ; #endif -#ifdef NEWTRUNC ckt->CKTlteReltol = task->TSKlteReltol; ckt->CKTlteAbstol = task->TSKlteAbstol; -#endif /* NEWTRUNC */ + ckt->CKTlteTrtol = task->TSKlteTrtol; + ckt->CKTnewtrunc = task->TSKnewtrunc; fprintf(stdout, "Doing analysis at TEMP = %f and TNOM = %f\n\n", ckt->CKTtemp - CONSTCtoK, ckt->CKTnomTemp - CONSTCtoK); + if (ckt->CKTnewtrunc) + fprintf(stdout, "Note: Voltage based truncation error correction selected\n"); + /* call altermod and alter on device and model parameters assembled in devtlist and modtlist (if using temper) because we have a new temperature */ inp_evaluate_temper(ft_curckt); diff --git a/src/spicelib/analysis/cktntask.c b/src/spicelib/analysis/cktntask.c index be681b2b6..e143798cf 100644 --- a/src/spicelib/analysis/cktntask.c +++ b/src/spicelib/analysis/cktntask.c @@ -82,11 +82,10 @@ CKTnewTask(CKTcircuit *ckt, TSKtask **taskPtr, IFuid taskName, TSKtask **defPtr) tsk->TSKkluMemGrowFactor = def->TSKkluMemGrowFactor ; #endif -#ifdef NEWTRUNC tsk->TSKlteReltol = def->TSKlteReltol; tsk->TSKlteAbstol = def->TSKlteAbstol; -#endif - + tsk->TSKlteTrtol = def->TSKlteTrtol; + tsk->TSKnewtrunc = def->TSKnewtrunc; } else { #endif /*CDHW*/ @@ -98,11 +97,11 @@ CKTnewTask(CKTcircuit *ckt, TSKtask **taskPtr, IFuid taskName, TSKtask **defPtr) tsk->TSKreltol = 1e-3; tsk->TSKchgtol = 1e-14; tsk->TSKvoltTol = 1e-6; -#ifdef NEWTRUNC tsk->TSKlteReltol = 1e-3; tsk->TSKlteAbstol = 1e-6; -#endif - tsk->TSKtrtol = 7; + tsk->TSKlteTrtol = 500.; + tsk->TSKnewtrunc = 0; + tsk->TSKtrtol = 7.; tsk->TSKbypass = 0; tsk->TSKtranMaxIter = 10; tsk->TSKdcMaxIter = 100; diff --git a/src/spicelib/analysis/cktsopt.c b/src/spicelib/analysis/cktsopt.c index 0c1f723e1..8a1e60b30 100644 --- a/src/spicelib/analysis/cktsopt.c +++ b/src/spicelib/analysis/cktsopt.c @@ -187,7 +187,24 @@ CKTsetOpt(CKTcircuit *ckt, JOB *anal, int opt, IFvalue *val) task->TSKkluMemGrowFactor = (val->rValue == 1.2); break; #endif - + case OPT_LTERELTOL: + task->TSKlteReltol = val->rValue; + break; + case OPT_LTEABSTOL: + task->TSKlteAbstol = val->rValue; + break; + case OPT_LTETRTOL: + task->TSKlteTrtol = val->rValue; + break; + case OPT_NEWTRUNC: +#ifdef PREDICTOR + task->TSKnewtrunc = (val->iValue != 0); +#else + task->TSKnewtrunc = 0; + fprintf(stderr, "Warning: Option 'newtrunc' ignored,\n" + " compilation with preprocessor flag 'PREDICTOR' is required.\n"); +#endif + break; /* gtri - begin - wbk - add new options */ #ifdef XSPICE case OPT_EVT_MAX_OP_ALTER: @@ -230,7 +247,7 @@ CKTsetOpt(CKTcircuit *ckt, JOB *anal, int opt, IFvalue *val) ckt->enh->rshunt_data.gshunt = 1.0 / val->rValue; } else { - printf("WARNING - Rshunt option too small. Ignored.\n"); + fprintf(stderr, "WARNING - Rshunt option too small. Ignored.\n"); } break; #endif @@ -353,9 +370,14 @@ static IFparm OPTtbl[] = { { "klu", OPT_KLU, IF_SET|IF_FLAG, "Set KLU as Direct Linear Solver" }, { "klu_memgrow_factor", OPT_KLU_MEMGROW_FACTOR, IF_SET|IF_REAL, - "KLU Memory Grow Factor (default is 1.2)" } + "KLU Memory Grow Factor (default is 1.2)" }, #endif + { "ltereltol", OPT_LTERELTOL,IF_SET | IF_REAL ,"Relative error tolerence" }, + { "lteabstol", OPT_LTEABSTOL,IF_SET | IF_REAL,"Absolute error tolerence" }, + { "ltetrtol", OPT_LTETRTOL,IF_SET | IF_REAL,"Truncation error overestimation factor" }, + { "newtrunc", OPT_NEWTRUNC,IF_SET | IF_FLAG,"voltage controlled truncation" } + }; int OPTcount = NUMELEMS(OPTtbl); diff --git a/src/spicelib/analysis/ckttrunc.c b/src/spicelib/analysis/ckttrunc.c index 36d3b7464..2d2e0e866 100644 --- a/src/spicelib/analysis/ckttrunc.c +++ b/src/spicelib/analysis/ckttrunc.c @@ -15,173 +15,213 @@ Author: 1985 Thomas L. Quarles #include "ngspice/devdefs.h" #include "ngspice/sperror.h" - +//#define STEPDEBUG int CKTtrunc(CKTcircuit *ckt, double *timeStep) { -#ifndef NEWTRUNC - int i; - double timetemp; + if (ckt->CKTnewtrunc == 0) { + int i; + double timetemp; #ifdef STEPDEBUG - double debugtemp; + double debugtemp; #endif /* STEPDEBUG */ - double startTime; - int error = OK; + double startTime; + int error = OK; - startTime = SPfrontEnd->IFseconds(); + startTime = SPfrontEnd->IFseconds(); - timetemp = HUGE; - for (i=0;iDEVtrunc && ckt->CKThead[i]) { + timetemp = HUGE; + for (i = 0; i < DEVmaxnum; i++) { + if (DEVices[i] && DEVices[i]->DEVtrunc && ckt->CKThead[i]) { #ifdef STEPDEBUG - debugtemp = timetemp; + debugtemp = timetemp; #endif /* STEPDEBUG */ - error = DEVices[i]->DEVtrunc (ckt->CKThead[i], ckt, &timetemp); - if(error) { - ckt->CKTstat->STATtranTruncTime += SPfrontEnd->IFseconds() - - startTime; - return(error); - } + error = DEVices[i]->DEVtrunc(ckt->CKThead[i], ckt, &timetemp); + if (error) { + ckt->CKTstat->STATtranTruncTime += SPfrontEnd->IFseconds() + - startTime; + return(error); + } #ifdef STEPDEBUG - if(debugtemp != timetemp) { - printf("timestep cut by device type %s from %g to %g\n", + if (debugtemp != timetemp) { + printf("timestep cut by device type %s from %g to %g\n", DEVices[i]->DEVpublic.name, debugtemp, timetemp); - } + } #endif /* STEPDEBUG */ + } } + *timeStep = MIN(2 * *timeStep, timetemp); + + ckt->CKTstat->STATtranTruncTime += SPfrontEnd->IFseconds() - startTime; + return(OK); } - *timeStep = MIN(2 * *timeStep,timetemp); + else { + int i; + CKTnode* node; + double timetemp; + double tmp; + double diff; + double tol; + double startTime; + int size; - ckt->CKTstat->STATtranTruncTime += SPfrontEnd->IFseconds() - startTime; - return(OK); -#else /* NEWTRUNC */ - int i; - CKTnode *node; - double timetemp; - double tmp; - double diff; - double tol; - double startTime; - int size; + startTime = SPfrontEnd->IFseconds(); - startTime = SPfrontEnd->IFseconds(); + timetemp = HUGE; + size = SMPmatSize(ckt->CKTmatrix); +#ifdef STEPDEBUG + printf("\nNEWTRUNC at time %g, delta %g\n", ckt->CKTtime, ckt->CKTdeltaOld[0]); +#endif + node = ckt->CKTnodes; + switch (ckt->CKTintegrateMethod) { - timetemp = HUGE; - size = SMPmatSize(ckt->CKTmatrix); + case TRAPEZOIDAL: #ifdef STEPDEBUG - printf("at time %g, delta %g\n",ckt->CKTtime,ckt->CKTdeltaOld[0]); + printf("TRAP, Order is %d\n", ckt->CKTorder); #endif - node = ckt->CKTnodes; - switch(ckt->CKTintegrateMethod) { - - case TRAPEZOIDAL: - switch(ckt->CKTorder) { - case 1: - for(i=1;iCKTrhs[i]),fabs(ckt->CKTpred[i]))* - ckt->CKTlteReltol+ckt->CKTlteAbstol; - node = node->next; - if(node->type!= SP_VOLTAGE) continue; - diff = ckt->CKTrhs[i]-ckt->CKTpred[i]; + switch (ckt->CKTorder) { + case 1: + for (i = 1; i < size; i++) { + tol = MAX(fabs(ckt->CKTrhs[i]), fabs(ckt->CKTpred[i])) * + ckt->CKTlteReltol + ckt->CKTlteAbstol; + node = node->next; + if (node->type != SP_VOLTAGE) continue; + diff = ckt->CKTrhs[i] - ckt->CKTpred[i]; #ifdef STEPDEBUG - printf("%s: cor=%g, pred=%g ",node->name, - ckt->CKTrhs[i],ckt->CKTpred[i]); + printf("%s: cor=%g, pred=%g ", node->name, + ckt->CKTrhs[i], ckt->CKTpred[i]); #endif - if(diff != 0) { - tmp = ckt->CKTtrtol * tol * 2 /diff; - tmp = ckt->CKTdeltaOld[0]*sqrt(fabs(tmp)); - timetemp = MIN(timetemp,tmp); + if (diff != 0) { + // if (!AlmostEqualUlps(diff, 0, 10)) { + tmp = ckt->CKTlteTrtol * tol * 2 / diff; + tmp = ckt->CKTdeltaOld[0] * fabs(tmp); + timetemp = MIN(timetemp, tmp); #ifdef STEPDEBUG - printf("tol = %g, diff = %g, h->%g\n",tol,diff,tmp); + printf("tol = %g, diff = %g, h->%g\n", tol, diff, tmp); #endif - } else { + } + else { #ifdef STEPDEBUG - printf("diff is 0\n"); + printf("diff is 0\n"); #endif + } } + break; + case 2: + for (i = 1; i < size; i++) { + tol = MAX(fabs(ckt->CKTrhs[i]), fabs(ckt->CKTpred[i])) * + ckt->CKTlteReltol + ckt->CKTlteAbstol; + node = node->next; + if (node->type != SP_VOLTAGE) continue; + diff = ckt->CKTrhs[i] - ckt->CKTpred[i]; +#ifdef STEPDEBUG + printf("%s: cor=%g, pred=%g ", node->name, + ckt->CKTrhs[i], ckt->CKTpred[i]); +#endif + if (diff != 0) { + // if (!AlmostEqualUlps(diff, 0, 10)) { + tmp = ckt->CKTlteTrtol * tol * 2 / diff; + tmp = ckt->CKTdeltaOld[0] * sqrt(fabs(tmp)); + timetemp = MIN(timetemp, tmp); +#ifdef STEPDEBUG + printf("tol = %g, diff = %g, h->%g\n", tol, diff, tmp); +#endif + } + else { +#ifdef STEPDEBUG + printf("diff is 0\n"); +#endif + } + } + break; + /* case 2: + for(i=1;iCKTrhs[i]),fabs(ckt->CKTpred[i]))* + ckt->CKTlteReltol+ckt->CKTlteAbstol; + node = node->next; + if(node->type!= SP_VOLTAGE) continue; + diff = ckt->CKTrhs[i]-ckt->CKTpred[i]; + #ifdef STEPDEBUG + printf("%s: cor=%g, pred=%g ",node->name,ckt->CKTrhs[i], + ckt->CKTpred[i]); + #endif + if(diff != 0) { + // if(!AlmostEqualUlps(diff, 0, 10)) { + tmp = tol * ckt->CKTlteTrtol * (ckt->CKTdeltaOld[0] + ckt->CKTdeltaOld[1]) + / (diff * ckt->CKTdelta); + tmp = fabs(tmp); + tmp = exp(log(tmp) / 3); + tmp *= ckt->CKTdelta; + timetemp = MIN(timetemp,tmp); + #ifdef STEPDEBUG + printf("tol = %g, diff = %g, h->%g\n",tol,diff,tmp); + #endif + } else { + #ifdef STEPDEBUG + printf("diff is 0\n"); + #endif + } + } + break; */ + default: + return(E_ORDER); + break; + } break; - case 2: - for(i=1;iCKTrhs[i]),fabs(ckt->CKTpred[i]))* - ckt->CKTlteReltol+ckt->CKTlteAbstol; - node = node->next; - if(node->type!= SP_VOLTAGE) continue; - diff = ckt->CKTrhs[i]-ckt->CKTpred[i]; + + case GEAR: { #ifdef STEPDEBUG - printf("%s: cor=%g, pred=%g ",node->name,ckt->CKTrhs[i], - ckt->CKTpred[i]); + printf("GEAR, Order is %d\n", ckt->CKTorder); #endif - if(diff != 0) { - tmp = ckt->CKTdeltaOld[0]*ckt->CKTtrtol * tol * 3 * - (ckt->CKTdeltaOld[0]+ckt->CKTdeltaOld[1])/diff; - tmp = fabs(tmp); - timetemp = MIN(timetemp,tmp); -#ifdef STEPDEBUG - printf("tol = %g, diff = %g, h->%g\n",tol,diff,tmp); -#endif - } else { -#ifdef STEPDEBUG - printf("diff is 0\n"); -#endif - } + double delsum = 0; + for (i = 0; i <= ckt->CKTorder; i++) { + delsum += ckt->CKTdeltaOld[i]; } - break; - default: - return(E_ORDER); - break; - - } - break; - - case GEAR: { - double delsum=0; - for(i=0;i<=ckt->CKTorder;i++) { - delsum += ckt->CKTdeltaOld[i]; - } - for(i=1;inext; - if(node->type!= SP_VOLTAGE) continue; - tol = MAX( fabs(ckt->CKTrhs[i]),fabs(ckt->CKTpred[i]))* - ckt->CKTlteReltol+ckt->CKTlteAbstol; - diff = (ckt->CKTrhs[i]-ckt->CKTpred[i]); + for (i = 1; i < size; i++) { + node = node->next; + if (node->type != SP_VOLTAGE) continue; + tol = MAX(fabs(ckt->CKTrhs[i]), fabs(ckt->CKTpred[i])) * + ckt->CKTlteReltol + ckt->CKTlteAbstol; + diff = (ckt->CKTrhs[i] - ckt->CKTpred[i]); #ifdef STEPDEBUG - printf("%s: cor=%g, pred=%g ",node->name,ckt->CKTrhs[i], + printf("%s: cor=%g, pred=%g ", node->name, ckt->CKTrhs[i], ckt->CKTpred[i]); #endif - if(diff != 0) { - tmp = tol*ckt->CKTtrtol*delsum/(diff*ckt->CKTdelta); - tmp = fabs(tmp); - switch(ckt->CKTorder) { + if (diff != 0) { + tmp = tol * ckt->CKTlteTrtol * delsum / (diff * ckt->CKTdelta); + tmp = fabs(tmp); + switch (ckt->CKTorder) { case 0: break; case 1: tmp = sqrt(tmp); break; default: - tmp = exp(log(tmp)/(ckt->CKTorder+1)); + tmp = exp(log(tmp) / (ckt->CKTorder + 1)); break; + } + tmp *= ckt->CKTdelta; + timetemp = MIN(timetemp, tmp); +#ifdef STEPDEBUG + printf("tol = %g, diff = %g, h->%g\n", tol, diff, tmp); +#endif } - tmp *= ckt->CKTdelta; - timetemp = MIN(timetemp,tmp); + else { #ifdef STEPDEBUG - printf("tol = %g, diff = %g, h->%g\n",tol,diff,tmp); -#endif - } else { -#ifdef STEPDEBUG - printf("diff is 0\n"); + printf("diff is 0\n"); #endif + } } } - } - break; + break; - default: - return(E_METHOD); + default: + return(E_METHOD); + } + *timeStep = MIN(2 * *timeStep, timetemp); + ckt->CKTstat->STATtranTruncTime += SPfrontEnd->IFseconds() - startTime; + return(OK); } - *timeStep = MIN(2 * *timeStep,timetemp); - ckt->CKTstat->STATtranTruncTime += SPfrontEnd->IFseconds() - startTime; - return(OK); -#endif /* NEWTRUNC */ } diff --git a/src/spicelib/devices/devsup.c b/src/spicelib/devices/devsup.c index 762199cae..d215b791b 100644 --- a/src/spicelib/devices/devsup.c +++ b/src/spicelib/devices/devsup.c @@ -814,13 +814,16 @@ DEVcap(CKTcircuit *ckt, double vgd, double vgs, double vgb, double covlgd, double DEVpred(CKTcircuit *ckt, int loct) { -#ifndef NEWTRUNC - double xfact; + if (!ckt->CKTnewtrunc) { + double xfact; - xfact = ckt->CKTdelta/ckt->CKTdeltaOld[1]; - return( ( (1+xfact) * *(ckt->CKTstate1+loct) ) - - ( xfact * *(ckt->CKTstate2+loct) ) ); -#endif /* NEWTRUNC */ + xfact = ckt->CKTdelta / ckt->CKTdeltaOld[1]; + return(((1 + xfact) * *(ckt->CKTstate1 + loct)) - + (xfact * *(ckt->CKTstate2 + loct))); + } + else { + return 1.; + } } diff --git a/src/xspice/icm/analog/delay/cfunc.mod b/src/xspice/icm/analog/delay/cfunc.mod index 0830bcc12..c86bbc82a 100644 --- a/src/xspice/icm/analog/delay/cfunc.mod +++ b/src/xspice/icm/analog/delay/cfunc.mod @@ -142,11 +142,10 @@ struct CKTcircuitmin { double CKTreltol; /* --- */ double CKTchgtol; /* --- */ double CKTvoltTol; /* --- */ - /* What is this define for ? */ -#ifdef NEWTRUNC - double CKTlteReltol; - double CKTlteAbstol; -#endif /* NEWTRUNC */ + double CKTlteReltol; /* relative error in voltage based truncation error estimation */ + double CKTlteAbstol; /* absolute error in voltage based truncation error estimation */ + double CKTlteTrtol; /* scaling time step in voltage based truncation error estimation */ + int CKTnewtrunc; /* enable lte (local truncation error) based on voltages */ double CKTgmin; /* .options GMIN */ double CKTgshunt; /* .options RSHUNT */ double CKTcshunt; /* .options CSHUNT */ diff --git a/visualc/src/include/ngspice/config.h b/visualc/src/include/ngspice/config.h index 7daa091dc..2fc43d11c 100644 --- a/visualc/src/include/ngspice/config.h +++ b/visualc/src/include/ngspice/config.h @@ -464,9 +464,6 @@ /* Define if you want to discover :) */ /* #undef NEWPRED */ -/* Do not trigger unwanted traps by default */ -/* #undef NEWTRUNC */ - /* Define if we want NOBYPASS */ /* #undef NOBYPASS */ @@ -490,7 +487,7 @@ #define PACKAGE_VERSION VERSION /* Define if we want predictor algorithm */ -/* #undef PREDICTOR */ +#define PREDICTOR /* Define to 1 if the C compiler supports function prototypes. */ /* #undef PROTOTYPES */ From f6fc2565694e5c10c3285975bdba70c0b38ee0a5 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 28 Dec 2025 11:03:08 +0100 Subject: [PATCH 093/161] Measure transient analysis time. --- examples/vdmos/100W.sp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/vdmos/100W.sp b/examples/vdmos/100W.sp index a917702ad..c8e7d2962 100644 --- a/examples/vdmos/100W.sp +++ b/examples/vdmos/100W.sp @@ -63,6 +63,7 @@ plot db(V(out)/V(out1)) set units=degrees plot unwrap(ph(V(out)/V(out1))) tran 1u 1000m +rusage time fourier 1K V(out) plot v(out)*@rload[i] settype temperature v(tn) v(tp) v(tcn) v(tcp) From c51dcb67a346437d2e8fcd54f4eac7d66c165f33 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 28 Dec 2025 11:09:15 +0100 Subject: [PATCH 094/161] Add a note on --enable-predictor --- compile_cyg_make_short_check_64.sh | 1 + compile_linux.sh | 2 ++ compile_linux_shared.sh | 2 ++ compile_macos_clang_M2.sh | 2 ++ compile_macos_clang_M2_shared.sh | 2 ++ compile_macos_shared.sh | 1 + compile_min.sh | 2 ++ 7 files changed, 12 insertions(+) diff --git a/compile_cyg_make_short_check_64.sh b/compile_cyg_make_short_check_64.sh index a71effb93..3e5b7f7ff 100644 --- a/compile_cyg_make_short_check_64.sh +++ b/compile_cyg_make_short_check_64.sh @@ -26,6 +26,7 @@ fi if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi echo +# If truncation error correction by voltage is required, add --enable-predictor cd release64_cyg if [ $? -ne 0 ]; then echo "cd release64_cyg failed"; exit 1 ; fi echo diff --git a/compile_linux.sh b/compile_linux.sh index a51fafe22..602c3fc50 100755 --- a/compile_linux.sh +++ b/compile_linux.sh @@ -37,6 +37,8 @@ fi if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi echo + +# If truncation error correction by voltage is required, add --enable-predictor if test "$1" = "d"; then cd debug if [ $? -ne 0 ]; then echo "cd debug failed"; exit 1 ; fi diff --git a/compile_linux_shared.sh b/compile_linux_shared.sh index 72fe12194..85c8e83f9 100755 --- a/compile_linux_shared.sh +++ b/compile_linux_shared.sh @@ -36,6 +36,8 @@ fi if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi echo + +# If truncation error correction by voltage is required, add --enable-predictor if test "$1" = "d"; then cd debugsh if [ $? -ne 0 ]; then echo "cd debugsh failed"; exit 1 ; fi diff --git a/compile_macos_clang_M2.sh b/compile_macos_clang_M2.sh index 0e8150baf..605b2daa2 100644 --- a/compile_macos_clang_M2.sh +++ b/compile_macos_clang_M2.sh @@ -36,6 +36,8 @@ fi if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi echo + +# If truncation error correction by voltage is required, add --enable-predictor if test "$1" = "d"; then cd debug if [ $? -ne 0 ]; then echo "cd debug failed"; exit 1 ; fi diff --git a/compile_macos_clang_M2_shared.sh b/compile_macos_clang_M2_shared.sh index 31a778bbb..5a96f42fa 100644 --- a/compile_macos_clang_M2_shared.sh +++ b/compile_macos_clang_M2_shared.sh @@ -36,6 +36,8 @@ fi if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi echo + +# If truncation error correction by voltage is required, add --enable-predictor if test "$1" = "d"; then cd debug_sh if [ $? -ne 0 ]; then echo "cd debug_sh failed"; exit 1 ; fi diff --git a/compile_macos_shared.sh b/compile_macos_shared.sh index 9cd8664a0..a2370c409 100755 --- a/compile_macos_shared.sh +++ b/compile_macos_shared.sh @@ -32,6 +32,7 @@ fi ./autogen.sh if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi +# If truncation error correction by voltage is required, add --enable-predictor echo if test "$1" = "d"; then cd debug-sh diff --git a/compile_min.sh b/compile_min.sh index 6f030acc0..22cea900c 100755 --- a/compile_min.sh +++ b/compile_min.sh @@ -41,6 +41,8 @@ fi if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi echo + +# If truncation error correction by voltage is required, add --enable-predictor if test "$1" = "d"; then cd debug if [ $? -ne 0 ]; then echo "cd debug failed"; exit 1 ; fi From 8d21c8e79b15fbcf89d0446d5ea14204d71540a4 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 28 Dec 2025 12:47:55 +0100 Subject: [PATCH 095/161] Make pred available always --- src/include/ngspice/cktdefs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/ngspice/cktdefs.h b/src/include/ngspice/cktdefs.h index c12bf91cf..1eac359b8 100644 --- a/src/include/ngspice/cktdefs.h +++ b/src/include/ngspice/cktdefs.h @@ -123,8 +123,8 @@ struct CKTcircuit { (imag) */ double *CKTirhsOld; /* previous rhs value (imaginary)*/ double *CKTirhsSpare; /* spare rhs value (imaginary)*/ -#ifdef PREDICTOR double *CKTpred; /* predicted solution vector */ +#ifdef PREDICTOR double *CKTsols[8]; /* previous 8 solutions */ #endif /* PREDICTOR */ From 6ff339ee9c82c83fcbfcd7b437c24f4e6176ab88 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 28 Dec 2025 23:17:21 +0100 Subject: [PATCH 096/161] Add a note on --enable-predictor and -march=native --- compile_cyg_make_short_check_64.sh | 3 ++- compile_linux.sh | 1 + compile_macos_clang_M2.sh | 1 + compile_macos_clang_M2_shared.sh | 1 + compile_macos_shared.sh | 1 + compile_min.sh | 1 + 6 files changed, 7 insertions(+), 1 deletion(-) diff --git a/compile_cyg_make_short_check_64.sh b/compile_cyg_make_short_check_64.sh index 3e5b7f7ff..db441c53b 100644 --- a/compile_cyg_make_short_check_64.sh +++ b/compile_cyg_make_short_check_64.sh @@ -27,10 +27,11 @@ if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi echo # If truncation error correction by voltage is required, add --enable-predictor +# If compiling for a local machine, you may add -march=native to the CFLAGS shown below cd release64_cyg if [ $? -ne 0 ]; then echo "cd release64_cyg failed"; exit 1 ; fi echo -../configure --with-x=yes --enable-cider --enable-shortcheck CFLAGS="-O2 -m64 -Wall -Wextra -Wshadow" LDFLAGS="-s -m64" +../configure --with-x=yes --enable-cider --enable-predictor --enable-shortcheck CFLAGS="-march=native -O2 -m64 -Wall -Wextra -Wshadow" LDFLAGS="-s -m64" if [ $? -ne 0 ]; then echo "../configure failed"; exit 1 ; fi diff --git a/compile_linux.sh b/compile_linux.sh index 602c3fc50..cc193a06d 100755 --- a/compile_linux.sh +++ b/compile_linux.sh @@ -39,6 +39,7 @@ if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi echo # If truncation error correction by voltage is required, add --enable-predictor +# If compiling for a local machine, you may add -march=native to the CFLAGS shown below if test "$1" = "d"; then cd debug if [ $? -ne 0 ]; then echo "cd debug failed"; exit 1 ; fi diff --git a/compile_macos_clang_M2.sh b/compile_macos_clang_M2.sh index 605b2daa2..e5423ded7 100644 --- a/compile_macos_clang_M2.sh +++ b/compile_macos_clang_M2.sh @@ -38,6 +38,7 @@ if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi echo # If truncation error correction by voltage is required, add --enable-predictor +# If compiling for a local machine, you may add -march=native to the CFLAGS shown below if test "$1" = "d"; then cd debug if [ $? -ne 0 ]; then echo "cd debug failed"; exit 1 ; fi diff --git a/compile_macos_clang_M2_shared.sh b/compile_macos_clang_M2_shared.sh index 5a96f42fa..6f108c6c6 100644 --- a/compile_macos_clang_M2_shared.sh +++ b/compile_macos_clang_M2_shared.sh @@ -38,6 +38,7 @@ if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi echo # If truncation error correction by voltage is required, add --enable-predictor +# If compiling for a local machine, you may add -march=native to the CFLAGS shown below if test "$1" = "d"; then cd debug_sh if [ $? -ne 0 ]; then echo "cd debug_sh failed"; exit 1 ; fi diff --git a/compile_macos_shared.sh b/compile_macos_shared.sh index a2370c409..a3cc91c4f 100755 --- a/compile_macos_shared.sh +++ b/compile_macos_shared.sh @@ -33,6 +33,7 @@ fi if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi # If truncation error correction by voltage is required, add --enable-predictor +# If compiling for a local machine, you may add -march=native to the CFLAGS shown below echo if test "$1" = "d"; then cd debug-sh diff --git a/compile_min.sh b/compile_min.sh index 22cea900c..2bceb5887 100755 --- a/compile_min.sh +++ b/compile_min.sh @@ -43,6 +43,7 @@ if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi echo # If truncation error correction by voltage is required, add --enable-predictor +# If compiling for a local machine, you may add -march=native to the CFLAGS shown below if test "$1" = "d"; then cd debug if [ $? -ne 0 ]; then echo "cd debug failed"; exit 1 ; fi From 8737839f4146ac773192df26fa32ca530cff7c07 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 28 Dec 2025 23:19:58 +0100 Subject: [PATCH 097/161] Add a function m3avg(vector) for filtering of trap ringing. Moving average with D(n) = (C(n-1)/2 + C(n) + C(n+1)/2)/2 --- src/frontend/parse.c | 5 ++-- src/include/ngspice/fteext.h | 2 +- src/maths/cmaths/cmath2.c | 56 ++++++++++++++++++++++++++++++++++++ src/maths/cmaths/cmath2.h | 1 + 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/frontend/parse.c b/src/frontend/parse.c index 4c31a3fbe..f575ecbe7 100644 --- a/src/frontend/parse.c +++ b/src/frontend/parse.c @@ -363,8 +363,9 @@ struct func ft_funcs[] = { { "ceil", cx_ceil }, { "mean", cx_mean }, { "stddev", cx_stddev }, - { "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 */ + { "avg", cx_avg }, + { "m3avg", cx_m3avg }, + { "group_delay", (cx_function_t*)(void *) cx_group_delay }, { "vector", cx_vector }, { "cvector", cx_cvector }, { "unitvec", cx_unitvec }, diff --git a/src/include/ngspice/fteext.h b/src/include/ngspice/fteext.h index 202f693c0..541c7f8c0 100644 --- a/src/include/ngspice/fteext.h +++ b/src/include/ngspice/fteext.h @@ -103,7 +103,7 @@ extern void *cx_max(void *, short int , int , int *, short int *); extern void *cx_min(void *, short int , int , int *, short int *); extern void *cx_d(void *, short int , int , int *, short int *); extern void *cx_avg(void *, short int , int , int *, short int *); - +extern void *cx_m3avg(void *, short int , int , int *, short int *); /* cmath3.c */ diff --git a/src/maths/cmaths/cmath2.c b/src/maths/cmaths/cmath2.c index 6dc37b6b1..7af7cd84e 100644 --- a/src/maths/cmaths/cmath2.c +++ b/src/maths/cmaths/cmath2.c @@ -361,6 +361,62 @@ cx_avg(void *data, short int type, int length, int *newlength, short int *newtyp } } +/* Compute the moving average of a vector. + * Using three elements ((n-1)/2 + n + (n+1)/2)/2 + * Useful for removing trap ringing. + */ + +void* +cx_m3avg(void* data, short int type, int length, int* newlength, short int* newtype) +{ + double sum_real = 0.0, sum_imag = 0.0; + int i; + + if (type == VF_REAL) { + + double* d = alloc_d(length); + double* dd = (double*)data; + + int nlen = length - 1; + + *newtype = VF_REAL; + *newlength = length; + + d[0] = dd[0]; + + for (i = 1; i < nlen; i++) { + d[i] = (dd[i-1] + dd[i+1]) / 4. + dd[i] / 2.; + } + + d[nlen] = dd[nlen]; + + return ((void*)d); + + } + else { + + ngcomplex_t* c = alloc_c(length); + ngcomplex_t* cc = (ngcomplex_t*)data; + + int nlen = length - 1; + + *newtype = VF_COMPLEX; + *newlength = length; + + realpart(c[0]) = realpart(cc[0]); + + for (i = 0; i < length; i++) { + realpart(c[i]) = (realpart(cc[i - 1]) + realpart(cc[i + 1])) / 4. + realpart(cc[i]) / 2.; + imagpart(c[i]) = (imagpart(cc[i - 1]) + imagpart(cc[i + 1])) / 4. + imagpart(cc[i]) / 2.; + } + + realpart(c[nlen]) = realpart(cc[nlen]); + imagpart(c[nlen]) = imagpart(cc[nlen]); + + return ((void*)c); + + } +} /* Compute the mean of a vector. */ diff --git a/src/maths/cmaths/cmath2.h b/src/maths/cmaths/cmath2.h index 31bd4c1a0..c5a9a1028 100644 --- a/src/maths/cmaths/cmath2.h +++ b/src/maths/cmaths/cmath2.h @@ -33,6 +33,7 @@ void * cx_max(void *data, short int type, int length, int *newlength, short int void * cx_min(void *data, short int type, int length, int *newlength, short int *newtype); void * cx_d(void *data, short int type, int length, int *newlength, short int *newtype); void * cx_avg(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_m3avg(void *data, short int type, int length, int *newlength, short int *newtype); void * cx_floor(void *data, short int type, int length, int *newlength, short int *newtype); void * cx_ceil(void *data, short int type, int length, int *newlength, short int *newtype); void * cx_nint(void *data, short int type, int length, int *newlength, short int *newtype); From c12ad7ba27f4e0b7474faf8ec42f6d73faed8de0 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 30 Dec 2025 15:13:58 +0100 Subject: [PATCH 098/161] Update the reference to the manual --- examples/various/transformers1.cir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/various/transformers1.cir b/examples/various/transformers1.cir index cf26601b4..6e9b224ab 100644 --- a/examples/various/transformers1.cir +++ b/examples/various/transformers1.cir @@ -35,7 +35,7 @@ Xtr3 1 0 22 0 tr3 .ends * transformer 2 -* ngspice manual 12.2.20 and 12.2.21 +* ngspice manual 8.2.21 and 8.2.22 * px primary nodes, sx secondary nodes of electric circuit * mcx nodes of magnetic circuit .subckt tr2 p1 p2 s1 s2 From 2e5772e35eed205e626e47bc897a081cd793595e Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 28 Dec 2025 23:30:35 +0100 Subject: [PATCH 099/161] Add the non-nqs PSP103 OSDI model to spinit --- src/spinit.in | 1 + visualc/spinit_all | 1 + visualc/spinitd | 1 + visualc/spinitd64 | 1 + visualc/spinitr | 1 + visualc/spinitr64 | 1 + 6 files changed, 6 insertions(+) diff --git a/src/spinit.in b/src/spinit.in index 669f6f444..ec47bd905 100644 --- a/src/spinit.in +++ b/src/spinit.in @@ -38,6 +38,7 @@ if $?osdi_enabled osdi @pkglibdir@/BSIMCMG.osdi osdi @pkglibdir@/HICUMl0-2.0.osdi osdi @pkglibdir@/psp103_nqs.osdi + osdi @pkglibdir@/psp103.osdi osdi @pkglibdir@/r2_cmc.osdi osdi @pkglibdir@/vbic_4T_et_cf.osdi diff --git a/visualc/spinit_all b/visualc/spinit_all index b2605b9cd..72244ed59 100644 --- a/visualc/spinit_all +++ b/visualc/spinit_all @@ -40,6 +40,7 @@ if $?osdi_enabled osdi ../lib/ngspice/BSIMCMG.osdi osdi ../lib/ngspice/HICUMl0-2.0.osdi osdi ../lib/ngspice/psp103_nqs.osdi + osdi ../lib/ngspice/psp103.osdi osdi ../lib/ngspice/r2_cmc.osdi osdi ../lib/ngspice/vbic_4T_et_cf.osdi diff --git a/visualc/spinitd b/visualc/spinitd index 9e2da93db..6b045be22 100644 --- a/visualc/spinitd +++ b/visualc/spinitd @@ -41,6 +41,7 @@ if $?osdi_enabled osdi C:/Spiced/lib/ngspice/BSIMCMG.osdi osdi C:/Spiced/lib/ngspice/HICUMl0-2.0.osdi osdi C:/Spiced/lib/ngspice/psp103_nqs.osdi + osdi C:/Spiced/lib/ngspice/psp103.osdi osdi C:/Spiced/lib/ngspice/r2_cmc.osdi osdi C:/Spiced/lib/ngspice/vbic_4T_et_cf.osdi diff --git a/visualc/spinitd64 b/visualc/spinitd64 index d0f3983a8..76ce45ed4 100644 --- a/visualc/spinitd64 +++ b/visualc/spinitd64 @@ -39,6 +39,7 @@ if $?osdi_enabled osdi C:/Spice64d/lib/ngspice/BSIMBULK107.osdi osdi C:/Spice64d/lib/ngspice/BSIMCMG.osdi osdi C:/Spice64d/lib/ngspice/HICUMl0-2.0.osdi + osdi C:/Spice64d/lib/ngspice/psp103_nqs.osdi osdi C:/Spice64d/lib/ngspice/psp103.osdi osdi C:/Spice64d/lib/ngspice/r2_cmc.osdi osdi C:/Spice64d/lib/ngspice/vbic_4T_et_cf.osdi diff --git a/visualc/spinitr b/visualc/spinitr index 197cae611..0e975aacf 100644 --- a/visualc/spinitr +++ b/visualc/spinitr @@ -40,6 +40,7 @@ if $?osdi_enabled osdi C:/Spice/lib/ngspice/BSIMCMG.osdi osdi C:/Spice/lib/ngspice/HICUMl0-2.0.osdi osdi C:/Spice/lib/ngspice/psp103_nqs.osdi + osdi C:/Spice/lib/ngspice/psp103.osdi osdi C:/Spice/lib/ngspice/r2_cmc.osdi osdi C:/Spice/lib/ngspice/vbic_4T_et_cf.osdi diff --git a/visualc/spinitr64 b/visualc/spinitr64 index 197330fe0..dce687802 100644 --- a/visualc/spinitr64 +++ b/visualc/spinitr64 @@ -40,6 +40,7 @@ if $?osdi_enabled osdi C:/Spice64/lib/ngspice/BSIMCMG.osdi osdi C:/Spice64/lib/ngspice/HICUMl0-2.0.osdi osdi C:/Spice64/lib/ngspice/psp103_nqs.osdi + osdi C:/Spice64/lib/ngspice/psp103.osdi osdi C:/Spice64/lib/ngspice/r2_cmc.osdi osdi C:/Spice64/lib/ngspice/vbic_4T_et_cf.osdi From 343319a1ed55e63437d57e970e0161259581c5b9 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 2 Jan 2026 15:27:39 +0100 Subject: [PATCH 100/161] F5 example removed, obsolete or needs to be improved. --- examples/optran/F5TurboV2thermal-optran.cir | 79 --------------------- examples/optran/F5models.lib | 78 -------------------- examples/optran/contents.txt | 5 -- examples/optran/script-optran.txt | 55 -------------- 4 files changed, 217 deletions(-) delete mode 100644 examples/optran/F5TurboV2thermal-optran.cir delete mode 100644 examples/optran/F5models.lib delete mode 100644 examples/optran/script-optran.txt diff --git a/examples/optran/F5TurboV2thermal-optran.cir b/examples/optran/F5TurboV2thermal-optran.cir deleted file mode 100644 index a9fc6d0b7..000000000 --- a/examples/optran/F5TurboV2thermal-optran.cir +++ /dev/null @@ -1,79 +0,0 @@ -.title KiCad schematic -.include "F5models.lib" -.include "script-optran.txt" -R2 in 0 47.5k -R1 Net-_Q1-Pad2_ in 1k -R5 +32 Net-_P1-Pad1_ 1k -R3 Net-_P3-Pad1_ 0 10 -R4 0 Net-_P3-Pad3_ 10 -R6 Net-_P2-Pad1_ -32 1k -R7 out Net-_P3-Pad1_ 220 -R8 out Net-_P3-Pad1_ 220 -R9 out Net-_P3-Pad3_ 220 -R10 out Net-_P3-Pad3_ 220 -R11 Net-_R11-Pad1_ Net-_P1-Pad1_ 2.2k -R13 Net-_Q3-Pad2_ Net-_P1-Pad1_ 47.5 -R15 Net-_Q5-Pad2_ Net-_P2-Pad1_ 47.5 -R12 Net-_R12-Pad1_ Net-_P2-Pad1_ 2.2k -R17 +32 Net-_D3a1-Pad1_ 1 -R21 Net-_D1a1-Pad2_ -32 1 -R18 +32 Net-_D3a1-Pad1_ 1 -R22 Net-_D1a1-Pad2_ -32 1 -R16 Net-_Q6-Pad2_ Net-_P2-Pad1_ 47.5 -R14 Net-_Q4-Pad2_ Net-_P1-Pad1_ 47.5 -R19 +32 Net-_D4a1-Pad1_ 1 -R23 Net-_D2a1-Pad2_ -32 1 -R20 +32 Net-_D4a1-Pad1_ 1 -R24 Net-_D2a1-Pad2_ -32 1 -Ra2 Net-_Ra1-Pad2_ 0 4 -D3a1 +32 Net-_D3a1-Pad1_ DMOD -D1a1 Net-_D1a1-Pad2_ -32 DMOD -D3b1 +32 Net-_D3a1-Pad1_ DMOD -D1b1 Net-_D1a1-Pad2_ -32 DMOD -D4a1 +32 Net-_D4a1-Pad1_ DMOD -D2a1 Net-_D2a1-Pad2_ -32 DMOD -D4b1 +32 Net-_D4a1-Pad1_ DMOD -D2b1 Net-_D2a1-Pad2_ -32 DMOD -XP3 Net-_P3-Pad1_ 0 Net-_P3-Pad3_ RPOT value=200 ratio={rp3} -XP1 Net-_P1-Pad1_ +32 +32 RPOT value=5k ratio={rp1} -XP2 Net-_P2-Pad1_ -32 -32 RPOT value=5k ratio={rp2} -V3 in 0 dc 0 ac 1 sin(0 2 1k 5m) -JQ1 Net-_P1-Pad1_ Net-_Q1-Pad2_ Net-_P3-Pad1_ 2SK170 -JQ2 Net-_P2-Pad1_ Net-_Q1-Pad2_ Net-_P3-Pad3_ 2SJ74 -MQ5 out Net-_Q5-Pad2_ Net-_D1a1-Pad2_ Q5tj Q5tc IRFP240 thermal -MQ4 out Net-_Q4-Pad2_ Net-_D4a1-Pad1_ Q4tj Q4tc IRFP9240 thermal -MQ6 out Net-_Q6-Pad2_ Net-_D2a1-Pad2_ Q6tj Q6tc IRFP240 thermal -Rj1 Q3tj 0 1G -Rj2 Q4tj 0 1G -Rj3 Q5tj 0 1G -Rj4 Q6tj 0 1G -Rc2 Q3hs Net-_Rc2-Pad2_ {hs} -Rc4 Q4hs Net-_Rc2-Pad2_ {hs} -Rc6 Q5hs Net-_Rc2-Pad2_ {hs} -Rc8 Q6hs Net-_Rc2-Pad2_ {hs} -Rc1 Q3tc Q3hs {chs} -Rc3 Q4tc Q4hs {chs} -Rc5 Q5tc Q5hs {chs} -Rc7 Q6tc Q6hs {chs} -Vt1 Net-_Rc2-Pad2_ 0 {envtemp} -Cc1 Q3hs 0 {hscc} -Cc3 Q5hs 0 {hscc} -Cc4 Q6hs 0 {hscc} -V1 +32 0 dc 32 ; pulse(0 32 0.4m 2m 2m 100 200) -V2 -32 0 dc -32 ; pulse(0 -32 0.4m 2m 2m 100 200) -XTH2 Net-_D1a1-Pad2_ Q5hs Net-_R12-Pad1_ th R25=4.7k -XTH1 Net-_D3a1-Pad1_ Q3hs Net-_R11-Pad1_ th R25=4.7k -MQ3 out Net-_Q3-Pad2_ Net-_D3a1-Pad1_ Q3tj Q3tc IRFP9240 thermal -Vs1 Net-_S1-Pad3_ 0 dc 0 pulse(0 5 6 1m 1m 20 20) -XS1 Net-_Ra1-Pad2_ 0 Net-_S1-Pad3_ 0 genrelay -Cc2 Q4hs 0 {hscc} -Ra1 out Net-_Ra1-Pad2_ 4 -.tran 20u 5 -.param envtemp=40 -.param chs=1 -.param hs=1.2 -.param hscc=1 -.param rp2=0.21 -.param rp1=0.36 -.param rp3=0.505 -.end diff --git a/examples/optran/F5models.lib b/examples/optran/F5models.lib deleted file mode 100644 index b1e8b3c46..000000000 --- a/examples/optran/F5models.lib +++ /dev/null @@ -1,78 +0,0 @@ -* The models of this library are in the public domain -* from https://www.diyaudio.com/forums/solid-state/252973-2sk170-2sj74-spice-model-pass-0-4ma.html -*2SJ74 Dep-Mode 20mA 400mW LowNoise pkg:TO-92B 2,1,3 -.MODEL 2SJ74 PJF(Beta=92.12m Rs=7.748 Rd=7.748 Lambda=4.464m -+Vto=-.5428 Cgd=85.67p Pb=.3905 Fc=.5 -+Cgs=78.27p Is=12.98p -+Kf=26.64E-18 Af=1) - -*2SK170 -* 20mA 400mW LowNoise Dep-Mode pkg:TO-92B 3,1,2 -.MODEL 2SK170 NJF(Beta=59.86m Rs=4.151 Rd=4.151 Lambda=1.923m -+Vto=-.5024 Cgd=20p Pb=.4746 Fc=.5 -+Cgs=25.48p Is=8.477p -+Kf=111.3E-18 Af=1) - -.subckt RPOT 1 2 3 -R1 1 2 {value*ratio + 1m} -R2 2 3 {value*(1-ratio)+ 1m} -* below are default parameters, which are required by some simulators -.param value=1k -.param ratio=1 -.ends - -.model IRFP240 VDMOS nchan -+ Vto=4 Kp=5.9 Lambda=.001 Theta=0.015 ksubthres=.27 -+ Rd=61m Rs=18m Rg=3 Rds=1e7 -+ Cgdmax=2.45n Cgdmin=10p a=0.3 Cgs=1.2n -+ Is=60p N=1.1 Rb=14m XTI=3 -+ Cjo=1.5n Vj=0.8 m=0.5 -+ tcvth=0.0065 MU=-1.27 texp0=1.5 -+ Rthjc=0.4 Cthj=0.1 -+ mtriode=0.8 - -.model IRFP9240 VDMOS pchan -+ Vto=-4 Kp=8.8 Lambda=.003 Theta=0.08 ksubthres=.35 -+ Rd=180m Rs=50m Rg=3 Rds=1e7 -+ Cgdmax=1.25n Cgdmin=50p a=0.23 Cgs=1.15n -+ Is=150p N=1.3 Rb=16m XTI=2 -+ Cjo=1.3n Vj=0.8 m=0.5 -+ tcvth=0.004 MU=-1.27 texp0=1.5 -+ Rthjc=0.4 Cthj=0.1 -+ mtriode=0.6 - -.model DMOD D - -* Thermistor model -.subckt th n1 nt n2 -.param B=3977 -.param R25=4700 -*control node -Ctherm1 n1 0 100p -Ctherm2 n2 0 100p -Rtherm n1 n2 R = {R25*exp(B*(1/(v(nt)+273.15)-1/(25+273.15)))} -.ends - -* generic relay model -.subckt genrelay out1 out2 in1 in2 -.param ron = 10m -S1 out1 out2 in1 in2 SW -.MODEL SW VSWITCH(VON=4V VOFF=1V RON={ron} ROFF=100K) -.ends - -.MODEL IXTH16N10 VDMOS Nchan Vds=100 -+ VTO=-3.2 KP=9 -+ Lambda=2m -+ Mtriode=1.8 -+ Ksubthres=120m -+ subshift=160m -+ Rs=4m Rd=5m Rds=200e6 -+ Cgdmax=9000p Cgdmin=300p A=0.25 -+ Cgs=5500p Cjo=11000p -+ Is=10e-6 Rb=8m -+ BV=200 IBV=250e-6 -+ NBV=4 -+ TT=250e-9 -+ vq=100 -+ rq=0.1 -+ Rthjc=0.2 Cthj=0.1 diff --git a/examples/optran/contents.txt b/examples/optran/contents.txt index 16ac7920a..a9cfbbddb 100644 --- a/examples/optran/contents.txt +++ b/examples/optran/contents.txt @@ -1,10 +1,5 @@ ngspice input files using optran -Pass Labs F5 turbo -thermal simulation -use optran for 4s and coarse steps to obtain stable temperature -then simulate transient with high resolution - HiPass3opamps_optran.cir Just a check with three different OpAmps diff --git a/examples/optran/script-optran.txt b/examples/optran/script-optran.txt deleted file mode 100644 index 8da005aeb..000000000 --- a/examples/optran/script-optran.txt +++ /dev/null @@ -1,55 +0,0 @@ -.temp {envtemp} -.param envtemp=40 -.option savecurrents -.control -set controlswait -if $?sharedmode -* script for shared ngspice -version -rusage -else -*** script for standard ngspice -* Start optran without first iteration, -* without gmin stepping and without src stepping -* optran step size 10 ms, duration 40s, -optran 1 0 0 10m 40 0 -* check the first 10 ms, input is switched on after 5 ms -tran 1u 10m -echo -* output power -let po = @ra1[i] * v(out) -meas tran power_rms rms po from=5m to=10m -echo -rusage -* temperature transistor Q6 -set xbrushwidth=4 -settype temperature q6tj q6tc q6hs -plot q6tj q6tc q6hs q3tj q3tc q3hs ylimit 40 140 -set xbrushwidth=2 -* input and output voltages -plot in out -* power supply currents -*plot V1#branch V2#branch ylimit -50 50 -plot V1#branch V2#branch ylimit -10 10 -* output current -plot @ra1[i] -*plot @ra1[i] xlimit 0 5m ylimit -0.3 0.3 -* resistance of thermistor2 TH1, TH2 -let rth1 = (v("net-_d3a1-pad1_") - v("net-_r11-pad1_")) / (@b.xth1.brtherm[i] + 1n) -let rth2 = (v("net-_d1a1-pad2_") - v("net-_r12-pad1_")) / (@b.xth2.brtherm[i] + 1n) -settype impedance rth1 rth2 -plot rth1 rth2 ylimit 0 5k - -ac dec 10 1 1Meg -plot db(out) -plot cph(out) - -tran 1u 100m -fft out -set xbrushwidth=4 -set color0=white -plot mag(out) xlimit 0 10k -* to see the harmonics -plot mag(out) xlimit 0 10k ylimit 0 30m -end -.endc \ No newline at end of file From d3b0dc1b3120964cb42ce33adab4774aa928350c Mon Sep 17 00:00:00 2001 From: dwarning Date: Fri, 2 Jan 2026 20:28:45 +0100 Subject: [PATCH 101/161] Adapt VDMOS Vth temperature coefficient to usual notation with - for nch and + for pch. --- examples/probe/F5models.lib | 2 +- examples/probe/VDMOS_models.lib | 2 +- examples/vdmos/100W.sp | 2 +- examples/vdmos/100W_wingspread.sp | 2 +- examples/vdmos/crss_coss_ciss.sp | 2 +- examples/vdmos/dcdc.sp | 2 +- examples/vdmos/self-heating.sp | 2 +- examples/vdmos/soa_chk.sp | 2 +- src/spicelib/devices/vdmos/vdmostemp.c | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/probe/F5models.lib b/examples/probe/F5models.lib index ef74eb2f5..2b9086554 100644 --- a/examples/probe/F5models.lib +++ b/examples/probe/F5models.lib @@ -27,7 +27,7 @@ R2 2 3 {value*(1-ratio)+ 1m} + Cgdmax=2.45n Cgdmin=10p a=0.3 Cgs=1.2n + Is=60p N=1.1 Rb=14m XTI=3 + Cjo=1.5n Vj=0.8 m=0.5 -+ tcvth=0.0065 MU=-1.27 texp0=1.5 ++ tcvth=-0.0065 MU=-1.27 texp0=1.5 + Rthjc=0.4 Cthj=0.1 + mtriode=0.8 diff --git a/examples/probe/VDMOS_models.lib b/examples/probe/VDMOS_models.lib index b53103398..a95cfe5f5 100644 --- a/examples/probe/VDMOS_models.lib +++ b/examples/probe/VDMOS_models.lib @@ -4,7 +4,7 @@ + Cgdmax=2.45n Cgdmin=10p a=0.3 Cgs=1.2n + Is=60p N=1.1 Rb=14m XTI=3 + Cjo=1.5n Vj=0.8 m=0.5 -+ tcvth=0.0065 MU=-1.27 texp0=1.5 ++ tcvth=-0.0065 MU=-1.27 texp0=1.5 + Rthjc=0.4 Cthj=0.1 + mtriode=0.8 diff --git a/examples/vdmos/100W.sp b/examples/vdmos/100W.sp index c8e7d2962..6fcd63d00 100644 --- a/examples/vdmos/100W.sp +++ b/examples/vdmos/100W.sp @@ -84,7 +84,7 @@ plot inoise_spectrum + Cgdmax=2.45n Cgdmin=10p a=0.3 Cgs=1.2n + Is=60p N=1.1 Rb=14m XTI=3 + Cjo=1.5n Vj=0.8 m=0.5 -+ tcvth=0.0065 MU=-1.27 texp0=1.5 ++ tcvth=-0.0065 MU=-1.27 texp0=1.5 + Rthjc=0.4 Cthj=5e-3 + mtriode=0.8 .model IRFP9240 VDMOS pchan diff --git a/examples/vdmos/100W_wingspread.sp b/examples/vdmos/100W_wingspread.sp index 3af6383e5..5e18917db 100644 --- a/examples/vdmos/100W_wingspread.sp +++ b/examples/vdmos/100W_wingspread.sp @@ -67,7 +67,7 @@ end + Cgdmax=2.45n Cgdmin=10p a=0.3 Cgs=1.2n + Is=60p N=1.1 Rb=14m XTI=3 + Cjo=1.5n Vj=0.8 m=0.5 -+ tcvth=0.0065 MU=-1.27 texp0=1.5 ++ tcvth=-0.0065 MU=-1.27 texp0=1.5 *+ Rthjc=0.4 Cthj=5e-3 + mtriode=0.8 .model IRFP9240 VDMOS pchan diff --git a/examples/vdmos/crss_coss_ciss.sp b/examples/vdmos/crss_coss_ciss.sp index 44f44bb94..6ff310399 100644 --- a/examples/vdmos/crss_coss_ciss.sp +++ b/examples/vdmos/crss_coss_ciss.sp @@ -40,7 +40,7 @@ plot 'i(v6)/deriv(v(d4))' vs v(d2p) xlog xlimit 1 100 ylimit 0 3n title "IRFP924 + Cgdmax=2.45n Cgdmin=10p a=0.3 Cgs=1.2n + Is=60p N=1.1 Rb=14m XTI=3 + Cjo=1.5n Vj=0.8 m=0.5 -+ tcvth=0.0065 MU=-1.27 texp0=1.5 ++ tcvth=-0.0065 MU=-1.27 texp0=1.5 *+ Rthjc=0.4 Cthj=5e-3 + mtriode=0.8 .model IRFP9240 VDMOS pchan diff --git a/examples/vdmos/dcdc.sp b/examples/vdmos/dcdc.sp index 6e32a54de..46b239b89 100644 --- a/examples/vdmos/dcdc.sp +++ b/examples/vdmos/dcdc.sp @@ -26,7 +26,7 @@ V4 out2 0 0.0 + Cgdmax=.2n Cgdmin=.05n a=0.3 Cgs=.12n + Is=17p N=1.1 Rb=80m XTI=3 + Cjo=.25n Vj=0.8 m=0.5 -+ tcvth=0.007 MU=-1.27 texp0=1.5 ++ tcvth=-0.007 MU=-1.27 texp0=1.5 .model MBRS340 D(Is=22.6u Rs=.042 N=1.094 Cjo=480p M=.61 Eg=.69 Xti=2) diff --git a/examples/vdmos/self-heating.sp b/examples/vdmos/self-heating.sp index 5de456a2b..90edbc847 100644 --- a/examples/vdmos/self-heating.sp +++ b/examples/vdmos/self-heating.sp @@ -10,7 +10,7 @@ VD D 0 2V + Cgdmax=2.45n Cgdmin=10p a=0.3 Cgs=1.2n + Is=60p N=1.1 Rb=14m XTI=3 + Cjo=1.5n Vj=0.8 m=0.5 -+ tcvth=0.0065 MU=-1.27 texp0=1.5 ++ tcvth=-0.0065 MU=-1.27 texp0=1.5 + Rthjc=0.02 Cthj=1e-3 Rthca=1000 + mtriode=0.8 .control diff --git a/examples/vdmos/soa_chk.sp b/examples/vdmos/soa_chk.sp index ea84d89f2..8d1278185 100644 --- a/examples/vdmos/soa_chk.sp +++ b/examples/vdmos/soa_chk.sp @@ -5,7 +5,7 @@ VDMOS SOA check + Rd=61m Rs=18m Rg=3 Rds=1e7 + Cgdmax=2.45n Cgdmin=10p a=0.3 Cgs=1.2n + Is=60p N=1.1 Rb=14m Cjo=1.5n XTI=3 -+ tcvth=0.0065 MU=-1.27 texp0=1.5 ++ tcvth=-0.0065 MU=-1.27 texp0=1.5 + mtriode=0.8 + Vgs_max=20 Vgd_max=20 Vds_max=200 diff --git a/src/spicelib/devices/vdmos/vdmostemp.c b/src/spicelib/devices/vdmos/vdmostemp.c index 202a4611a..36010a87f 100644 --- a/src/spicelib/devices/vdmos/vdmostemp.c +++ b/src/spicelib/devices/vdmos/vdmostemp.c @@ -47,7 +47,7 @@ void VDMOStempUpdate(VDMOSmodel *inModel, VDMOSinstance *here, double Temp, CKTc here->VDMOStTransconductance = model->VDMOStransconductance * here->VDMOSm * pow(ratio, model->VDMOSmu); - here->VDMOStVth = model->VDMOSvth0 - model->VDMOStype * model->VDMOStcvth * dt; + here->VDMOStVth = model->VDMOSvth0 + model->VDMOStcvth * dt; here->VDMOStksubthres = model->VDMOSksubthres * (1.0 + (model->VDMOStksubthres1 * dt) + (model->VDMOStksubthres2 * dt * dt)); From 1841709eaba603fc39fc59d356075029f3340cf7 Mon Sep 17 00:00:00 2001 From: dwarning Date: Sat, 3 Jan 2026 09:04:40 +0100 Subject: [PATCH 102/161] more realistic default values for case to ambient thermal resistance and device transconductances --- src/spicelib/devices/vdmos/vdmosset.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spicelib/devices/vdmos/vdmosset.c b/src/spicelib/devices/vdmos/vdmosset.c index dfc6a2da3..0adfce318 100644 --- a/src/spicelib/devices/vdmos/vdmosset.c +++ b/src/spicelib/devices/vdmos/vdmosset.c @@ -32,7 +32,7 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, model->VDMOStype = NMOS; if (!model->VDMOStransconductanceGiven) - model->VDMOStransconductance = 25 + 10 * model->VDMOStype; /* IRF540, 9540 */ + model->VDMOStransconductance = 15 + 5 * model->VDMOStype; /* IRF540, 9540 */ if (!model->VDMOSvth0Given) model->VDMOSvth0 = 3 * model->VDMOStype; /* IRF540, 9540 */ @@ -128,7 +128,7 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, model->VDMOSrthjc = 1.0; if (!model->VDMOSrthcaGiven) - model->VDMOSrthca = 1000; + model->VDMOSrthca = 23; /* e.g. TO220 case */ if (!model->VDMOScthjGiven) model->VDMOScthj = 10e-06; From 4fd68ba901f88778ab760cdb9614d1e0b85736bd Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 7 Jan 2026 20:12:35 +0100 Subject: [PATCH 103/161] enable simulation with 'option newtrunc' --- examples/soi/ring51_40.sp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/soi/ring51_40.sp b/examples/soi/ring51_40.sp index 0c833466a..fa583f81e 100644 --- a/examples/soi/ring51_40.sp +++ b/examples/soi/ring51_40.sp @@ -14,6 +14,7 @@ cout buf ss 1pF * this is needed .option reltol=1e-4 +.option ltereltol=1e-4 .tran 0.2n 16n .print tran v(out25) v(out50) @@ -48,6 +49,7 @@ if $?batchmode else save out25 out50 run + rusage time plot out25 out50 let lin-tstart = 4n $ skip the start-up phase let lin-tstop = 14n $ end earlier(just for demonstration) From cd6ca5e86a7f7c25e0b4135f3a5d7e1f2c5ae3d1 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 7 Jan 2026 20:13:48 +0100 Subject: [PATCH 104/161] re-enable maling old app ngsconvert ngnutmeg is still defect --- src/frontend/rawfile.c | 3 ++- src/ngsconvert.c | 13 ++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/frontend/rawfile.c b/src/frontend/rawfile.c index 4a1359163..2871ae5ab 100644 --- a/src/frontend/rawfile.c +++ b/src/frontend/rawfile.c @@ -114,7 +114,8 @@ void raw_write(char *name, struct plot *pl, bool app, bool binary) fprintf(fp, "Title: %s\n", pl->pl_title); fprintf(fp, "Date: %s\n", pl->pl_date); - fprintf(fp, "Command: %s-%s, Build %s\n", ft_sim->simulator, ft_sim->version, Spice_Build_Date); + if (ft_sim) /* not available when old app ngscovert is made */ + fprintf(fp, "Command: %s-%s, Build %s\n", ft_sim->simulator, ft_sim->version, Spice_Build_Date); fprintf(fp, "Plotname: %s\n", pl->pl_name); fprintf(fp, "Flags: %s%s\n", realflag ? "real" : "complex", raw_padding ? "" : " unpadded"); diff --git a/src/ngsconvert.c b/src/ngsconvert.c index c3396f461..0fb17226b 100644 --- a/src/ngsconvert.c +++ b/src/ngsconvert.c @@ -40,6 +40,9 @@ bool cp_no_histsubst = FALSE; struct compat newcompat; bool cx_degrees = FALSE; +IFsimulator *ft_sim = NULL; +char Spice_Build_Date[] = " date is not available\n"; + char *cp_program = "sconvert"; @@ -56,6 +59,15 @@ char *cp_program = "sconvert"; #define TMALLOC(t, n) (t*) tmalloc(sizeof(t) * (size_t)(n)) #define TREALLOC(t, p, n) (t*) trealloc(p, sizeof(t) * (size_t)(n)) +FILE * +newfopen(const char *fn, const char* md) +{ + FILE* fp; + if (fn == NULL) + return NULL; + fp = fopen(fn, md); + return fp; +} char * smktemp(char *id) @@ -488,7 +500,6 @@ main(int ac, char **av) exit(EXIT_NORMAL); } - void cp_pushcontrol(void) { } void cp_popcontrol(void) { } void out_init(void) { } From 48438ba7365b5cc3ac5d40df3d409c6e11b838a3 Mon Sep 17 00:00:00 2001 From: dwarning Date: Thu, 8 Jan 2026 22:34:10 +0100 Subject: [PATCH 105/161] rm ngnutmeg from build list of old apps --- src/Makefile.am | 41 +---------------------------------------- 1 file changed, 1 insertion(+), 40 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index d1cedb9bf..76dad79db 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,7 +21,7 @@ bin_PROGRAMS = ngspice if OLDAPPS if !WINGUI -bin_PROGRAMS += ngnutmeg ngsconvert ngproc2mod ngmultidec ngmakeidx +bin_PROGRAMS += ngsconvert ngproc2mod ngmultidec ngmakeidx helpdatadir = $(pkgdatadir)/helpdir helpdata_DATA = ngspice.txt ngspice.idx if !NO_HELP @@ -220,50 +220,11 @@ endif $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --tag=RC --mode=compile $(RC) $(RCFLAGS) $< -o $@ if OLDAPPS -## nutmeg: - -ngnutmeg_SOURCES = \ - main.c \ - conf.c \ - conf.h \ - ngnutmeg.c - -ngnutmeg_CPPFLAGS = $(AM_CPPFLAGS) - -if WINGUI -ngnutmeg_SOURCES += winmain.c hist_info.c -endif - -ngnutmeg_LDADD = \ - frontend/libfte.la - -if WINGUI -ngnutmeg_LDADD += \ - frontend/wdisp/libwindisp.la -endif - -ngnutmeg_LDADD += \ - frontend/plotting/libplotting.la \ - frontend/parser/libparser.la \ - frontend/numparam/libnumparam.la \ - frontend/trannoise/libtrannoise.la \ - maths/cmaths/libcmaths.la \ - maths/misc/libmathmisc.la \ - maths/fft/libmathfft.la \ - maths/poly/libpoly.la \ - misc/libmisc.la \ - spicelib/parser/libinp.la - ## These programs are not required on Windows if !WINGUI if !SHWIN -if !NO_X -ngnutmeg_LDADD += \ - frontend/help/libhlp.la -endif !NO_X - ## help: nghelp_SOURCES = conf.c nghelp.c From 06aa4989a62f85787fd1188ecd65c57ce391c315 Mon Sep 17 00:00:00 2001 From: dwarning Date: Thu, 8 Jan 2026 22:35:52 +0100 Subject: [PATCH 106/161] convert to lower case for spice2 input and remove few warnings --- src/ngsconvert.c | 45 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/src/ngsconvert.c b/src/ngsconvert.c index 0fb17226b..01c4d768d 100644 --- a/src/ngsconvert.c +++ b/src/ngsconvert.c @@ -21,6 +21,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group #include +int input(FILE *fp); FILE *cp_in = NULL; FILE *cp_out = NULL; @@ -59,6 +60,7 @@ char *cp_program = "sconvert"; #define TMALLOC(t, n) (t*) tmalloc(sizeof(t) * (size_t)(n)) #define TREALLOC(t, p, n) (t*) trealloc(p, sizeof(t) * (size_t)(n)) +#if defined(__MINGW32__) || defined(_MSC_VER) FILE * newfopen(const char *fn, const char* md) { @@ -68,6 +70,7 @@ newfopen(const char *fn, const char* md) fp = fopen(fn, md); return fp; } +#endif char * smktemp(char *id) @@ -204,7 +207,11 @@ oldread(char *name) pl->pl_scale = pl->pl_dvecs = v; end = v; tfread(buf, 1, 8, fp); - buf[8] = '\0'; + for (j = 0; j < 8; j++) { + if (buf[j] == ' ') break; + buf[j] = (char) tolower((unsigned char) buf[j]); + } + buf[j] = '\0'; v->v_name = strdup(buf); } for (v = pl->pl_dvecs; v; v = v->v_next) { @@ -392,15 +399,19 @@ oldwrite(char *name, bool app, struct plot *pl) int main(int ac, char **av) { - char *sf, *af; + char *sf = NULL, *af = NULL; char buf[BSIZE_SP]; - char t, f; + char t = 0, f = 0; struct plot *pl; size_t n; char *infile = NULL; char *outfile = NULL; FILE *fp; + cp_in = stdin; + cp_out = stdout; + cp_err = stderr; + switch (ac) { case 5: sf = av[2]; @@ -426,20 +437,32 @@ main(int ac, char **av) case 1: printf("Input file: "); (void) fflush(stdout); - (void) fgets(buf, BSIZE_SP, stdin); - sf = strdup(buf); + if (fgets(buf, BSIZE_SP, stdin) != NULL) { + sf = strdup(buf); + } else { + printf("Error reading input file."); + } printf("Input type: "); (void) fflush(stdout); - (void) fgets(buf, BSIZE_SP, stdin); - f = buf[0]; + if (fgets(buf, BSIZE_SP, stdin) != NULL) { + f = buf[0]; + } else { + printf("Error reading input type."); + } printf("Output file: "); (void) fflush(stdout); - (void) fgets(buf, BSIZE_SP, stdin); - af = strdup(buf); + if (fgets(buf, BSIZE_SP, stdin) != NULL) { + af = strdup(buf); + } else { + printf("Error reading output file."); + } printf("Output type: "); (void) fflush(stdout); - (void) fgets(buf, BSIZE_SP, stdin); - t = buf[0]; + if (fgets(buf, BSIZE_SP, stdin) != NULL) { + t = buf[0]; + } else { + printf("Error reading output type."); + } break; default: fprintf(cp_err, From 81894e0c526c5424355609d9772032d2a19bdbc0 Mon Sep 17 00:00:00 2001 From: dwarning Date: Fri, 9 Jan 2026 12:57:49 +0100 Subject: [PATCH 107/161] Minor change that helps VADistiller. --- src/spicelib/devices/dio/dioload.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/spicelib/devices/dio/dioload.c b/src/spicelib/devices/dio/dioload.c index d7243d5b1..6f53966eb 100644 --- a/src/spicelib/devices/dio/dioload.c +++ b/src/spicelib/devices/dio/dioload.c @@ -707,9 +707,9 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd; *(ckt->CKTrhs + here->DIOtempNode) += Ith - dIth_dVdio*vd - dIth_dVrs*vrs - dIth_dT*delTemp - ceqqth; } if (model->DIOresistSWGiven) { - cdeq=cdsw-gdsw*vdsw; - *(ckt->CKTrhs + here->DIOnegNode) += cdeq; - *(ckt->CKTrhs + here->DIOposSwPrimeNode) -= cdeq; + double cdeqsw=cdsw-gdsw*vdsw; + *(ckt->CKTrhs + here->DIOnegNode) += cdeqsw; + *(ckt->CKTrhs + here->DIOposSwPrimeNode) -= cdeqsw; if (selfheat) { *(ckt->CKTrhs + here->DIOposNode) += dIrssw_dT*delTemp; *(ckt->CKTrhs + here->DIOposSwPrimeNode) += dIdioSw_dT*delTemp - dIrssw_dT*delTemp; From 23eafe9978962befae7f8d100197ff5d3aa59c80 Mon Sep 17 00:00:00 2001 From: dwarning Date: Fri, 9 Jan 2026 16:07:38 +0100 Subject: [PATCH 108/161] remove redundant definition and unused variable --- src/frontend/rawfile.c | 1 - src/spicelib/analysis/noisean.c | 1 - 2 files changed, 2 deletions(-) diff --git a/src/frontend/rawfile.c b/src/frontend/rawfile.c index 2871ae5ab..1ecf834b5 100644 --- a/src/frontend/rawfile.c +++ b/src/frontend/rawfile.c @@ -22,7 +22,6 @@ Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group #include "ngspice/compatmode.h" extern IFsimulator SIMinfo; -extern char Spice_Build_Date[]; static void fixdims(struct dvec *v, char *s); diff --git a/src/spicelib/analysis/noisean.c b/src/spicelib/analysis/noisean.c index 3eeca41f2..29f880452 100644 --- a/src/spicelib/analysis/noisean.c +++ b/src/spicelib/analysis/noisean.c @@ -61,7 +61,6 @@ NOISEan(CKTcircuit* ckt, int restart) int numNames; IFuid* nameList; /* va: tmalloc'ed list of names */ - static runDesc* noiPlot = NULL; runDesc* plot = NULL; #ifdef XSPICE From 86ca3948ebf5952e0145c803be02ba8319162b90 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 13 Jan 2026 15:50:03 +0100 Subject: [PATCH 109/161] Better graphics --- examples/memristor/memristor.sp | 1 + examples/memristor/memristor_x.sp | 1 + 2 files changed, 2 insertions(+) diff --git a/examples/memristor/memristor.sp b/examples/memristor/memristor.sp index 0664f1075..c41787430 100644 --- a/examples/memristor/memristor.sp +++ b/examples/memristor/memristor.sp @@ -51,6 +51,7 @@ let newstime = stime/1.4 let deltime = newstime/100 alter @V1[sin] [ 0 $&vmax $&newfreq ] tran $&deltime $&newstime uic +set xbrushwidth=2 * the 'programming' currents plot tran1.alli tran2.alli alli title 'Memristor with threshold: Internal Programming currents' * resistance versus time plot diff --git a/examples/memristor/memristor_x.sp b/examples/memristor/memristor_x.sp index 198cb979b..a9bf93198 100644 --- a/examples/memristor/memristor_x.sp +++ b/examples/memristor/memristor_x.sp @@ -65,6 +65,7 @@ let newstime = stime/1.4 let deltime = newstime/100 alter @V1[sin] [ 0 $&vmax $&newfreq ] tran $&deltime $&newstime uic +set xbrushwidth=2 * the resistor currents plot tran1.alli tran2.alli alli title 'Memristor with threshold: currents' * calculate resistance (avoid dividing by zero) From 1601571432e911abfd924d64bc4b21177e6afa06 Mon Sep 17 00:00:00 2001 From: dwarning Date: Fri, 16 Jan 2026 08:38:37 +0100 Subject: [PATCH 110/161] Correct vgs assignment - bug found by K. OHara --- src/spicelib/devices/vdmos/vdmosconv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spicelib/devices/vdmos/vdmosconv.c b/src/spicelib/devices/vdmos/vdmosconv.c index 49e0ccde8..2bbed8050 100644 --- a/src/spicelib/devices/vdmos/vdmosconv.c +++ b/src/spicelib/devices/vdmos/vdmosconv.c @@ -32,7 +32,7 @@ VDMOSconvTest(GENmodel *inModel, CKTcircuit *ckt) here = VDMOSnextInstance(here)) { vgs = model->VDMOStype * ( - *(ckt->CKTrhs+here->VDMOSgNode) - + *(ckt->CKTrhs+here->VDMOSgNodePrime) - *(ckt->CKTrhs+here->VDMOSsNodePrime)); vds = model->VDMOStype * ( *(ckt->CKTrhs+here->VDMOSdNodePrime) - From 84ce2b4084fe3a044fc83a37e8d08e97cdf47bf5 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 16 Jan 2026 15:43:48 +0100 Subject: [PATCH 111/161] Exclude B voltage source, whan '.probe alli' is used. It already gets a bxx#branch for current measurement. --- src/frontend/inpc_probe.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/frontend/inpc_probe.c b/src/frontend/inpc_probe.c index 99c4bcc5d..e77437bef 100644 --- a/src/frontend/inpc_probe.c +++ b/src/frontend/inpc_probe.c @@ -240,6 +240,10 @@ void inp_probe(struct card* deck) if (strchr("ehvk", *instname)) continue; + /* exclude B voltage source */ + if (strchr("b", *instname) && strstr(curr_line, "v=")) + continue; + /* exclude a devices (code models may have special characters in their instance line. digital nodes should not get V sources in series anyway.) */ if ('a' == *instname) From b25ff08307df45c701c136d6a48c03c863d5a328 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 20 Jan 2026 15:24:52 +0100 Subject: [PATCH 112/161] Moving window filtering with function 'newvec = mtimeavg(vec)' Window of fixed time width given by 'set mtimeavgwindow=400u' Length and scale of newvec resembles the original vetor vec. Large vec and large mtimeavgwindow take their time. OpenMP is used if available. --- src/frontend/evaluate.c | 2 +- src/frontend/parse.c | 1 + src/include/ngspice/fteext.h | 1 + src/maths/cmaths/cmath4.c | 126 +++++++++++++++++++++++++++++++++++ src/maths/cmaths/cmath4.h | 2 + 5 files changed, 131 insertions(+), 1 deletion(-) diff --git a/src/frontend/evaluate.c b/src/frontend/evaluate.c index 42fc4540b..01127e1d0 100644 --- a/src/frontend/evaluate.c +++ b/src/frontend/evaluate.c @@ -858,7 +858,7 @@ apply_func_funcall(struct func *func, struct dvec *v, int *newlength, short int /* Modified for passing necessary parameters to the derive function - A.Roldan */ if (eq(func->fu_name, "interpolate") || eq(func->fu_name, "deriv") || eq(func->fu_name, "group_delay") - || eq(func->fu_name, "fft") || eq(func->fu_name, "ifft") || eq(func->fu_name, "integ")) + || eq(func->fu_name, "fft") || eq(func->fu_name, "ifft") || eq(func->fu_name, "integ") || eq(func->fu_name, "mtimeavg")) { void * (*f) (void *data, short int type, int length, int *newlength, short int *newtype, diff --git a/src/frontend/parse.c b/src/frontend/parse.c index f575ecbe7..24cc1e9e7 100644 --- a/src/frontend/parse.c +++ b/src/frontend/parse.c @@ -380,6 +380,7 @@ struct func ft_funcs[] = { { "integ", (cx_function_t*)(void *) cx_integ }, { "fft", (cx_function_t*)(void *) cx_fft }, { "ifft", (cx_function_t*)(void *) cx_ifft }, + { "mtimeavg", (cx_function_t*)(void *) cx_mtimeavg }, { "v", NULL }, { NULL, NULL } }; diff --git a/src/include/ngspice/fteext.h b/src/include/ngspice/fteext.h index 541c7f8c0..69d428b51 100644 --- a/src/include/ngspice/fteext.h +++ b/src/include/ngspice/fteext.h @@ -129,6 +129,7 @@ extern void *cx_integ(void *, short int , int , int *, short int *, struct plot extern void *cx_group_delay(void *, short int , int , int *, short int *, struct plot *, struct plot *, int ); extern void *cx_fft(void *, short int , int , int *, short int *, struct plot *, struct plot *, int ); extern void *cx_ifft(void *, short int , int , int *, short int *, struct plot *, struct plot *, int ); +extern void *cx_mtimeavg(void *, short int , int , int *, short int *, struct plot *, struct plot *, int ); /* define.c */ diff --git a/src/maths/cmaths/cmath4.c b/src/maths/cmaths/cmath4.c index 63b03f0a6..870bee140 100644 --- a/src/maths/cmaths/cmath4.c +++ b/src/maths/cmaths/cmath4.c @@ -33,6 +33,9 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group #include "ngspice/sim.h" /* To get SV_TIME */ #include "ngspice/fftext.h" +#include "ngspice/cktdefs.h" /* ft_curckt */ +#include "ngspice/ftedefs.h" /* ft_curckt */ +#include "ngspice/fteext.h" /* ft_curckt */ extern bool cx_degrees; extern void vec_new(struct dvec *d); @@ -988,3 +991,126 @@ cx_ifft(void *data, short int type, int length, int *newlength, short int *newty return ((void *) outdata); } + +/* Compute the moving average of a vector, + * resulting from a transient simulation, + * over a time window given by variable mtimeavgwindow. + * Create the average over each original time point + * +/- mtimeavgwindow/2. + */ +void* +cx_mtimeavg(void* data, short int type, int length, int* newlength, short int* newtype, struct plot* pl, struct plot* newpl, int grouping) +{ + double tdelta = 0.0, tstart=0.0, tstop=0.0, tdeltahalf; + struct dvec *sc; + int i; + double* d, * dd, * dsc; + + if (grouping == 0) + grouping = length; + + int nlen = length - 1; + + if (!pl || !pl->pl_scale || !newpl || !newpl->pl_scale) { + fprintf(cp_err, "Internal error mtimeavg: bad scale\n"); + return (NULL); + } + + /* Check to see if we have the time vector as scale */ + if (!isreal(pl->pl_scale) || + ((pl->pl_scale)->v_type != SV_TIME)) { + fprintf(cp_err, "Error: mtimeavg needs real time scale\n"); + return (NULL); + } + + if (type != VF_REAL) { + fprintf(cp_err, "Error: mtimeavg needs a real valued vector.\n"); + return (NULL); + } + + if (!cp_getvar("mtimeavgwindow", CP_REAL, &tdelta, 0)) + if (ft_curckt == (struct circ*)NULL) { + tdelta = 1e-6; + fprintf(cp_out, "Note: mtimeavgwindow not given, window set to %g s\n", tdelta); + } + else { + CKTcircuit* ckt = ft_curckt->ci_ckt; + tdelta = 10.0 * ckt->CKTstep; + fprintf(cp_out, "Note: mtimeavgwindow not given, window set to %g s\n", tdelta); + } + + sc = pl->pl_scale; + dsc = sc->v_realdata; + + d = alloc_d(length); + dd = (double*)data; + + tstart = dsc[0]; + tstop = dsc[nlen]; + tdeltahalf = tdelta / 2.; + *newtype = VF_REAL; + *newlength = length; + +#ifdef USE_OMP +#pragma omp parallel + { +#pragma omp for +#endif + for (i = 0; i < length; i++) { + int j, ibeg, iend, k; + double tbeg, tend, ttruebeg, ttrueend, truedelta; + double integ; + double tmid = dsc[i]; + + ttruebeg = tmid - tdeltahalf; + ttrueend = tmid + tdeltahalf; + tbeg = tstop; + tend = tstart; + /* start of the interval */ + j = i; + while (j > 0 && tbeg > ttruebeg) { + tbeg = dsc[j]; + j--; + } + ibeg = j; + + /* end of the interval */ + j = i; + while (j < nlen && tend < ttrueend) { + tend = dsc[j]; + j++; + } + iend = j; + + /* integrate the data */ + integ = 0.; + for (k = ibeg; k < iend; k++) { + integ = integ + dd[k] * (dsc[k + 1] - dsc[k]); + } + + /* cut a little from integ on the lower border, interpolated */ + if (ibeg > 0) { + integ = integ - (dsc[ibeg] - ttruebeg) * dd[ibeg]; + } + /* add a little to integ on the upper border, interpolated */ + if (iend < nlen) { + integ = integ + (dsc[iend] - ttrueend) * dd[iend]; + } + /* when on the edges of the vector, set reduced time windows */ + if (ibeg == 0) + truedelta = dsc[i] + tdeltahalf; + else if (iend == nlen) + truedelta = dsc[nlen] - dsc[i] + tdeltahalf; + else + truedelta = tdelta; + + d[i] = integ / truedelta; + + // fprintf(stdout, "%d %d %d %e %e..%e %e\n", i, ibeg, iend, dsc[ibeg], dsc[iend], ttruebeg, ttrueend); + } +#ifdef USE_OMP + } +#endif + return ((void*)d); +} + diff --git a/src/maths/cmaths/cmath4.h b/src/maths/cmaths/cmath4.h index 5b52f90b2..f4f9111d4 100644 --- a/src/maths/cmaths/cmath4.h +++ b/src/maths/cmaths/cmath4.h @@ -25,5 +25,7 @@ void * cx_fft(void *data, short int type, int length, int *newlength, short int struct plot *pl, struct plot *newpl, int grouping); void * cx_ifft(void *data, short int type, int length, int *newlength, short int *newtype, struct plot *pl, struct plot *newpl, int grouping); +void* cx_mtimeavg(void* data, short int type, int length, int* newlength, short int* newtype, + struct plot* pl, struct plot* newpl, int grouping); #endif From ab03cc94c07014996708daacebdc3aa99c2e12e9 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 20 Jan 2026 15:30:28 +0100 Subject: [PATCH 113/161] Using mtimeavg --- examples/various/mtimeavg_test.cir | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 examples/various/mtimeavg_test.cir diff --git a/examples/various/mtimeavg_test.cir b/examples/various/mtimeavg_test.cir new file mode 100644 index 000000000..90b8068b5 --- /dev/null +++ b/examples/various/mtimeavg_test.cir @@ -0,0 +1,27 @@ +test mtimeavg + +* noise source + +VNoiw 1 0 DC 0 TRNOISE(20n 0.5n 0 0) + +.control +tran 0.5n 500n +set color3=orange +set color5=red +set mtimeavgwindow=5n +let filtered5n = mtimeavg(V(1)) +set mtimeavgwindow=10n +let filtered10n = mtimeavg(V(1)) +set mtimeavgwindow=20n +let filtered20n = mtimeavg(V(1)) +set mtimeavgwindow=50n +let filtered50n = mtimeavg(V(1)) +set xbrushwidth=2 +set color0=white +plot filtered5n filtered10n filtered20n filtered50n ylimit -50n 50n +set xbrushwidth=1 +set color3=red +plot V(1) filtered50n ylimit -50n 50n +.endc + +.end From afb17cb6c70c431162e3f7ca5a2e318f75b90e50 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 23 Jan 2026 19:50:26 +0100 Subject: [PATCH 114/161] New analogue and digital device models from TI contain the token GND in their subcircuit. Up to now ngspice has declared GND as global and replaced it by 0. Now, if PS is selected as compat mode, GND is not declared as global, and is not replaced inside of a subcircuit. --- src/frontend/inpcom.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index c388d667e..4cf3b2edf 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -1860,11 +1860,13 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name comfile = TRUE; if (call_depth == 0 && !comfile) { - if (!cp_getvar("no_auto_gnd", CP_BOOL, NULL, 0)) + if (!cp_getvar("no_auto_gnd", CP_BOOL, NULL, 0) && !newcompat.ps) insert_new_line(cc, copy(".global gnd"), 1, 0, "internal"); - else + else { insert_new_line( - cc, copy("* gnd is not set to 0 automatically "), 1, 0, "internal"); + cc, copy("* gnd is not set to 0 automatically "), 1, 0, "internal"); + fprintf(stdout, "Note: gnd in a subcircuit is not set to 0 automatically\n"); + } if (!newcompat.lt && !newcompat.ps && !newcompat.s3) { /* process all library section references */ @@ -2295,12 +2297,20 @@ static char *readline(FILE *fd) static void inp_fix_gnd_name(struct card *c) { + bool found_subckt = FALSE; for (; c; c = c->nextcard) { - char *gnd = c->line; + // if inside of a subcircuit, and compatmode is ps, don't replace gnd + if (newcompat.ps) { + if (ciprefix(".subckt", c->line)) + found_subckt = TRUE; + if (ciprefix(".ends", c->line)) + found_subckt = FALSE; + } + // if there is a comment or no gnd, go to next line - if ((*gnd == '*') || !strstr(gnd, "gnd")) + if (found_subckt || (*gnd == '*') || !strstr(gnd, "gnd")) continue; // replace "?gnd?" by "? 0 ?", ? being a ' ' ',' '(' ')'. From ab87bd57a4a047bf7a9dd5fc4f4688a72eaf4a25 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 3 Feb 2026 13:42:25 +0100 Subject: [PATCH 115/161] Re-enable compiling with clang Patch thanks to Gon Solo, issue 826 --- src/include/cppduals/duals/dual | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/include/cppduals/duals/dual b/src/include/cppduals/duals/dual index 4cb227e84..1e46b4c23 100644 --- a/src/include/cppduals/duals/dual +++ b/src/include/cppduals/duals/dual @@ -485,9 +485,6 @@ struct is_arithmetic> : is_arithmetic {}; #endif // CPPDUALS_ENABLE_IS_ARITHMETIC -/// Duals are compound types. -template -struct is_compound> : true_type {}; // Modification of std::numeric_limits<> per // C++03 17.4.3.1/1, and C++11 18.3.2.3/1. From 417c52ee5c92db131d678064e1e097bc4d66c82b Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 3 Feb 2026 15:05:24 +0100 Subject: [PATCH 116/161] Remove compiler warnings --- src/maths/cmaths/cmath2.c | 1 - src/maths/cmaths/cmath4.c | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/maths/cmaths/cmath2.c b/src/maths/cmaths/cmath2.c index 7af7cd84e..d6ce651af 100644 --- a/src/maths/cmaths/cmath2.c +++ b/src/maths/cmaths/cmath2.c @@ -369,7 +369,6 @@ cx_avg(void *data, short int type, int length, int *newlength, short int *newtyp void* cx_m3avg(void* data, short int type, int length, int* newlength, short int* newtype) { - double sum_real = 0.0, sum_imag = 0.0; int i; if (type == VF_REAL) { diff --git a/src/maths/cmaths/cmath4.c b/src/maths/cmaths/cmath4.c index 870bee140..a1f547d97 100644 --- a/src/maths/cmaths/cmath4.c +++ b/src/maths/cmaths/cmath4.c @@ -1028,7 +1028,7 @@ cx_mtimeavg(void* data, short int type, int length, int* newlength, short int* n return (NULL); } - if (!cp_getvar("mtimeavgwindow", CP_REAL, &tdelta, 0)) + if (!cp_getvar("mtimeavgwindow", CP_REAL, &tdelta, 0)) { if (ft_curckt == (struct circ*)NULL) { tdelta = 1e-6; fprintf(cp_out, "Note: mtimeavgwindow not given, window set to %g s\n", tdelta); @@ -1038,6 +1038,7 @@ cx_mtimeavg(void* data, short int type, int length, int* newlength, short int* n tdelta = 10.0 * ckt->CKTstep; fprintf(cp_out, "Note: mtimeavgwindow not given, window set to %g s\n", tdelta); } + } sc = pl->pl_scale; dsc = sc->v_realdata; From 9ac5bda20774eabfb40e7f61f7c009a850c00b17 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 3 Feb 2026 22:38:56 +0100 Subject: [PATCH 117/161] After an ac simulation, a tran measurement causes a segfault. A check prevents this issue. --- src/frontend/com_measure2.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/frontend/com_measure2.c b/src/frontend/com_measure2.c index 7fa30d352..fd371edcd 100644 --- a/src/frontend/com_measure2.c +++ b/src/frontend/com_measure2.c @@ -439,8 +439,13 @@ com_measure_when( sp_check = TRUE; else if (cieq (meas->m_analysis, "dc")) dc_check = TRUE; - else + else { tran_check = TRUE; + if (!d->v_realdata) { + fprintf(stderr, "Error: no real data available for measurement (no tran simulation?)\n"); + return MEASUREMENT_FAILURE; + } + } for (i = 0; i < d->v_length; i++) { @@ -697,8 +702,13 @@ measure_at( sp_check = TRUE; else if (cieq (meas->m_analysis, "dc")) dc_check = TRUE; - else + else { tran_check = TRUE; + if (!d->v_realdata) { + fprintf(stderr, "Error: no real data available for measurement (no tran simulation?)\n"); + return MEASUREMENT_FAILURE; + } + } for (i = 0; i < d->v_length; i++) { if (ac_check) { From 81d3812db07c254f7df81c843e49e1d194195d53 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 7 Feb 2026 13:21:54 +0100 Subject: [PATCH 118/161] Add a user-settable variable measureprec to set the number of digits when printing the measure outputs. Internally this is a global variable measure_precision. Enable all measure commands to recognize measure_precision when printing an output. Default value is 5 (yielding 6 digits after .?). --- src/frontend/com_measure2.c | 43 +++++++++++++++++++++++++----------- src/frontend/miscvars.c | 1 + src/frontend/options.c | 12 +++++++++- src/include/ngspice/fteext.h | 3 +++ 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/frontend/com_measure2.c b/src/frontend/com_measure2.c index fd371edcd..29b6e63c9 100644 --- a/src/frontend/com_measure2.c +++ b/src/frontend/com_measure2.c @@ -16,6 +16,8 @@ #include "com_measure2.h" #include "breakp2.h" +int measure_precision = -1; + typedef enum { MEASUREMENT_OK = 0, MEASUREMENT_FAILURE = 1 @@ -86,6 +88,9 @@ measure_get_precision(void) if ((env_ptr = getenv("NGSPICE_MEAS_PRECISION")) != NULL) precision = atoi(env_ptr); + if (measure_precision > 0) + precision = measure_precision; + return precision; } @@ -1810,9 +1815,13 @@ get_measure2( // print results if (out_line) - sprintf(out_line, "%-20s= %e targ= %e trig= %e\n", mName, (measTarg->m_measured - measTrig->m_measured), measTarg->m_measured, measTrig->m_measured); + sprintf(out_line, "%-20s= %.*e targ= %.*e trig= %.*e\n", + mName, precision, (measTarg->m_measured - measTrig->m_measured), + precision, measTarg->m_measured, precision, measTrig->m_measured); else - fprintf(mout,"%-20s= %e targ= %e trig= %e\n", mName, (measTarg->m_measured - measTrig->m_measured), measTarg->m_measured, measTrig->m_measured); + fprintf(mout,"%-20s= %.*e targ= %.*e trig= %.*e\n", mName, precision, + (measTarg->m_measured - measTrig->m_measured), + precision, measTarg->m_measured, precision, measTrig->m_measured); *result = (measTarg->m_measured - measTrig->m_measured); @@ -1883,9 +1892,9 @@ err_ret1: // print results if (out_line) - sprintf(out_line, "%-20s= %e\n", mName, meas->m_measured); + sprintf(out_line, "%-20s= %.*e\n", mName, precision, meas->m_measured); else - fprintf(mout,"%-20s= %e\n", mName, meas->m_measured); + fprintf(mout,"%-20s= %.*e\n", mName, precision, meas->m_measured); *result = meas->m_measured; @@ -1924,7 +1933,7 @@ err_ret2: if (out_line) sprintf(out_line, "%-20s= %.*e\n", mName, precision, meas->m_measured); else - fprintf(mout, "%-20s= %e\n", mName, meas->m_measured); + fprintf(mout, "%-20s= %.*e\n", mName, precision, meas->m_measured); *result = meas->m_measured; @@ -2012,9 +2021,11 @@ err_ret4: // print results if (out_line) - sprintf(out_line, "%-20s= %e from= %e to= %e\n", mName, meas->m_measured, meas->m_at, meas->m_measured_at); + sprintf(out_line, "%-20s= %.*e from= %.*e to= %.*e\n", mName, + precision, meas->m_measured, precision, meas->m_at, precision, meas->m_measured_at); else - fprintf(mout, "%-20s= %e from= %e to= %e\n", mName, meas->m_measured, meas->m_at, meas->m_measured_at); + fprintf(mout, "%-20s= %.*e from= %.*e to= %.*e\n", mName, + precision, meas->m_measured, precision, meas->m_at, precision, meas->m_measured_at); *result = meas->m_measured; @@ -2059,17 +2070,21 @@ err_ret5: if ((mFunctionType == AT_MIN) || (mFunctionType == AT_MAX)) { // print results if (out_line) - sprintf(out_line, "%-20s= %e at= %e\n", mName, measTrig->m_measured, measTrig->m_measured_at); + sprintf(out_line, "%-20s= %.*e at= %.*e\n", + mName, precision, measTrig->m_measured, precision, measTrig->m_measured_at); else - fprintf(mout, "%-20s= %e at= %e\n", mName, measTrig->m_measured, measTrig->m_measured_at); + fprintf(mout, "%-20s= %.*e at= %.*e\n", + mName, precision, measTrig->m_measured, precision, measTrig->m_measured_at); *result = measTrig->m_measured; } else { // print results if (out_line) - sprintf(out_line, "%-20s= %e with= %e\n", mName, measTrig->m_measured_at, measTrig->m_measured); + sprintf(out_line, "%-20s= %.*e with= %.*e\n", + mName, precision, measTrig->m_measured_at, precision, measTrig->m_measured); else - fprintf(mout, "%-20s= %e with= %e\n", mName, measTrig->m_measured_at, measTrig->m_measured); + fprintf(mout, "%-20s= %.*e with= %.*e\n", + mName, precision, measTrig->m_measured_at, precision, measTrig->m_measured); *result = measTrig->m_measured_at; } @@ -2117,9 +2132,11 @@ err_ret6: // print results if (out_line) - sprintf(out_line, "%-20s= %e from= %e to= %e\n", mName, (maxValue - minValue), measTrig->m_from, measTrig->m_to); + sprintf(out_line, "%-20s= %.*e from= %.*e to= %.*e\n", + mName, precision, (maxValue - minValue), precision, measTrig->m_from, precision, measTrig->m_to); else - fprintf(mout, "%-20s= %e from= %e to= %e\n", mName, (maxValue - minValue), measTrig->m_from, measTrig->m_to); + fprintf(mout, "%-20s= %.*e from= %.*e to= %.*e\n", + mName, precision, (maxValue - minValue), precision, measTrig->m_from, precision, measTrig->m_to); *result = (maxValue - minValue); diff --git a/src/frontend/miscvars.c b/src/frontend/miscvars.c index 9632ef862..c157a9666 100644 --- a/src/frontend/miscvars.c +++ b/src/frontend/miscvars.c @@ -76,6 +76,7 @@ char *ft_setkwords[] = { "lprplot5", "lprps", "maxwins", + "measureprec", "modelcard", "modelline", "moremode", diff --git a/src/frontend/options.c b/src/frontend/options.c index 7dfe6f97a..d6da5a46c 100644 --- a/src/frontend/options.c +++ b/src/frontend/options.c @@ -342,6 +342,16 @@ cp_usrset(struct variable *var, bool isset) raw_prec = var->va_num; else fprintf(cp_err, "Bad 'rawfileprec' \"%s\"\n", var->va_name); + } + else if (eq(var->va_name, "measureprec")) { + if ((var->va_type == CP_BOOL) && (isset == FALSE)) + measure_precision = -1; + else if (var->va_type == CP_REAL) + measure_precision = (int)floor(var->va_real + 0.5); + else if (var->va_type == CP_NUM) + measure_precision = var->va_num; + else + fprintf(cp_err, "Bad 'measureprec' \"%s\"\n", var->va_name); } else if (eq(var->va_name, "numdgt")) { if ((var->va_type == CP_BOOL) && (isset == FALSE)) cp_numdgt = -1; @@ -350,7 +360,7 @@ cp_usrset(struct variable *var, bool isset) else if (var->va_type == CP_NUM) cp_numdgt = var->va_num; else - fprintf(cp_err, "Excuse me??\n"); + fprintf(cp_err, "Bad 'numdgt' \"%s\"\n", var->va_name); } else if (eq(var->va_name, "unixcom")) { cp_dounixcom = isset; if (isset) { diff --git a/src/include/ngspice/fteext.h b/src/include/ngspice/fteext.h index 69d428b51..af74009bd 100644 --- a/src/include/ngspice/fteext.h +++ b/src/include/ngspice/fteext.h @@ -304,6 +304,9 @@ extern struct plot *raw_read(char *name); extern bool do_measure(char *what, bool chk_only); extern bool check_autostop(char *what); +/* com_measure2.c*/ +extern int measure_precision; + /* resource.c */ extern void ft_ckspace(void); From e3bb6afb5d9ad31897922fe372bfce62f5c2c2b7 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 11 May 2025 16:40:31 +0200 Subject: [PATCH 119/161] Add ifspec.ifs to MS Visual C project --- visualc/xspice/spice2poly.vcxproj | 1 + 1 file changed, 1 insertion(+) diff --git a/visualc/xspice/spice2poly.vcxproj b/visualc/xspice/spice2poly.vcxproj index 0379e7691..408c46b0f 100644 --- a/visualc/xspice/spice2poly.vcxproj +++ b/visualc/xspice/spice2poly.vcxproj @@ -210,6 +210,7 @@ + From 3fcfc4b989417e835e819da928cdd551d69eeeb6 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 20 Feb 2026 14:19:14 +0100 Subject: [PATCH 120/161] Improve error message --- src/spicelib/parser/inpdpar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spicelib/parser/inpdpar.c b/src/spicelib/parser/inpdpar.c index 0aab07537..1d2c67ba8 100644 --- a/src/spicelib/parser/inpdpar.c +++ b/src/spicelib/parser/inpdpar.c @@ -72,7 +72,7 @@ INPdevParse(char **line, CKTcircuit *ckt, int dev, GENinstance *fast, errbuf = copy(" unknown parameter ($). Check the compatibility flag!\n"); } else { - errbuf = tprintf(" unknown parameter (%s) \n", parameter); + errbuf = tprintf(" unknown instance parameter (%s) \n", parameter); } rtn = errbuf; goto quit; From 84f87aeafd80e4abb7b8635892a8b6ac72961c4e Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 10 May 2025 20:15:31 +0200 Subject: [PATCH 121/161] Improve error message by adding the sourcing netlist line --- src/frontend/numparam/numparam.h | 1 + src/frontend/numparam/spicenum.c | 1 + src/frontend/numparam/xpressn.c | 11 +++++++---- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/frontend/numparam/numparam.h b/src/frontend/numparam/numparam.h index 148311149..fd8935d26 100644 --- a/src/frontend/numparam/numparam.h +++ b/src/frontend/numparam/numparam.h @@ -57,6 +57,7 @@ typedef struct { /* the input scanner data structure */ char *dyncategory; int hs_compatibility; /* allow extra keywords */ int linecount; /* number of lines in deck */ + char* cardline; /* line of card treated currently */ } dico_t; diff --git a/src/frontend/numparam/spicenum.c b/src/frontend/numparam/spicenum.c index 7832a37b7..7c38093c0 100644 --- a/src/frontend/numparam/spicenum.c +++ b/src/frontend/numparam/spicenum.c @@ -672,6 +672,7 @@ nupa_eval(struct card *card) dicoS->srcline = linenum; dicoS->oldline = orig_linenum; + dicoS->cardline = s; c = dicoS->dyncategory[linenum]; diff --git a/src/frontend/numparam/xpressn.c b/src/frontend/numparam/xpressn.c index ec1c55f8b..a8abbb016 100644 --- a/src/frontend/numparam/xpressn.c +++ b/src/frontend/numparam/xpressn.c @@ -229,14 +229,16 @@ message(dico_t *dico, const char *fmt, ...) if (ft_ngdebug) { fprintf (stderr, - "Netlist line no. %d, new internal line no. %d:\n", - dico->oldline, dico->srcline); + "Error in netlist line no. %d, new internal line no. %d:\n" + "%s\n\n", + dico->srcline, dico->oldline, dico->cardline); } else { fprintf (stderr, - "Netlist line no. %d:\n", - dico->oldline); + "Error in netlist line no. %d:\n" + "%s\n\n", + dico->srcline, dico->oldline); } } va_start(ap, fmt); @@ -273,6 +275,7 @@ initdico(dico_t *dico) dico->hs_compatibility = 1; else dico->hs_compatibility = 0; + dico->cardline = NULL; } From 51e46d5e00ad309b20f25f59a3580e8e9ccf1527 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 11 May 2025 09:14:02 +0200 Subject: [PATCH 122/161] Prepare BSIM4.7 for instance flag dtemp FIXME: The dtemp value is not yet linked to the model! --- src/spicelib/devices/bsim4v7/b4v7.c | 1 + src/spicelib/devices/bsim4v7/b4v7ask.c | 3 +++ src/spicelib/devices/bsim4v7/b4v7par.c | 4 ++++ src/spicelib/devices/bsim4v7/b4v7set.c | 3 ++- src/spicelib/devices/bsim4v7/bsim4v7def.h | 3 +++ 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/spicelib/devices/bsim4v7/b4v7.c b/src/spicelib/devices/bsim4v7/b4v7.c index f1d70b209..cb46a904c 100644 --- a/src/spicelib/devices/bsim4v7/b4v7.c +++ b/src/spicelib/devices/bsim4v7/b4v7.c @@ -57,6 +57,7 @@ IOP( "mulu0", BSIM4v7_MULU0, IF_REAL, "Low field mobility multiplier"), IOP( "xgw", BSIM4v7_XGW, IF_REAL, "Distance from gate contact center to device edge"), IOP( "ngcon", BSIM4v7_NGCON, IF_REAL, "Number of gate contacts"), IOP( "wnflag", BSIM4v7_WNFLAG, IF_INTEGER, "W/NF device flag for bin selection"), +IOPU( "dtemp", BSIM4v7_DTEMP, IF_REAL, "Instance temperature difference"), IOP( "trnqsmod", BSIM4v7_TRNQSMOD, IF_INTEGER, "Transient NQS model selector"), IOP( "acnqsmod", BSIM4v7_ACNQSMOD, IF_INTEGER, "AC NQS model selector"), diff --git a/src/spicelib/devices/bsim4v7/b4v7ask.c b/src/spicelib/devices/bsim4v7/b4v7ask.c index 19690eda9..f20dc692b 100644 --- a/src/spicelib/devices/bsim4v7/b4v7ask.c +++ b/src/spicelib/devices/bsim4v7/b4v7ask.c @@ -114,6 +114,9 @@ BSIM4v7instance *here = (BSIM4v7instance*)inst; case BSIM4v7_MULU0: value->rValue = here->BSIM4v7mulu0; return(OK); + case BSIM4v7_DTEMP: + value->rValue = here->BSIM4v7dtemp; + return(OK); case BSIM4v7_WNFLAG: value->iValue = here->BSIM4v7wnflag; return(OK); diff --git a/src/spicelib/devices/bsim4v7/b4v7par.c b/src/spicelib/devices/bsim4v7/b4v7par.c index d8bdd6d3d..e4c5a099a 100644 --- a/src/spicelib/devices/bsim4v7/b4v7par.c +++ b/src/spicelib/devices/bsim4v7/b4v7par.c @@ -141,6 +141,10 @@ IFvalue *select) here->BSIM4v7mulu0 = value->rValue; here->BSIM4v7mulu0Given = TRUE; break; + case BSIM4v7_DTEMP: + here->BSIM4v7dtemp = value->rValue; + here->BSIM4v7dtempGiven = TRUE; + return(OK); case BSIM4v7_WNFLAG: here->BSIM4v7wnflag = value->iValue; here->BSIM4v7wnflagGiven = TRUE; diff --git a/src/spicelib/devices/bsim4v7/b4v7set.c b/src/spicelib/devices/bsim4v7/b4v7set.c index ed2fd017f..1d3246b47 100644 --- a/src/spicelib/devices/bsim4v7/b4v7set.c +++ b/src/spicelib/devices/bsim4v7/b4v7set.c @@ -2256,8 +2256,9 @@ BSIM4v7instance **InstArray; here->BSIM4v7xgw = model->BSIM4v7xgw; if (!here->BSIM4v7ngconGiven) here->BSIM4v7ngcon = model->BSIM4v7ngcon; + if (!here->BSIM4v7dtempGiven) + here->BSIM4v7dtemp = 0; - /* Process instance model selectors, some * may override their global counterparts */ diff --git a/src/spicelib/devices/bsim4v7/bsim4v7def.h b/src/spicelib/devices/bsim4v7/bsim4v7def.h index e4c1f1adc..073bec7ff 100644 --- a/src/spicelib/devices/bsim4v7/bsim4v7def.h +++ b/src/spicelib/devices/bsim4v7/bsim4v7def.h @@ -116,6 +116,7 @@ typedef struct sBSIM4v7instance int BSIM4v7wnflag; double BSIM4v7xgw; double BSIM4v7ngcon; + double BSIM4v7dtemp; /* added here to account stress effect instance dependence */ double BSIM4v7u0temp; @@ -302,6 +303,7 @@ typedef struct sBSIM4v7instance unsigned BSIM4v7wnflagGiven :1; unsigned BSIM4v7xgwGiven :1; unsigned BSIM4v7ngconGiven :1; + unsigned BSIM4v7dtempGiven : 1; unsigned BSIM4v7icVDSGiven :1; unsigned BSIM4v7icVGSGiven :1; unsigned BSIM4v7icVBSGiven :1; @@ -2843,6 +2845,7 @@ typedef struct sBSIM4v7model #define BSIM4v7_M 38 #define BSIM4v7_MULU0 39 #define BSIM4v7_WNFLAG 40 +#define BSIM4v7_DTEMP 41 /* Global parameters */ #define BSIM4v7_MOD_TEMPEOT 65 From f8a4195e8ec5f908150a8930b463e26459fac05b Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 20 Feb 2026 14:50:18 +0100 Subject: [PATCH 123/161] Prepare for instance parameter 'dtemp', required by commercial PDKs. Not yet support in the model, silently ignored. --- src/spicelib/devices/bsim4v5/b4v5.c | 2 +- src/spicelib/devices/bsim4v5/b4v5ask.c | 3 +++ src/spicelib/devices/bsim4v5/b4v5par.c | 4 ++++ src/spicelib/devices/bsim4v5/b4v5set.c | 3 ++- src/spicelib/devices/bsim4v5/bsim4v5def.h | 3 +++ 5 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/spicelib/devices/bsim4v5/b4v5.c b/src/spicelib/devices/bsim4v5/b4v5.c index 2d920af47..30d05ac74 100644 --- a/src/spicelib/devices/bsim4v5/b4v5.c +++ b/src/spicelib/devices/bsim4v5/b4v5.c @@ -49,7 +49,7 @@ IOPR( "delvt0", BSIM4v5_DELVTO, IF_REAL , "Zero bias threshold voltage variat IOP( "mulu0", BSIM4v5_MULU0, IF_REAL, "Low field mobility multiplier"), IOP( "xgw", BSIM4v5_XGW, IF_REAL, "Distance from gate contact center to device edge"), IOP( "ngcon", BSIM4v5_NGCON, IF_REAL, "Number of gate contacts"), - +IOPU("dtemp", BSIM4v5_DTEMP, IF_REAL, "Instance temperature difference"), IOP( "trnqsmod", BSIM4v5_TRNQSMOD, IF_INTEGER, "Transient NQS model selector"), IOP( "acnqsmod", BSIM4v5_ACNQSMOD, IF_INTEGER, "AC NQS model selector"), diff --git a/src/spicelib/devices/bsim4v5/b4v5ask.c b/src/spicelib/devices/bsim4v5/b4v5ask.c index 95ae3c800..829bb3e4c 100644 --- a/src/spicelib/devices/bsim4v5/b4v5ask.c +++ b/src/spicelib/devices/bsim4v5/b4v5ask.c @@ -112,6 +112,9 @@ BSIM4v5instance *here = (BSIM4v5instance*)inst; case BSIM4v5_MULU0: value->rValue = here->BSIM4v5mulu0; return(OK); + case BSIM4v5_DTEMP: + value->rValue = here->BSIM4v5dtemp; + return(OK); case BSIM4v5_XGW: value->rValue = here->BSIM4v5xgw; return(OK); diff --git a/src/spicelib/devices/bsim4v5/b4v5par.c b/src/spicelib/devices/bsim4v5/b4v5par.c index 1013ce700..f3c07dee7 100644 --- a/src/spicelib/devices/bsim4v5/b4v5par.c +++ b/src/spicelib/devices/bsim4v5/b4v5par.c @@ -139,6 +139,10 @@ IFvalue *select) here->BSIM4v5mulu0 = value->rValue; here->BSIM4v5mulu0Given = TRUE; break; + case BSIM4v5_DTEMP: + here->BSIM4v5dtemp = value->rValue; + here->BSIM4v5dtempGiven = TRUE; + return(OK); case BSIM4v5_XGW: here->BSIM4v5xgw = value->rValue; here->BSIM4v5xgwGiven = TRUE; diff --git a/src/spicelib/devices/bsim4v5/b4v5set.c b/src/spicelib/devices/bsim4v5/b4v5set.c index d16f3747b..9214bc3ca 100644 --- a/src/spicelib/devices/bsim4v5/b4v5set.c +++ b/src/spicelib/devices/bsim4v5/b4v5set.c @@ -1751,8 +1751,9 @@ BSIM4v5instance **InstArray; here->BSIM4v5xgw = model->BSIM4v5xgw; if (!here->BSIM4v5ngconGiven) here->BSIM4v5ngcon = model->BSIM4v5ngcon; + if (!here->BSIM4v5dtempGiven) + here->BSIM4v5dtemp = 0; - /* Process instance model selectors, some * may override their global counterparts */ diff --git a/src/spicelib/devices/bsim4v5/bsim4v5def.h b/src/spicelib/devices/bsim4v5/bsim4v5def.h index 2120a59d3..f397af3b7 100644 --- a/src/spicelib/devices/bsim4v5/bsim4v5def.h +++ b/src/spicelib/devices/bsim4v5/bsim4v5def.h @@ -105,6 +105,7 @@ typedef struct sBSIM4v5instance double BSIM4v5mulu0; double BSIM4v5xgw; double BSIM4v5ngcon; + double BSIM4v5dtemp; /* added here to account stress effect instance dependence */ double BSIM4v5u0temp; @@ -288,6 +289,7 @@ typedef struct sBSIM4v5instance unsigned BSIM4v5mulu0Given :1; unsigned BSIM4v5xgwGiven :1; unsigned BSIM4v5ngconGiven :1; + unsigned BSIM4v5dtempGiven : 1; unsigned BSIM4v5icVDSGiven :1; unsigned BSIM4v5icVGSGiven :1; unsigned BSIM4v5icVBSGiven :1; @@ -2536,6 +2538,7 @@ typedef struct sBSIM4v5model #define BSIM4v5_SC 37 #define BSIM4v5_M 38 #define BSIM4v5_MULU0 39 +#define BSIM4v5_DTEMP 40 /* Global parameters */ #define BSIM4v5_MOD_TEMPMOD 89 From 96df01db06b6c51608b8e92d5373488db96c7dd1 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 20 Feb 2026 15:06:30 +0100 Subject: [PATCH 124/161] Prepare for instance parameter 'dtemp', required by commercial PDKs. Not yet support in the model, silently ignored. --- src/spicelib/devices/bsim4/b4.c | 1 + src/spicelib/devices/bsim4/b4ask.c | 3 +++ src/spicelib/devices/bsim4/b4par.c | 4 ++++ src/spicelib/devices/bsim4/b4set.c | 2 ++ src/spicelib/devices/bsim4/bsim4def.h | 4 ++++ 5 files changed, 14 insertions(+) diff --git a/src/spicelib/devices/bsim4/b4.c b/src/spicelib/devices/bsim4/b4.c index 438c1498b..83f3115e5 100644 --- a/src/spicelib/devices/bsim4/b4.c +++ b/src/spicelib/devices/bsim4/b4.c @@ -59,6 +59,7 @@ IOP( "mulu0", BSIM4_MULU0, IF_REAL, "Low field mobility multiplier"), IOP( "xgw", BSIM4_XGW, IF_REAL, "Distance from gate contact center to device edge"), IOP( "ngcon", BSIM4_NGCON, IF_REAL, "Number of gate contacts"), IOP( "wnflag", BSIM4_WNFLAG, IF_INTEGER, "W/NF device flag for bin selection"), +IOPU("dtemp", BSIM4_DTEMP, IF_REAL, "Instance temperature difference"), IOP( "trnqsmod", BSIM4_TRNQSMOD, IF_INTEGER, "Transient NQS model selector"), IOP( "acnqsmod", BSIM4_ACNQSMOD, IF_INTEGER, "AC NQS model selector"), diff --git a/src/spicelib/devices/bsim4/b4ask.c b/src/spicelib/devices/bsim4/b4ask.c index d43e1a708..abced660c 100644 --- a/src/spicelib/devices/bsim4/b4ask.c +++ b/src/spicelib/devices/bsim4/b4ask.c @@ -135,6 +135,9 @@ BSIM4instance *here = (BSIM4instance*)inst; case BSIM4_WNFLAG: value->iValue = here->BSIM4wnflag; return(OK); + case BSIM4_DTEMP: + value->rValue = here->BSIM4dtemp; + return(OK); case BSIM4_XGW: value->rValue = here->BSIM4xgw; return(OK); diff --git a/src/spicelib/devices/bsim4/b4par.c b/src/spicelib/devices/bsim4/b4par.c index ac4a274c5..44373bfd6 100644 --- a/src/spicelib/devices/bsim4/b4par.c +++ b/src/spicelib/devices/bsim4/b4par.c @@ -165,6 +165,10 @@ IFvalue *select) here->BSIM4wnflag = value->iValue; here->BSIM4wnflagGiven = TRUE; break; + case BSIM4_DTEMP: + here->BSIM4dtemp = value->rValue; + here->BSIM4dtempGiven = TRUE; + return(OK); case BSIM4_XGW: here->BSIM4xgw = value->rValue; here->BSIM4xgwGiven = TRUE; diff --git a/src/spicelib/devices/bsim4/b4set.c b/src/spicelib/devices/bsim4/b4set.c index 71bc75a81..0e91f37d3 100644 --- a/src/spicelib/devices/bsim4/b4set.c +++ b/src/spicelib/devices/bsim4/b4set.c @@ -2371,6 +2371,8 @@ BSIM4instance **InstArray; here->BSIM4xgw = model->BSIM4xgw; if (!here->BSIM4ngconGiven) here->BSIM4ngcon = model->BSIM4ngcon; + if (!here->BSIM4dtempGiven) + here->BSIM4dtemp = 0; /* Process instance model selectors, some * may override their global counterparts diff --git a/src/spicelib/devices/bsim4/bsim4def.h b/src/spicelib/devices/bsim4/bsim4def.h index 6d7d652e8..17f810a19 100644 --- a/src/spicelib/devices/bsim4/bsim4def.h +++ b/src/spicelib/devices/bsim4/bsim4def.h @@ -121,6 +121,7 @@ typedef struct sBSIM4instance int BSIM4wnflag; double BSIM4xgw; double BSIM4ngcon; + double BSIM4dtemp; /* added here to account stress effect instance dependence */ @@ -316,6 +317,7 @@ typedef struct sBSIM4instance unsigned BSIM4wnflagGiven :1; unsigned BSIM4xgwGiven :1; unsigned BSIM4ngconGiven :1; + unsigned BSIM4dtempGiven : 1; unsigned BSIM4icVDSGiven :1; unsigned BSIM4icVGSGiven :1; unsigned BSIM4icVBSGiven :1; @@ -2884,6 +2886,8 @@ typedef struct sBSIM4model #define BSIM4_WEFF 46 #define BSIM4_LEFF 47 +#define BSIM4_DTEMP 48 + /* Global parameters */ #define BSIM4_MOD_TEMPEOT 66 #define BSIM4_MOD_LEFFEOT 67 From 527cc86969284865066f58f8fe8cda391a44a22c Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 20 Feb 2026 15:18:47 +0100 Subject: [PATCH 125/161] Prepare for instance parameter 'dtemp', required by commercial PDKs. Not yet support in the model, silently ignored. --- src/spicelib/devices/bsim4v6/b4v6.c | 2 +- src/spicelib/devices/bsim4v6/b4v6ask.c | 3 +++ src/spicelib/devices/bsim4v6/b4v6par.c | 4 ++++ src/spicelib/devices/bsim4v6/b4v6set.c | 3 ++- src/spicelib/devices/bsim4v6/bsim4v6def.h | 3 +++ 5 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/spicelib/devices/bsim4v6/b4v6.c b/src/spicelib/devices/bsim4v6/b4v6.c index 1ecb91625..ee160010d 100644 --- a/src/spicelib/devices/bsim4v6/b4v6.c +++ b/src/spicelib/devices/bsim4v6/b4v6.c @@ -55,7 +55,7 @@ IOPR( "delvt0", BSIM4v6_DELVTO, IF_REAL , "Zero bias threshold voltage variat IOP( "mulu0", BSIM4v6_MULU0, IF_REAL, "Low field mobility multiplier"), IOP( "xgw", BSIM4v6_XGW, IF_REAL, "Distance from gate contact center to device edge"), IOP( "ngcon", BSIM4v6_NGCON, IF_REAL, "Number of gate contacts"), - +IOPU("dtemp", BSIM4v6_DTEMP, IF_REAL, "Instance temperature difference"), IOP( "trnqsmod", BSIM4v6_TRNQSMOD, IF_INTEGER, "Transient NQS model selector"), IOP( "acnqsmod", BSIM4v6_ACNQSMOD, IF_INTEGER, "AC NQS model selector"), diff --git a/src/spicelib/devices/bsim4v6/b4v6ask.c b/src/spicelib/devices/bsim4v6/b4v6ask.c index 64ce8b7bc..d9a025f0e 100644 --- a/src/spicelib/devices/bsim4v6/b4v6ask.c +++ b/src/spicelib/devices/bsim4v6/b4v6ask.c @@ -114,6 +114,9 @@ BSIM4v6instance *here = (BSIM4v6instance*)inst; case BSIM4v6_MULU0: value->rValue = here->BSIM4v6mulu0; return(OK); + case BSIM4v6_DTEMP: + value->rValue = here->BSIM4v6dtemp; + return(OK); case BSIM4v6_XGW: value->rValue = here->BSIM4v6xgw; return(OK); diff --git a/src/spicelib/devices/bsim4v6/b4v6par.c b/src/spicelib/devices/bsim4v6/b4v6par.c index 795fdc77c..f9430ab78 100644 --- a/src/spicelib/devices/bsim4v6/b4v6par.c +++ b/src/spicelib/devices/bsim4v6/b4v6par.c @@ -141,6 +141,10 @@ IFvalue *select) here->BSIM4v6mulu0 = value->rValue; here->BSIM4v6mulu0Given = TRUE; break; + case BSIM4v6_DTEMP: + here->BSIM4v6dtemp = value->rValue; + here->BSIM4v6dtempGiven = TRUE; + return(OK); case BSIM4v6_XGW: here->BSIM4v6xgw = value->rValue; here->BSIM4v6xgwGiven = TRUE; diff --git a/src/spicelib/devices/bsim4v6/b4v6set.c b/src/spicelib/devices/bsim4v6/b4v6set.c index 4ad739c34..3bf919304 100644 --- a/src/spicelib/devices/bsim4v6/b4v6set.c +++ b/src/spicelib/devices/bsim4v6/b4v6set.c @@ -2105,8 +2105,9 @@ BSIM4v6instance **InstArray; here->BSIM4v6xgw = model->BSIM4v6xgw; if (!here->BSIM4v6ngconGiven) here->BSIM4v6ngcon = model->BSIM4v6ngcon; + if (!here->BSIM4v6dtempGiven) + here->BSIM4v6dtemp = 0; - /* Process instance model selectors, some * may override their global counterparts */ diff --git a/src/spicelib/devices/bsim4v6/bsim4v6def.h b/src/spicelib/devices/bsim4v6/bsim4v6def.h index 94ee3b0c0..28f2aba35 100644 --- a/src/spicelib/devices/bsim4v6/bsim4v6def.h +++ b/src/spicelib/devices/bsim4v6/bsim4v6def.h @@ -114,6 +114,7 @@ typedef struct sBSIM4v6instance double BSIM4v6mulu0; double BSIM4v6xgw; double BSIM4v6ngcon; + double BSIM4v6dtemp; /* added here to account stress effect instance dependence */ double BSIM4v6u0temp; @@ -297,6 +298,7 @@ typedef struct sBSIM4v6instance unsigned BSIM4v6mulu0Given :1; unsigned BSIM4v6xgwGiven :1; unsigned BSIM4v6ngconGiven :1; + unsigned BSIM4v6dtempGiven : 1; unsigned BSIM4v6icVDSGiven :1; unsigned BSIM4v6icVGSGiven :1; unsigned BSIM4v6icVBSGiven :1; @@ -2713,6 +2715,7 @@ typedef struct sBSIM4v6model #define BSIM4v6_SC 37 #define BSIM4v6_M 38 #define BSIM4v6_MULU0 39 +#define BSIM4v6_DTEMP 40 /* Global parameters */ #define BSIM4v6_MOD_TEMPEOT 65 From 7159d6aa4b3b73639b8d160f8b73a14725883360 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 21 Feb 2026 14:20:30 +0100 Subject: [PATCH 126/161] V Pulse delivers erratic outputs, when not parameterized properly. Update the pulse generation: negative TR, TF, PW, PER not possible, get default values instead. 0 PW is allowed. Defaults are: TR negative or 0 --> TR = ckt->CKTstep TF negative or 0 --> TF = ckt->CKTstep PW < 0 --> PW = 0 PER <= 0 --> PER = TR + TF + PW */ --- src/spicelib/devices/vsrc/vsrcacct.c | 16 ++++++++++------ src/spicelib/devices/vsrc/vsrcload.c | 19 ++++++++++++------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/spicelib/devices/vsrc/vsrcacct.c b/src/spicelib/devices/vsrc/vsrcacct.c index df890ed76..6835cd0df 100644 --- a/src/spicelib/devices/vsrc/vsrcacct.c +++ b/src/spicelib/devices/vsrc/vsrcacct.c @@ -56,20 +56,24 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) double phase; double deltat; + /* TR negative or 0 --> TR = ckt->CKTstep + TF negative or 0 --> TF = ckt->CKTstep + PW < 0 --> PW = 0 + PER <= 0 --> PER = TR + TF + PW */ TD = here->VSRCfunctionOrder > 2 ? here->VSRCcoeffs[2] : 0.0; TR = here->VSRCfunctionOrder > 3 - && here->VSRCcoeffs[3] != 0.0 + && here->VSRCcoeffs[3] > 0.0 ? here->VSRCcoeffs[3] : ckt->CKTstep; TF = here->VSRCfunctionOrder > 4 - && here->VSRCcoeffs[4] != 0.0 + && here->VSRCcoeffs[4] > 0.0 ? here->VSRCcoeffs[4] : ckt->CKTstep; PW = here->VSRCfunctionOrder > 5 - && here->VSRCcoeffs[5] != 0.0 - ? here->VSRCcoeffs[5] : ckt->CKTfinalTime; + && here->VSRCcoeffs[5] >= 0.0 + ? here->VSRCcoeffs[5] : 0.0; PER = here->VSRCfunctionOrder > 6 - && here->VSRCcoeffs[6] != 0.0 - ? here->VSRCcoeffs[6] : ckt->CKTfinalTime; + && here->VSRCcoeffs[6] > 0.0 + ? here->VSRCcoeffs[6] : TR + TF + PW; PHASE = here->VSRCfunctionOrder > 7 ? here->VSRCcoeffs[7] : 0.0; diff --git a/src/spicelib/devices/vsrc/vsrcload.c b/src/spicelib/devices/vsrc/vsrcload.c index c74c9a756..5f88bc587 100644 --- a/src/spicelib/devices/vsrc/vsrcload.c +++ b/src/spicelib/devices/vsrc/vsrcload.c @@ -86,7 +86,12 @@ VSRCload(GENmodel *inModel, CKTcircuit *ckt) } else { time = ckt->CKTtime; } - /* use the transient functions */ + /* use the transient functions. Parameter limits: + TR negative or 0 --> TR = ckt->CKTstep + TF negative or 0 --> TF = ckt->CKTstep + PW < 0 --> PW = 0 + PER <= 0 --> PER = TR + TF + PW + */ switch(here->VSRCfunctionType) { default: @@ -106,17 +111,17 @@ VSRCload(GENmodel *inModel, CKTcircuit *ckt) TD = here->VSRCfunctionOrder > 2 ? here->VSRCcoeffs[2] : 0.0; TR = here->VSRCfunctionOrder > 3 - && here->VSRCcoeffs[3] != 0.0 + && here->VSRCcoeffs[3] > 0.0 ? here->VSRCcoeffs[3] : ckt->CKTstep; TF = here->VSRCfunctionOrder > 4 - && here->VSRCcoeffs[4] != 0.0 + && here->VSRCcoeffs[4] > 0.0 ? here->VSRCcoeffs[4] : ckt->CKTstep; PW = here->VSRCfunctionOrder > 5 - && here->VSRCcoeffs[5] != 0.0 - ? here->VSRCcoeffs[5] : ckt->CKTfinalTime; + && here->VSRCcoeffs[5] >= 0.0 + ? here->VSRCcoeffs[5] : 0.0; PER = here->VSRCfunctionOrder > 6 - && here->VSRCcoeffs[6] != 0.0 - ? here->VSRCcoeffs[6] : ckt->CKTfinalTime; + && here->VSRCcoeffs[6] > 0.0 + ? here->VSRCcoeffs[6] : TR + TF + PW; /* shift time by delay time TD */ time -= TD; From dd2a5fd062fdb6dd8fa2354da5a675ef0adc384a Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 21 Feb 2026 14:30:51 +0100 Subject: [PATCH 127/161] Move comment --- src/spicelib/devices/vsrc/vsrcload.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/spicelib/devices/vsrc/vsrcload.c b/src/spicelib/devices/vsrc/vsrcload.c index 5f88bc587..c4190d25d 100644 --- a/src/spicelib/devices/vsrc/vsrcload.c +++ b/src/spicelib/devices/vsrc/vsrcload.c @@ -86,12 +86,7 @@ VSRCload(GENmodel *inModel, CKTcircuit *ckt) } else { time = ckt->CKTtime; } - /* use the transient functions. Parameter limits: - TR negative or 0 --> TR = ckt->CKTstep - TF negative or 0 --> TF = ckt->CKTstep - PW < 0 --> PW = 0 - PER <= 0 --> PER = TR + TF + PW - */ + /* use the transient functions. */ switch(here->VSRCfunctionType) { default: @@ -99,6 +94,12 @@ VSRCload(GENmodel *inModel, CKTcircuit *ckt) break; case PULSE: { + /* Parameter limits : + TR negative or 0 --> TR = ckt->CKTstep + TF negative or 0 --> TF = ckt->CKTstep + PW < 0 --> PW = 0 + PER <= 0 --> PER = TR + TF + PW + */ double V1, V2, TD, TR, TF, PW, PER; double basetime = 0; double PHASE; From 7474cd70d005085e258f143c27e5c91fca04dc60 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 23 Feb 2026 15:43:52 +0100 Subject: [PATCH 128/161] Ignore .hdl and .biaswarn commands. --- src/frontend/inpcom.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 4cf3b2edf..33d5a4063 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -1331,6 +1331,8 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name static int is_control = 0; /* We are reading from a .control section */ bool found_end = FALSE, shell_eol_continuation = FALSE; + static bool biaswarn = FALSE; + static bool hdlwarn = FALSE; #ifdef CIDER static int in_cider_model = 0; #endif @@ -1440,6 +1442,26 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name memcpy(buffer, ".inc", 4); } + if (ciprefix(".hdl", buffer)) { + if (!hdlwarn) { + fprintf(cp_err, "Warning: Dot command .hdl is not supported, ingnored\n"); + fprintf(cp_err, " line no. %d, %s", line_number, buffer); + fprintf(cp_err, " file %s\n", file_name); + fprintf(cp_err, " This message will be posted only once!\n\n"); + hdlwarn = TRUE; + } + tfree(buffer); + continue; + } + if (ciprefix(".biaschk", buffer)) { + if (!biaswarn) { + fprintf(cp_err, "Warning: Dot command .biaschk is not supported, ingnored\n"); + fprintf(cp_err, " This message will be posted only once!\n\n"); + biaswarn = TRUE; + } + tfree(buffer); + continue; + } /* now handle .include statements */ if (ciprefix(".include", buffer) || ciprefix(".inc", buffer)) { @@ -2842,6 +2864,7 @@ static void inp_fix_macro_param_func_paren_io(struct card *card) str_ptr[3] = 'c'; str_ptr[4] = ' '; } +// fprintf(stdout, "%s\n", card->line); } } } From d13cd984f43fd68434963c600ee31caf29dcdc47 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 23 Feb 2026 15:50:24 +0100 Subject: [PATCH 129/161] Special treatment while spiltting multiple .param lines, if .param is a .func --- src/frontend/inpcom.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 33d5a4063..c7e7c9958 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -5661,11 +5661,9 @@ static void inp_reorder_params( } -// iterate through deck and find lines with multiply defined parameters -// -// split line up into multiple lines and place those new lines immediately -// after the current multi-param line in the deck - +/* Iterate through deck and find lines with more than one parameter defined + Split line up into multiple lines and place those new lines immediately + after the current multi-param line in the deck */ static int inp_split_multi_param_lines(struct card *card, int line_num) { for (; card; card = card->nextcard) { @@ -5701,6 +5699,12 @@ static int inp_split_multi_param_lines(struct card *card, int line_num) int paren_depth = 0; beg_param = skip_back_ws(equal_ptr, curr_line); + /* Special treatment if .param is a .func: + move back to opening '(' */ + if (*(beg_param - 1) == ')') { + while (beg_param > curr_line && *beg_param != '(') + beg_param--; + } beg_param = skip_back_non_ws(beg_param, curr_line); end_param = skip_ws(equal_ptr + 1); while (*end_param && !isspace_c(*end_param)) { From 5b39c73205a8acf20ec131fa1ba8f301865740d6 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 11 May 2025 16:41:47 +0200 Subject: [PATCH 130/161] Add a parameter m (output multiplicator) to spice2poly code model. --- src/xspice/icm/spice2poly/icm_spice2poly/cfunc.mod | 12 +++++++----- .../icm/spice2poly/icm_spice2poly/ifspec.ifs | 14 +++++++++++++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/xspice/icm/spice2poly/icm_spice2poly/cfunc.mod b/src/xspice/icm/spice2poly/icm_spice2poly/cfunc.mod index df6fdff20..b869d0845 100644 --- a/src/xspice/icm/spice2poly/icm_spice2poly/cfunc.mod +++ b/src/xspice/icm/spice2poly/icm_spice2poly/cfunc.mod @@ -47,7 +47,7 @@ required syntax. This model may also be called directly as follows: a1 [ ] xxx - .model xxx spice2poly ( coef = [ ] ) + .model xxx spice2poly ( coef = [ ] [m = val] ) Refer to the 2G6 User Guide for an explanation of the coefficients. @@ -102,12 +102,14 @@ void spice2poly (ARGS) double sum; /* Temporary for accumulating sum of terms */ double product; /* Temporary for accumulating product */ - + double mult; /* multplicator for G and F sources */ /* Get number of input values */ num_inputs = PORT_SIZE(in); + mult = PARAM(m); + /* If this is the first call to the model, allocate the static variable */ /* array */ @@ -165,7 +167,7 @@ void spice2poly (ARGS) /* Add the product times the appropriate coefficient into the sum */ sum += coef[i] * product; } - OUTPUT(out) = sum; + OUTPUT(out) = sum * mult; /* Compute and output the partials for each input */ @@ -201,13 +203,13 @@ void spice2poly (ARGS) sum += coef[j] * product; } - PARTIAL(out,in[i]) = sum; + PARTIAL(out,in[i]) = sum * mult; /* If this is DC analysis, save the partial for use as AC gain */ /* value in an AC analysis */ if(ANALYSIS == MIF_DC) - STATIC_VAR(acgains[i]) = sum; + STATIC_VAR(acgains[i]) = sum * mult; } /* Free the allocated items and return */ diff --git a/src/xspice/icm/spice2poly/icm_spice2poly/ifspec.ifs b/src/xspice/icm/spice2poly/icm_spice2poly/ifspec.ifs index 6aab4de10..02f4b6387 100644 --- a/src/xspice/icm/spice2poly/icm_spice2poly/ifspec.ifs +++ b/src/xspice/icm/spice2poly/icm_spice2poly/ifspec.ifs @@ -16,7 +16,8 @@ AUTHORS MODIFICATIONS - + 11/05/2025 Holger Vogt + new parameter m (multiplicator) SUMMARY @@ -67,6 +68,17 @@ Vector: yes Vector_Bounds: [2 -] Null_Allowed: no +PARAMETER_TABLE: + +Parameter_Name: m +Description: "multiplicator" +Data_Type: real +Default_Value: 1 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + STATIC_VAR_TABLE: From 48a37be31ca0a3c28625dacf3b26c402c5a01b53 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 23 Feb 2026 16:06:43 +0100 Subject: [PATCH 131/161] Add parameter m (multiplier), while translating from G or F source to code model spice2poly --- src/xspice/enh/enhtrans.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/xspice/enh/enhtrans.c b/src/xspice/enh/enhtrans.c index 2eb23aa2a..5482003c3 100644 --- a/src/xspice/enh/enhtrans.c +++ b/src/xspice/enh/enhtrans.c @@ -301,7 +301,7 @@ static char *two2three_translate( char **out_conn; char **in_conn; char **coef; - + char* multibeg, *multiend, *multi = NULL; char *card; @@ -313,6 +313,20 @@ static char *two2three_translate( /* Put the first character into local storage for checking type */ type = *orig_card; + /* There may be a multiplier m=val + Remove it here, add it later */ + multibeg = strstr(orig_card, " m="); + if (multibeg) { + multiend = multibeg + 3; + while (*multiend == ' ') + multiend++; + while (*multiend && *multiend != ' ') + multiend++; + multi = copy_substring(multibeg, multiend); + while (multibeg < multiend) + *(multibeg++) = ' '; + } + /* Count the number of tokens for use in parsing */ num_tokens = count_tokens(orig_card); @@ -414,6 +428,9 @@ static char *two2three_translate( for(i = 0; i < num_coefs; i++) mod_card_len += strlen(coef[i]) + 1; + if (multi && (type == 'g' || type == 'G' || type == 'f'|| type == 'F')) + mod_card_len += strlen(multi) + 1; + /* Allocate space for the cards and write them into the strings */ *inst_card = TMALLOC(char, inst_card_len); @@ -460,6 +477,11 @@ static char *two2three_translate( sprintf(*mod_card + strlen(*mod_card), "%s ", coef[i]); sprintf(*mod_card + strlen(*mod_card), "]"); + if (multi && (type == 'g' || type == 'G' || type == 'f' || type == 'F')) { + sprintf(*mod_card + strlen(*mod_card), " %s", multi); + tfree(multi); + } + #ifdef TRACE /* SDB debug statement */ printf("In two2three_translate, translated statements:\n%s \n%s \n", *inst_card, *mod_card); From a92eea2dfb2a38ce2c223aba2870b17e4681ee57 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 11 May 2025 17:34:39 +0200 Subject: [PATCH 132/161] Add warning message if E or H poly source has multiplier m --- src/xspice/enh/enhtrans.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/xspice/enh/enhtrans.c b/src/xspice/enh/enhtrans.c index 5482003c3..df5fbfd8e 100644 --- a/src/xspice/enh/enhtrans.c +++ b/src/xspice/enh/enhtrans.c @@ -482,6 +482,12 @@ static char *two2three_translate( tfree(multi); } + if (multi && (type == 'e' || type == 'E' || type == 'h' || type == 'H')) { + fprintf(stderr, "Warning: multiplier m not available for E and H poly sources, ignored as\n" + " %s\n", orig_card); + tfree(multi); + } + #ifdef TRACE /* SDB debug statement */ printf("In two2three_translate, translated statements:\n%s \n%s \n", *inst_card, *mod_card); From 24008efc8351e66bd5f3275bf2c929d5e5ced89c Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 23 Feb 2026 16:10:17 +0100 Subject: [PATCH 133/161] Improve error message. --- src/xspice/enh/enhtrans.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xspice/enh/enhtrans.c b/src/xspice/enh/enhtrans.c index df5fbfd8e..ce22e2025 100644 --- a/src/xspice/enh/enhtrans.c +++ b/src/xspice/enh/enhtrans.c @@ -370,8 +370,8 @@ static char *two2three_translate( if(num_coefs < 1) { char *errmsg; - printf("ERROR - Number of connections differs from poly dimension\n"); - printf("ERROR while parsing: %s\n", orig_card); + fprintf(stderr, "ERROR - Number of connections differs from poly dimension\n"); + fprintf(stderr, " while parsing: %s\n", orig_card); errmsg = copy("ERROR in two2three_translate -- Argument to poly() is not an integer\n"); *inst_card = copy("* ERROR - Number of connections differs from poly dimension\n"); *mod_card = copy(" * ERROR - Number of connections differs from poly dimension\n"); From a165ab5c289120687b9f70cf2c1b8a906d918452 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 23 Feb 2026 16:30:20 +0100 Subject: [PATCH 134/161] Allow Cd as a valid C reference designator for a capacitor, i.e. lower-casing of node names, by re-organizing the setting of lower cases in the netlist: No lower-casing for cd only while in a .control section. --- src/frontend/inpcom.c | 79 ++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index c7e7c9958..7b3fb7b0c 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -1774,15 +1774,16 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name } #endif /* no lower case letters for lines beginning with: */ - else if (!ciprefix("write", buffer) && - !ciprefix("wrdata", buffer) && - !ciprefix(".lib", buffer) && !ciprefix(".inc", buffer) && - !ciprefix("codemodel", buffer) && - !ciprefix("osdi", buffer) && - !ciprefix("pre_osdi", buffer) && - !ciprefix("echo", buffer) && !ciprefix("shell", buffer) && - !ciprefix("source", buffer) && !ciprefix("cd ", buffer) && - !ciprefix("load", buffer) && !ciprefix("setcs", buffer)) { + else if (!(ciprefix(".lib", buffer) || ciprefix(".inc", buffer) || + (is_control && ( + ciprefix("write", buffer) || + ciprefix("wrdata", buffer) || + ciprefix("codemodel", buffer) || + ciprefix("osdi", buffer) || + ciprefix("pre_osdi", buffer) || + ciprefix("echo", buffer) || ciprefix("shell", buffer) || + ciprefix("source", buffer) ||ciprefix("cd ", buffer) || + ciprefix("load", buffer) || ciprefix("setcs", buffer))))) { /* lower case for all other lines */ for (s = buffer; *s && (*s != '\n'); s++) *s = tolower_c(*s); @@ -1793,39 +1794,41 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name for (s = buffer; *s && (*s != '\n'); s++) ; } - /* lower case for variables or vectors in command 'echo' */ - if (ciprefix("echo", buffer)) { - char* p = buffer, *tmpstr; - while (p && *p != '\n' && *p != '\0') { - p = nexttok(p); - /* vectors or variables start with $ */ - if (p && *p == '$') { - for (tmpstr = p; *tmpstr && !isspace_c(*tmpstr); tmpstr++) - *tmpstr = tolower_c(*tmpstr); - p = tmpstr; + if (is_control) { + /* lower case for variables or vectors in command 'echo' */ + if (ciprefix("echo", buffer)) { + char* p = buffer, * tmpstr; + while (p && *p != '\n' && *p != '\0') { + p = nexttok(p); + /* vectors or variables start with $ */ + if (p && *p == '$') { + for (tmpstr = p; *tmpstr && !isspace_c(*tmpstr); tmpstr++) + *tmpstr = tolower_c(*tmpstr); + p = tmpstr; + } } } - } - /* add Inp_Path to buffer while keeping the sourcepath variable contents */ - if (ciprefix("set", buffer)) { - char *p; + /* add Inp_Path to buffer while keeping the sourcepath variable contents */ + if (ciprefix("set", buffer)) { + char* p; - p = skip_ws(buffer + 3); // Next word - if (strncmp(p, "sourcepath", 10) == 0 && - skip_non_ws(p) == p + 10) { - p = strchr(buffer, ')'); - if (p) { - *p = 0; // clear ) and insert Inp_Path in between - p = tprintf("%s %s ) %s", buffer, + p = skip_ws(buffer + 3); // Next word + if (strncmp(p, "sourcepath", 10) == 0 && + skip_non_ws(p) == p + 10) { + p = strchr(buffer, ')'); + if (p) { + *p = 0; // clear ) and insert Inp_Path in between + p = tprintf("%s %s ) %s", buffer, Inp_Path ? Inp_Path : "", p + 1); - tfree(buffer); - buffer = p; - /* s points to end of buffer */ - for (s = buffer; *s && (*s != '\n'); s++) - ; - } - else { - fprintf(stderr, "Warning: no closing parens found in 'set sourcepath' statement\n"); + tfree(buffer); + buffer = p; + /* s points to end of buffer */ + for (s = buffer; *s && (*s != '\n'); s++) + ; + } + else { + fprintf(stderr, "Warning: no closing parens found in 'set sourcepath' statement\n"); + } } } } From 603089b29f6e2fba9e4040cc8a7bc0463429237c Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 24 Feb 2026 14:17:37 +0100 Subject: [PATCH 135/161] Re-enable not setting lower case if commands from spinit or .spiceinit --- src/frontend/inpcom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 7b3fb7b0c..0a7cc4739 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -1775,14 +1775,14 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name #endif /* no lower case letters for lines beginning with: */ else if (!(ciprefix(".lib", buffer) || ciprefix(".inc", buffer) || - (is_control && ( + ((comfile || is_control) && ( ciprefix("write", buffer) || ciprefix("wrdata", buffer) || ciprefix("codemodel", buffer) || ciprefix("osdi", buffer) || ciprefix("pre_osdi", buffer) || ciprefix("echo", buffer) || ciprefix("shell", buffer) || - ciprefix("source", buffer) ||ciprefix("cd ", buffer) || + ciprefix("source", buffer) ||ciprefix("cd", buffer) || ciprefix("load", buffer) || ciprefix("setcs", buffer))))) { /* lower case for all other lines */ for (s = buffer; *s && (*s != '\n'); s++) From e613d5b8dbcf46e53276b254585bebf2261a4c8f Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 24 Feb 2026 17:00:40 +0100 Subject: [PATCH 136/161] Improve error message, no output of line string if not 'set ngdebug' --- src/frontend/numparam/xpressn.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/frontend/numparam/xpressn.c b/src/frontend/numparam/xpressn.c index a8abbb016..5c4907fa3 100644 --- a/src/frontend/numparam/xpressn.c +++ b/src/frontend/numparam/xpressn.c @@ -236,8 +236,7 @@ message(dico_t *dico, const char *fmt, ...) else { fprintf (stderr, - "Error in netlist line no. %d:\n" - "%s\n\n", + "Error in netlist line no. %d, new internal line no. %d:\n\n", dico->srcline, dico->oldline); } } From fb501b5131e768a3a9e69a3deb48051aee8edfa1 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 24 Feb 2026 17:02:00 +0100 Subject: [PATCH 137/161] Prevent potential buffer s overflow by limiting the characters written. Use vsnprintf instead of vsprintf. --- src/winmain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/winmain.c b/src/winmain.c index a851f4242..ee19a73c6 100644 --- a/src/winmain.c +++ b/src/winmain.c @@ -1499,7 +1499,7 @@ win_x_fprintf(FILE *stream, const char *format, ...) if ((stream == stdout) || (stream == stderr)) { s[0] = SE; - result = vsprintf(s, format, args); + result = vsnprintf(s, IOBufSize, format, args); win_x_fputs(s, stream); } else result = vfprintf(stream, format, args); From 973f3fd57c02bda3ba4d36ab4baa3d77a4dabe93 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 25 Feb 2026 14:14:25 +0100 Subject: [PATCH 138/161] Improve th error message: add the failing option's name. --- src/spicelib/parser/inpdoopt.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/spicelib/parser/inpdoopt.c b/src/spicelib/parser/inpdoopt.c index 61d44ba0a..84fb5429c 100644 --- a/src/spicelib/parser/inpdoopt.c +++ b/src/spicelib/parser/inpdoopt.c @@ -67,10 +67,14 @@ INPdoOpts( } continue; } - - errmsg = TMALLOC(char, 100); - (void) strcpy(errmsg," Error: unknown option - ignored\n"); - optCard->error = INPerrCat(optCard->error,errmsg); - fprintf(stderr, "%s\n", optCard->error); + /* print err message only if it is not just a number */ + char* ctoken = token; + while (*ctoken && strchr("0123456789.e+-", *ctoken)) + ctoken++; + if (*ctoken) { + errmsg = tprintf("Error: unknown option %s - ignored\n", token); + optCard->error = INPerrCat(optCard->error, errmsg); + fprintf(stderr, "%s\n", optCard->error); + } } } From c22d6c772df24457e001b0fa3d18b08f4f37830f Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 27 Feb 2026 17:48:23 +0100 Subject: [PATCH 139/161] prepare for binning of N devices --- src/spicelib/parser/inp2n.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/spicelib/parser/inp2n.c b/src/spicelib/parser/inp2n.c index ef6c9a742..b01d8b44c 100644 --- a/src/spicelib/parser/inp2n.c +++ b/src/spicelib/parser/inp2n.c @@ -71,7 +71,10 @@ void INP2N(CKTcircuit *ckt, INPtables *tab, struct card *current) { if (i >= 2) { c = INPgetMod(ckt, token, &thismodel, tab); - if (c) { + /* check if using model binning -- pass in line since need 'l' and 'w' */ + if (!thismodel) + txfree(INPgetModBin(ckt, token, &thismodel, tab, line)); + if (c && !thismodel) { LITERR(c); tfree(c); tfree(token); From 7a76310b6b6bdc0cbff1e0a96900ff858a17842f Mon Sep 17 00:00:00 2001 From: Enrique Date: Thu, 26 Feb 2026 22:39:34 +0100 Subject: [PATCH 140/161] Added parameter numPeriod so that the user can select the number of fundamental frequency periods used in the detection of the fundamental frequency and its harmonics. This is usefull when trying to recover the fundamental frequency and its harmonics from a noisy signal, like the output of a DCDC converter --- src/frontend/fourier.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/frontend/fourier.c b/src/frontend/fourier.c index d66efe3ee..5754700a3 100644 --- a/src/frontend/fourier.c +++ b/src/frontend/fourier.c @@ -23,7 +23,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group static char *pnum(double num); -static int CKTfour(int ndata, int numFreq, double *thd, double *Time, double *Value, +static int CKTfour(int ndata, int numFreq, int numPeriod, double *thd, double *Time, double *Value, double FundFreq, double *Freq, double *Mag, double *Phase, double *nMag, double *nPhase); @@ -32,8 +32,8 @@ static int CKTfour(int ndata, int numFreq, double *thd, double *Time, double *Va #define DEF_FOURGRIDSIZE 200 -/* CKTfour(ndata, numFreq, thd, Time, Value, FundFreq, Freq, Mag, Phase, nMag, nPhase) - * len 10 ? inp inp inp out out out out out +/* CKTfour(ndata, numFreq, numPeriod, thd, Time, Value, FundFreq, Freq, Mag, Phase, nMag, nPhase) + * len 10 1 ? inp inp inp out out out out out */ int @@ -42,7 +42,7 @@ fourier(wordlist *wl, struct plot *current_plot) struct dvec *time, *vec; struct pnode *pn, *names; double fundfreq, *data = NULL; - int nfreqs, fourgridsize, polydegree; + int nfreqs, nperiods, fourgridsize, polydegree; double *freq, *mag, *phase, *nmag, *nphase; /* Outputs from CKTfour */ double thd, *timescale = NULL; char *s; @@ -68,6 +68,8 @@ fourier(wordlist *wl, struct plot *current_plot) if (!cp_getvar("nfreqs", CP_NUM, &nfreqs, 0) || nfreqs < 1) nfreqs = 10; + if (!cp_getvar("nperiods", CP_NUM, &nperiods, 0) || nperiods < 1) + nperiods = 1; if (!cp_getvar("polydegree", CP_NUM, &polydegree, 0) || polydegree < 0) polydegree = 1; if (!cp_getvar("fourgridsize", CP_NUM, &fourgridsize, 0) || fourgridsize < 1) @@ -112,14 +114,16 @@ fourier(wordlist *wl, struct plot *current_plot) if (polydegree) { double *dp, d; + /* Get fourgridsize points per period */ + fourgridsize = fourgridsize * nperiods; /* Build the grid... */ timescale = TMALLOC(double, fourgridsize); data = TMALLOC(double, fourgridsize); dp = ft_minmax(time, TRUE); /* Now get the last fund freq... */ - d = 1 / fundfreq; /* The wavelength... */ + d = nperiods / fundfreq; /* The wavelength... */ if (dp[1] - dp[0] < d) { - fprintf(cp_err, "Error: wavelength longer than time span\n"); + fprintf(cp_err, "Error: (%d * wavelength) longer than time span\n", nperiods); goto done; } else if (dp[1] - dp[0] > d) { dp[0] = dp[1] - d; @@ -143,7 +147,7 @@ fourier(wordlist *wl, struct plot *current_plot) timescale = time->v_realdata; } - err = CKTfour(fourgridsize, nfreqs, &thd, timescale, + err = CKTfour(fourgridsize, nfreqs, nperiods, &thd, timescale, data, fundfreq, freq, mag, phase, nmag, nphase); if (err != OK) { @@ -153,9 +157,10 @@ fourier(wordlist *wl, struct plot *current_plot) fprintf(cp_out, "Fourier analysis for %s:\n", vec->v_name); fprintf(cp_out, - " No. Harmonics: %d, THD: %g %%, Gridsize: %d, Interpolation Degree: %d\n\n", + " No. Harmonics: %d, THD: %g %%, Gridsize: %d, Interpolation Degree: %d," + " No. Periods: %d\n\n", nfreqs, thd, fourgridsize, - polydegree); + polydegree, nperiods); /* Each field will have width cp_numdgt + 6 (or 7 * with HP-UX) + 1 if there is a - sign. */ @@ -288,6 +293,7 @@ static int CKTfour(int ndata, /* number of entries in the Time and Value arrays */ int numFreq, /* number of harmonics to calculate */ + int numPeriod, /* number of periods for detection */ double *thd, /* total harmonic distortion (percent) to be returned */ double *Time, /* times at which the voltage/current @@ -313,10 +319,10 @@ CKTfour(int ndata, /* number of entries in the Time and * The arrays must all be allocated by the caller. * The Time and Value array must be reasonably distributed over at * least one full period of the fundamental Frequency for the - * fourier transform to be useful. The function will take the - * last period of the frequency as data for the transform. + * fourier transform to be useful. The function will take + * numPeriod periods of the frequency as data for the transform. * - * We are assuming that the caller has provided exactly one period + * We are assuming that the caller has provided exactly numPeriod periods * of the fundamental frequency. */ int i; int j; @@ -331,10 +337,10 @@ CKTfour(int ndata, /* number of entries in the Time and Phase[i] = 0; } - for (i = 0; i < ndata; i++) + for (i = 0; i < ndata ; i++) for (j = 0; j < numFreq; j++) { - Mag[j] += Value[i] * sin(j*2.0*M_PI*i/((double)ndata)); - Phase[j] += Value[i] * cos(j*2.0*M_PI*i/((double)ndata)); + Mag[j] += Value[i] * sin(j*2.0*M_PI*numPeriod*i/((double)ndata)); + Phase[j] += Value[i] * cos(j*2.0*M_PI*numPeriod*i/((double)ndata)); } Mag[0] = Phase[0]/ndata; From f86018afe9df30bda8edfa85694483dfcbd39300 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 28 Feb 2026 16:17:43 +0100 Subject: [PATCH 141/161] Do not give up when non-existing fft window is chosen, but issue a message and go on. --- src/frontend/com_fft.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/com_fft.c b/src/frontend/com_fft.c index 2d592525b..f93baac97 100644 --- a/src/frontend/com_fft.c +++ b/src/frontend/com_fft.c @@ -84,7 +84,7 @@ com_fft(wordlist *wl) order = 2; if (fft_windows(window, win, time, length, maxt, span, order) == 0) - goto done; + fprintf(cp_err, "Warning: unknown window type %s for fft, set to \"none\" \n", window); names = ft_getpnames_quotes(wl, TRUE); vlist = NULL; From b5112b18e5e22943f5067a8f6df53e01b6d24f41 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 3 Mar 2026 16:16:58 +0100 Subject: [PATCH 142/161] FM and FC exchange place in the parameter sequence of SFFM voltage and current source, to become compatible with standard SPICE. Fixes bug 832. --- src/spicelib/devices/isrc/isrcload.c | 6 +++--- src/spicelib/devices/vsrc/vsrcload.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/spicelib/devices/isrc/isrcload.c b/src/spicelib/devices/isrc/isrcload.c index d88cc4072..67e96e3bf 100644 --- a/src/spicelib/devices/isrc/isrcload.c +++ b/src/spicelib/devices/isrc/isrcload.c @@ -205,18 +205,18 @@ ISRCload(GENmodel *inModel, CKTcircuit *ckt) case SFFM: { - double VO, VA, FM, MDI, FC, TD, PHASEM, PHASEC; + double VO, VA, FC, MDI, FM, TD, PHASEM, PHASEC; double phasec; double phasem; static bool warn1 = FALSE, warn2 = FALSE; VO = here->ISRCcoeffs[0]; VA = here->ISRCcoeffs[1]; - FM = here->ISRCfunctionOrder > 2 + FC = here->ISRCfunctionOrder > 2 ? here->ISRCcoeffs[2] : (5./ckt->CKTfinalTime); MDI = here->ISRCfunctionOrder > 3 ? here->ISRCcoeffs[3] : 90.0; - FC = here->ISRCfunctionOrder > 4 + FM = here->ISRCfunctionOrder > 4 && here->ISRCcoeffs[4] ? here->ISRCcoeffs[4] : (500./ckt->CKTfinalTime); TD = here->ISRCfunctionOrder > 5 diff --git a/src/spicelib/devices/vsrc/vsrcload.c b/src/spicelib/devices/vsrc/vsrcload.c index c4190d25d..3e2f86b8e 100644 --- a/src/spicelib/devices/vsrc/vsrcload.c +++ b/src/spicelib/devices/vsrc/vsrcload.c @@ -233,18 +233,18 @@ VSRCload(GENmodel *inModel, CKTcircuit *ckt) case SFFM: { - double VO, VA, FM, MDI, FC, TD, PHASEM, PHASEC; + double VO, VA, FC, MDI, FM, TD, PHASEM, PHASEC; double phasec; double phasem; static bool warn1 = FALSE, warn2 = FALSE; VO = here->VSRCcoeffs[0]; VA = here->VSRCcoeffs[1]; - FM = here->VSRCfunctionOrder > 2 + FC = here->VSRCfunctionOrder > 2 ? here->VSRCcoeffs[2] : (5./ckt->CKTfinalTime); MDI = here->VSRCfunctionOrder > 3 ? here->VSRCcoeffs[3] : 90.0; /* 0.9 * FC / FM */ - FC = here->VSRCfunctionOrder > 4 + FM = here->VSRCfunctionOrder > 4 && here->VSRCcoeffs[4] /* test if not 0 */ ? here->VSRCcoeffs[4] : (500./ckt->CKTfinalTime); TD = here->VSRCfunctionOrder > 5 From 7d0dce0e70a0f51f769807cbe5384d04c4c96749 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 10 Mar 2026 23:21:59 +0100 Subject: [PATCH 143/161] Update to warning messages if osdi or code model files cannot be loaded --- src/frontend/com_dl.c | 2 ++ src/frontend/options.c | 1 + src/include/ngspice/fteext.h | 2 ++ 3 files changed, 5 insertions(+) diff --git a/src/frontend/com_dl.c b/src/frontend/com_dl.c index c2d3f4e49..6cc5202e9 100644 --- a/src/frontend/com_dl.c +++ b/src/frontend/com_dl.c @@ -15,6 +15,7 @@ if (wl && wl->wl_word) if (load_opus(wl->wl_word)) { fprintf(stderr, "Error: Library %s couldn't be loaded!\n", wl->wl_word); ft_spiniterror = TRUE; + ft_codemodelerror = TRUE; if (ft_stricterror) /* if set in spinit */ controlled_exit(EXIT_BAD); } @@ -34,6 +35,7 @@ void com_osdi(wordlist *wl) if (load_osdi(ww->wl_word)) { fprintf(cp_err, "Error: Library %s couldn't be loaded!\n", ww->wl_word); ft_spiniterror = TRUE; + ft_osdierror = TRUE; if (ft_stricterror) controlled_exit(EXIT_BAD); } diff --git a/src/frontend/options.c b/src/frontend/options.c index d6da5a46c..6e14d99b0 100644 --- a/src/frontend/options.c +++ b/src/frontend/options.c @@ -25,6 +25,7 @@ bool ft_acctprint = FALSE, ft_noacctprint = FALSE, ft_listprint = FALSE; bool ft_nodesprint = FALSE, ft_optsprint = FALSE, ft_noinitprint = FALSE; bool ft_norefprint = FALSE, ft_skywaterpdk = FALSE; bool ft_ngdebug = FALSE, ft_nginfo = FALSE, ft_stricterror = FALSE, ft_spiniterror = FALSE; +bool ft_codemodelerror = FALSE, ft_osdierror = FALSE; static void setdb(char *str); static struct variable *cp_enqvec_as_var(const char *vec_name, diff --git a/src/include/ngspice/fteext.h b/src/include/ngspice/fteext.h index af74009bd..7aa0202b6 100644 --- a/src/include/ngspice/fteext.h +++ b/src/include/ngspice/fteext.h @@ -270,6 +270,8 @@ extern bool ft_ngdebug; extern bool ft_nginfo; extern bool ft_stricterror; extern bool ft_spiniterror; +extern bool ft_codemodelerror; +extern bool ft_osdierror; extern bool ft_skywaterpdk; /* parse.c */ From 38ce7778b3d49d4c44498b9163a581fd015ac593 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 10 Mar 2026 23:24:15 +0100 Subject: [PATCH 144/161] Update 2 to warning messages if osdi or code model files cannot be loaded --- src/frontend/inpcom.c | 10 ++++++++++ src/spicelib/devices/dev.c | 12 +++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 0a7cc4739..50ec5ab68 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -1105,6 +1105,16 @@ struct card *inp_readall(FILE *fp, const char *dir_name, const char* file_name, if (newcompat.ps && newcompat.a) pspice_compat_a(working); + /* another warning that codemodels or osdi libs have not been loaded successfully */ + if (ft_osdierror) { + fprintf(stderr, "Warning: OSDI libs have not been loaded successfully.\n"); + fprintf(stderr, " Any of the following steps may fail, if Verilog A models are involved!.\n\n"); + } + if (ft_codemodelerror) { + fprintf(stderr, "Warning: code models like analog.cm have not been loaded successfully.\n"); + fprintf(stderr, " Any of the following steps may fail, if code models are involved!.\n\n"); + } + struct nscope *root = inp_add_levels(working); inp_probe(working); diff --git a/src/spicelib/devices/dev.c b/src/spicelib/devices/dev.c index 3e07b1beb..b3514919e 100644 --- a/src/spicelib/devices/dev.c +++ b/src/spicelib/devices/dev.c @@ -58,6 +58,7 @@ static void free_dlerr_msg(char *msg); #define RTLD_NOW 2 /* immediate function call binding */ #define RTLD_GLOBAL 4 /* symbols in this dlopen'ed obj are visible to other * dlopen'ed objs */ +#define F_OK 0 #endif /* ifndef HAS_WINGUI */ #include "ngspice/dllitf.h" /* the coreInfo Structure*/ @@ -405,9 +406,14 @@ int load_opus(const char *name) lib = dlopen(name, RTLD_NOW); // fprintf(stdout, "Lib %s has handle %p\n", name, lib); if (!lib) { - msg = dlerror(); - fprintf(stderr, "Error opening code model \"%s\"\n: %s\n", name, msg); - FREE_DLERR_MSG(msg); + int acc = access(name, F_OK); + if (acc != 0) { + fprintf(stderr, "Error opening code model \"%s\": No such file or directory!\n", + name); + } + else + fprintf(stderr, "Error opening code model \"%s\"\n", name); + return 1; } From a0bf7f7e8a3375a0834a8a88ddb82173507248c5 Mon Sep 17 00:00:00 2001 From: dwarning Date: Sat, 14 Mar 2026 12:03:49 +0100 Subject: [PATCH 145/161] Diode soft recovery model based on the idea of A. Buermen with iterated charge node for diffusion charge and model parameter Vp. Small simplifications in AC model and capacitance reporting are made. No self-heating for this effect. Pole-Zero and distortion analysis is not implemented for this model extension. --- src/spicelib/devices/dio/dio.c | 3 +- src/spicelib/devices/dio/dioacld.c | 14 +++ src/spicelib/devices/dio/dioask.c | 4 + src/spicelib/devices/dio/diobindCSC.c | 24 +++++ src/spicelib/devices/dio/diodefs.h | 48 ++++++--- src/spicelib/devices/dio/dioload.c | 137 +++++++++++++++++++++++--- src/spicelib/devices/dio/diomask.c | 5 +- src/spicelib/devices/dio/diompar.c | 6 +- src/spicelib/devices/dio/diosetup.c | 34 ++++++- src/spicelib/devices/dio/diotrunc.c | 2 + 10 files changed, 244 insertions(+), 33 deletions(-) diff --git a/src/spicelib/devices/dio/dio.c b/src/spicelib/devices/dio/dio.c index 2ebeb2e41..c7b160f79 100644 --- a/src/spicelib/devices/dio/dio.c +++ b/src/spicelib/devices/dio/dio.c @@ -1,7 +1,7 @@ /********** Copyright 1990 Regents of the University of California. All rights reserved. Author: 1985 Thomas L. Quarles -Modified by Paolo Nenzi 2003 and Dietmar Warning 2012 +Modified by Paolo Nenzi 2003, Dietmar Warning 2012 and Arpad Buermen 2025 **********/ #include "ngspice/ngspice.h" @@ -122,6 +122,7 @@ IFparm DIOmPTable[] = { /* model parameters */ OPU( "cond", DIO_MOD_COND,IF_REAL, "Ohmic conductance"), IOP( "isr", DIO_MOD_ISR, IF_REAL, "Recombination saturation current"), IOP( "nr", DIO_MOD_NR, IF_REAL, "Recombination current emission coefficient"), + IOP( "vp", DIO_MOD_VP, IF_REAL, "Soft reverse recovery parameter"), /* SOA parameters */ IOPX( "fv_max", DIO_MOD_FV_MAX, IF_REAL, "maximum voltage in forward direction"), diff --git a/src/spicelib/devices/dio/dioacld.c b/src/spicelib/devices/dio/dioacld.c index 62ad65efd..62116d8f5 100644 --- a/src/spicelib/devices/dio/dioacld.c +++ b/src/spicelib/devices/dio/dioacld.c @@ -91,6 +91,20 @@ DIOacLoad(GENmodel *inModel, CKTcircuit *ckt) (*(here->DIOnegTempPtr) += -dIdioSw_dT); } } + if ((here->DIOqpNode > 0) && (model->DIOsoftRevRecParam!=0) && (here->DIOtTransitTime!=0)) { + /* QP subcircuit */ + double gdres= *(ckt->CKTstate0 + here->DIOresConduct); + double fac = here->DIOtTransitTime / model->DIOsoftRevRecParam; + double dcrrdvd = fac * gdres; + *(here->DIOqpQpPtr) += 1/model->DIOsoftRevRecParam; + *(here->DIOqpQpPtr + 1) += here->DIOtTransitTime * ckt->CKTomega; + *(here->DIOqpPosPrimePtr) += -dcrrdvd; + *(here->DIOqpNegPtr) += dcrrdvd; + /* Gain of VCVS (1-vp)/tau * j*omega*tau = (1-vp) * j*omega */ + double xgain = (1 - model->DIOsoftRevRecParam) * ckt->CKTomega; + *(here->DIOposPrimeQpPtr + 1) += xgain; + *(here->DIOnegQpPtr + 1) += -xgain; + } } } return(OK); diff --git a/src/spicelib/devices/dio/dioask.c b/src/spicelib/devices/dio/dioask.c index 67009b889..e40d5c4d0 100644 --- a/src/spicelib/devices/dio/dioask.c +++ b/src/spicelib/devices/dio/dioask.c @@ -75,9 +75,13 @@ DIOask (CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value, return(OK); case DIO_CURRENT: value->rValue = *(ckt->CKTstate0+here->DIOcurrent); + if ((here->DIOqpNode > 0) && (here->DIOtTransitTime!=0)) + value->rValue += here->DIOqpGain * *(ckt->CKTstate0 + here->DIOcqcsr); return(OK); case DIO_CAP: value->rValue = here->DIOcap; + if ((here->DIOqpNode > 0) && (here->DIOtTransitTime!=0)) + value->rValue += here->DIOtTransitTime * *(ckt->CKTstate0+here->DIOconduct); return(OK); case DIO_CHARGE: value->rValue = *(ckt->CKTstate0+here->DIOcapCharge); diff --git a/src/spicelib/devices/dio/diobindCSC.c b/src/spicelib/devices/dio/diobindCSC.c index 29cee9cff..89994448e 100644 --- a/src/spicelib/devices/dio/diobindCSC.c +++ b/src/spicelib/devices/dio/diobindCSC.c @@ -54,6 +54,14 @@ DIObindCSC (GENmodel *inModel, CKTcircuit *ckt) CREATE_KLU_BINDING_TABLE(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode); } } + /* rev-rec */ + if (model->DIOsoftRevRecParamGiven && model->DIOsoftRevRecParam!=0 && model->DIOtransitTime!=0) { + CREATE_KLU_BINDING_TABLE(DIOqpQpPtr , DIOqpQpBinding , DIOqpNode, DIOqpNode); + CREATE_KLU_BINDING_TABLE(DIOqpPosPrimePtr, DIOqpPosPrimeBinding, DIOqpNode, DIOposPrimeNode); + CREATE_KLU_BINDING_TABLE(DIOqpNegPtr , DIOqpNegBinding , DIOqpNode, DIOnegNode); + CREATE_KLU_BINDING_TABLE(DIOposPrimeQpPtr, DIOposPrimeQpBinding, DIOposPrimeNode, DIOqpNode); + CREATE_KLU_BINDING_TABLE(DIOnegQpPtr , DIOnegQpBinding , DIOnegNode, DIOqpNode); + } } } @@ -103,6 +111,14 @@ DIObindCSCComplex (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode); } } + /* rev-rec */ + if (model->DIOsoftRevRecParamGiven && model->DIOsoftRevRecParam!=0 && model->DIOtransitTime!=0) { + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOqpQpPtr , DIOqpQpBinding , DIOqpNode, DIOqpNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOqpPosPrimePtr, DIOqpPosPrimeBinding, DIOqpNode, DIOposPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOqpNegPtr , DIOqpNegBinding , DIOqpNode, DIOnegNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposPrimeQpPtr, DIOposPrimeQpBinding, DIOposPrimeNode, DIOqpNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOnegQpPtr , DIOnegQpBinding , DIOnegNode, DIOqpNode); + } } } @@ -152,6 +168,14 @@ DIObindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode); } } + /* rev-rec */ + if (model->DIOsoftRevRecParamGiven && model->DIOsoftRevRecParam!=0 && model->DIOtransitTime!=0) { + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOqpQpPtr , DIOqpQpBinding , DIOqpNode, DIOqpNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOqpPosPrimePtr, DIOqpPosPrimeBinding, DIOqpNode, DIOposPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOqpNegPtr , DIOqpNegBinding , DIOqpNode, DIOnegNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposPrimeQpPtr, DIOposPrimeQpBinding, DIOposPrimeNode, DIOqpNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOnegQpPtr , DIOnegQpBinding , DIOnegNode, DIOqpNode); + } } } diff --git a/src/spicelib/devices/dio/diodefs.h b/src/spicelib/devices/dio/diodefs.h index 298f330b9..0a1f056a8 100644 --- a/src/spicelib/devices/dio/diodefs.h +++ b/src/spicelib/devices/dio/diodefs.h @@ -1,7 +1,7 @@ /********** Copyright 1990 Regents of the University of California. All rights reserved. Author: 1985 Thomas L. Quarles -Modified by Paolo Nenzi 2003 and Dietmar Warning 2012 +Modified by Paolo Nenzi 2003, Dietmar Warning 2012 and Arpad Buermen 2025 **********/ #ifndef DIO #define DIO @@ -44,6 +44,7 @@ typedef struct sDIOinstance { const int DIOtempNode; /* number of the temperature node of the diode */ int DIOposPrimeNode; /* number of positive prime node of diode */ int DIOposSwPrimeNode; /* number of positive prime node of diode sidewall */ + int DIOqpNode; /* number of soft recovery charge node */ double *DIOposPosPrimePtr; /* pointer to sparse matrix at * (positive,positive prime) */ @@ -83,9 +84,19 @@ typedef struct sDIOinstance { double *DIOtempPosSwPrimePtr; double *DIOposSwPrimeTempPtr; + /* rev-rec */ + double *DIOqpQpPtr; + double *DIOqpPosPrimePtr; + double *DIOqpNegPtr; + double *DIOposPrimeQpPtr; + double *DIOnegQpPtr; + double DIOcap; /* stores the diode capacitance */ double DIOcapSW; /* stores the diode Sw capacitance */ + /* rev-rec */ + double DIOqpGain;/* converts iterated diffcharge current */ + double *DIOsens; /* stores the perturbed values of geq and ceq in ac sensitivity analyis */ @@ -229,13 +240,19 @@ typedef struct sDIOinstance { /* self heating */ BindElement *DIOtempPosBinding; BindElement *DIOtempPosPrimeBinding; - BindElement *DIOtempNegBinding; + BindElement *DIOtempNegBinding; BindElement *DIOtempTempBinding; BindElement *DIOposTempBinding; BindElement *DIOposPrimeTempBinding; BindElement *DIOnegTempBinding; BindElement *DIOtempPosSwPrimeBinding; BindElement *DIOposSwPrimeTempBinding; + /* rev-rec */ + BindElement *DIOqpQpBinding; + BindElement *DIOqpPosPrimeBinding; + BindElement *DIOqpNegBinding; + BindElement *DIOposPrimeQpBinding; + BindElement *DIOnegQpBinding; #endif } DIOinstance ; @@ -244,7 +261,6 @@ typedef struct sDIOinstance { #define DIOsenCeq DIOsens + 3 /* stores the perturbed values of ceq */ #define DIOdphidp DIOsens + 6 - #define DIOvoltage DIOstate #define DIOcurrent DIOstate+1 #define DIOconduct DIOstate+2 @@ -256,18 +272,25 @@ typedef struct sDIOinstance { #define DIOcapChargeSW DIOstate+8 #define DIOcapCurrentSW DIOstate+9 -#define DIOqth DIOstate+10 /* thermal capacitor charge */ -#define DIOcqth DIOstate+11 /* thermal capacitor current */ - -#define DIOdeltemp DIOstate+12 /* thermal voltage over rth0 */ +#define DIOqth DIOstate+10 /* thermal capacitor charge */ +#define DIOcqth DIOstate+11 /* thermal capacitor current */ +#define DIOdeltemp DIOstate+12 /* thermal voltage over rth0 */ #define DIOdIdio_dT DIOstate+13 #define DIOdIdioSW_dT DIOstate+14 +/* rev-rec */ +#define DIOsrcapCharge DIOstate+15 +#define DIOsrcapCurrent DIOstate+16 +#define DIOqp DIOstate+17 +#define DIOresCurrent DIOstate+18 +#define DIOresConduct DIOstate+19 +#define DIOcqcsr DIOstate+20 +#define DIOgqcsr DIOstate+21 -#define DIOnumStates 15 +#define DIOnumStates 22 -#define DIOsensxp DIOstate+15 /* charge sensitivities and their derivatives. - * +16 for the derivatives - pointer to the - * beginning of the array */ +#define DIOsensxp DIOstate+22 /* charge sensitivities and their derivatives. + * +23 for the derivatives - pointer to the + * beginning of the array */ #define DIOnumSenStates 2 @@ -342,6 +365,7 @@ typedef struct sDIOmodel { /* model structure for a diode */ unsigned DIOte_maxGiven : 1; unsigned DIOrecSatCurGiven : 1; unsigned DIOrecEmissionCoeffGiven : 1; + unsigned DIOsoftRevRecParamGiven : 1; unsigned DIOrth0Given :1; unsigned DIOcth0Given :1; @@ -418,6 +442,7 @@ typedef struct sDIOmodel { /* model structure for a diode */ double DIOte_max; /* maximum temperature */ double DIOrecSatCur; /* Recombination saturation current */ double DIOrecEmissionCoeff; /* Recombination emission coefficient */ + double DIOsoftRevRecParam; /* Soft reverse recovery parameter */ double DIOrth0; double DIOcth0; @@ -526,6 +551,7 @@ enum { DIO_MOD_PD_MAX, DIO_MOD_ISR, DIO_MOD_NR, + DIO_MOD_VP, DIO_MOD_RTH0, DIO_MOD_CTH0, diff --git a/src/spicelib/devices/dio/dioload.c b/src/spicelib/devices/dio/dioload.c index 6f53966eb..80ade0970 100644 --- a/src/spicelib/devices/dio/dioload.c +++ b/src/spicelib/devices/dio/dioload.c @@ -2,7 +2,7 @@ Copyright 1990 Regents of the University of California. All rights reserved. Author: 1985 Thomas L. Quarles Modified: 2000 AlansFixes -Modified by Paolo Nenzi 2003 and Dietmar Warning 2012 +Modified by Paolo Nenzi 2003, Dietmar Warning 2012 and Arpad Buermen 2025 **********/ #include "ngspice/ngspice.h" @@ -65,6 +65,10 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) double dIdio_dT, dIth_dVdio=0.0, dIrs_dT=0.0, dIth_dVrs=0.0, dIth_dT=0.0; double dIdioSw_dT=0.0, dIth_dVdioSw=0.0, dIth_dVrssw=0.0, dIrssw_dT=0.0; double argsw_dT, csat_dT, csatsw_dT; + /* rev-rec */ + double cdres, gdres; + double vqp; + double capsr, gqcsr, cqcsr; /* loop through all the diode models */ for( ; model != NULL; model = DIOnextModel(model)) { @@ -74,6 +78,7 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) here=DIOnextInstance(here)) { int selfheat = ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given)); + int revrec = ((here->DIOqpNode > 0) && (model->DIOsoftRevRecParam!=0) && (here->DIOtTransitTime!=0)); /* * this routine loads diodes for dc and transient analyses. @@ -120,10 +125,12 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) vd = *(ckt->CKTstate1 + here->DIOvoltage); if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate1 + here->DIOvoltageSW); delTemp = *(ckt->CKTstate1 + here->DIOdeltemp); + vqp = *(ckt->CKTstate1 + here->DIOqp); } else{ vd = *(ckt->CKTstate0 + here->DIOvoltage); if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate0 + here->DIOvoltageSW); delTemp = *(ckt->CKTstate0 + here->DIOdeltemp); + vqp = *(ckt->CKTstate0 + here->DIOqp); } #ifdef SENSDEBUG @@ -137,24 +144,30 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) vd= *(ckt->CKTstate0 + here->DIOvoltage); if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate0 + here->DIOvoltageSW); delTemp = *(ckt->CKTstate0 + here->DIOdeltemp); + vqp= *(ckt->CKTstate0 + here->DIOqp); } else if (ckt->CKTmode & MODEINITTRAN) { vd= *(ckt->CKTstate1 + here->DIOvoltage); if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate1 + here->DIOvoltageSW); delTemp = *(ckt->CKTstate1 + here->DIOdeltemp); + vqp= *(ckt->CKTstate1 + here->DIOqp); } else if ( (ckt->CKTmode & MODEINITJCT) && (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC) ) { vd=here->DIOinitCond; if (model->DIOresistSWGiven) vdsw = here->DIOinitCond; + vqp=0; } else if ( (ckt->CKTmode & MODEINITJCT) && here->DIOoff) { vd=vdsw=0; delTemp = 0.0; + vqp=0; } else if ( ckt->CKTmode & MODEINITJCT) { vd=here->DIOtVcrit; vdsw=here->DIOtVcritSW; delTemp = 0.0; + vqp=0; } else if ( ckt->CKTmode & MODEINITFIX && here->DIOoff) { vd=vdsw=0; delTemp = 0.0; + vqp=0; } else { #ifndef PREDICTOR if (ckt->CKTmode & MODEINITPRED) { @@ -177,12 +190,22 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) *(ckt->CKTstate0 + here->DIOdIdioSW_dT) = *(ckt->CKTstate1 + here->DIOdIdioSW_dT); } + vqp = DEVpred(ckt,here->DIOqp); + *(ckt->CKTstate0 + here->DIOresCurrent) = + *(ckt->CKTstate1 + here->DIOresCurrent); + *(ckt->CKTstate0 + here->DIOresConduct) = + *(ckt->CKTstate1 + here->DIOresConduct); + *(ckt->CKTstate0 + here->DIOcqcsr) = + *(ckt->CKTstate1 + here->DIOcqcsr); + *(ckt->CKTstate0 + here->DIOgqcsr) = + *(ckt->CKTstate1 + here->DIOgqcsr); } else { #endif /* PREDICTOR */ vd = *(ckt->CKTrhsOld+here->DIOposPrimeNode)- *(ckt->CKTrhsOld + here->DIOnegNode); if (model->DIOresistSWGiven) vdsw = *(ckt->CKTrhsOld+here->DIOposSwPrimeNode)- *(ckt->CKTrhsOld + here->DIOnegNode); + if (selfheat) delTemp = *(ckt->CKTrhsOld + here->DIOtempNode); else @@ -192,6 +215,7 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) *(ckt->CKTstate1+here->DIOqth) = *(ckt->CKTstate0+here->DIOqth); } + vqp = *(ckt->CKTrhsOld+here->DIOqpNode); #ifndef PREDICTOR } #endif /* PREDICTOR */ @@ -238,6 +262,11 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) gdsw= *(ckt->CKTstate0 + here->DIOconductSW); dIdioSw_dT= *(ckt->CKTstate0 + here->DIOdIdioSW_dT); } + vqp= *(ckt->CKTstate0 + here->DIOqp); + cdres= *(ckt->CKTstate0 + here->DIOresCurrent); + gdres= *(ckt->CKTstate0 + here->DIOresConduct); + cqcsr= *(ckt->CKTstate0 + here->DIOcqcsr); + gqcsr= *(ckt->CKTstate0 + here->DIOgqcsr); goto load; } } @@ -304,7 +333,7 @@ next1: if (model->DIOsatSWCurGiven) { /* sidewall current */ double vds; - if (model->DIOresistSWGiven) + if (model->DIOresistSWGiven) vds = vdsw; /* sidewall voltage used */ else vds = vd; /* common voltage used */ @@ -470,7 +499,6 @@ next1: gdb = ((1+sqrt_ikx)*gdb + cdb*gdb/(2*sqrt_ikx*ikr_area_m))/(1+2*sqrt_ikx - cdb/ikr_area_m); cdb = cdb/(1+sqrt_ikx); } - } if ( (model->DIOforwardSWKneeCurrentGiven) && (cdsw > 1.0e-18) ) { @@ -493,6 +521,11 @@ next1: dIdioSw_dT = cdsw_dT; } + cdres = cd; + gdres = gd; + cqcsr = 0; + gqcsr = 0; + if ((ckt->CKTmode & (MODEDCTRANCURVE | MODETRAN | MODEAC | MODEINITSMSIG)) || ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) { /* @@ -528,22 +561,46 @@ next1: deplcapSW = czof2SW*(here->DIOtF3SW+model->DIOgradingSWCoeff*vdx/here->DIOtJctSWPot); } - diffcharge = here->DIOtTransitTime*cd; - diffcap = here->DIOtTransitTime*gd; - if (!model->DIOresistSWGiven) { + if (revrec) { + /* + soft recovery with TT!=0 + add only depletion capacitance. + */ *(ckt->CKTstate0 + here->DIOcapCharge) = - diffcharge + deplcharge + deplchargeSW + (here->DIOcmetal + here->DIOcpoly)*vd; - capd = diffcap + deplcap + deplcapSW + here->DIOcmetal + here->DIOcpoly; + deplcharge + deplchargeSW + (here->DIOcmetal + here->DIOcpoly)*vd; + + capd = deplcap + deplcapSW + here->DIOcmetal + here->DIOcpoly; here->DIOcap = capd; + /* + DIOcap is now equal only to depletion capacitance + overlap capacitance. + Diffusion capacitance is modelled via Qp so there is no clear way to define it. + */ + + /* Now prepare the charge for the capacitor connected to the QP node */ + *(ckt->CKTstate0 + here->DIOsrcapCharge) = here->DIOtTransitTime * vqp; + capsr = here->DIOtTransitTime; } else { - *(ckt->CKTstate0 + here->DIOcapCharge) = - diffcharge + deplcharge + (here->DIOcmetal + here->DIOcpoly)*vd; - capd = diffcap + deplcap + here->DIOcmetal + here->DIOcpoly; - here->DIOcap = capd; - *(ckt->CKTstate0 + here->DIOcapChargeSW) = - deplcapSW; - capdsw = deplcapSW; - here->DIOcapSW = capdsw; + /* no soft recovery of soft recovery with TT=0 (i.e. no soft recovery due to TT=0) */ + diffcharge = here->DIOtTransitTime*cd; + diffcap = here->DIOtTransitTime*gd; + if (!model->DIOresistSWGiven) { + *(ckt->CKTstate0 + here->DIOcapCharge) = + diffcharge + deplcharge + deplchargeSW + (here->DIOcmetal + here->DIOcpoly)*vd; + capd = diffcap + deplcap + deplcapSW + here->DIOcmetal + here->DIOcpoly; + here->DIOcap = capd; + } else { + *(ckt->CKTstate0 + here->DIOcapCharge) = + diffcharge + deplcharge + (here->DIOcmetal + here->DIOcpoly)*vd; + capd = diffcap + deplcap + here->DIOcmetal + here->DIOcpoly; + here->DIOcap = capd; + *(ckt->CKTstate0 + here->DIOcapChargeSW) = + deplcapSW; + capdsw = deplcapSW; + here->DIOcapSW = capdsw; + } + + *(ckt->CKTstate0 + here->DIOsrcapCharge) = 0; + capsr = 0; } /* * store small-signal parameters @@ -564,6 +621,10 @@ next1: *(ckt->CKTstate0 + here->DIOconductSW) = gdsw; *(ckt->CKTstate0 + here->DIOdIdioSW_dT) = dIdioSw_dT; } + *(ckt->CKTstate0 + here->DIOresCurrent) = cdres; + *(ckt->CKTstate0 + here->DIOresConduct) = gdres; + *(ckt->CKTstate0 + here->DIOcqcsr) = cqcsr; + *(ckt->CKTstate0 + here->DIOgqcsr) = gqcsr; #ifdef SENSDEBUG printf("storing small signal parameters\n"); printf("cd = %.7e,vd = %.7e\n",cd,vd); @@ -580,6 +641,7 @@ next1: *(ckt->CKTstate0 + here->DIOcurrent) = cd; if (model->DIOresistSWGiven) *(ckt->CKTstate0 + here->DIOcurrentSW) = cdsw; + *(ckt->CKTstate0 + here->DIOresCurrent) = cdres; #ifdef SENSDEBUG printf("storing parameters for transient sensitivity\n" ); @@ -613,6 +675,21 @@ next1: *(ckt->CKTstate1 + here->DIOcapCurrentSW) = *(ckt->CKTstate0 + here->DIOcapCurrentSW); } + if (revrec) { + /* soft recovery subcircuit */ + if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->DIOsrcapCharge) = + *(ckt->CKTstate0 + here->DIOsrcapCharge); + } + error = NIintegrate(ckt,&geq,&ceq,capsr,here->DIOsrcapCharge); + if(error) return(error); + gqcsr = geq; + cqcsr = *(ckt->CKTstate0 + here->DIOsrcapCurrent); + if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->DIOsrcapCurrent) = + *(ckt->CKTstate0 + here->DIOsrcapCurrent); + } + } if (selfheat) { error = NIintegrate(ckt, &gcTt, &ceqqth, model->DIOcth0, here->DIOqth); @@ -654,6 +731,11 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd; *(ckt->CKTstate0 + here->DIOconductSW) = gdsw; *(ckt->CKTstate0 + here->DIOdIdioSW_dT) = dIdioSw_dT; } + *(ckt->CKTstate0 + here->DIOqp) = vqp; + *(ckt->CKTstate0 + here->DIOresCurrent) = cdres; + *(ckt->CKTstate0 + here->DIOresConduct) = gdres; + *(ckt->CKTstate0 + here->DIOcqcsr) = cqcsr; + *(ckt->CKTstate0 + here->DIOgqcsr) = gqcsr; if(SenCond) continue; #ifndef NOBYPASS @@ -754,6 +836,29 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd; (*(here->DIOnegTempPtr) += -dIdioSw_dT); } } + + if (revrec) { + double fac, ceqrr, dcrrdvd, grr; + double ceqrrd, geqrrd; + /* QP subcircuit */ + fac = here->DIOtTransitTime / model->DIOsoftRevRecParam; + dcrrdvd = fac*gdres; + ceqrr = -fac*cdres + cqcsr + dcrrdvd*vd - gqcsr*vqp; + grr = 1/model->DIOsoftRevRecParam; + *(ckt->CKTrhs + here->DIOqpNode) -= ceqrr; + *(here->DIOqpQpPtr) += grr + gqcsr; + *(here->DIOqpPosPrimePtr) += -dcrrdvd; + *(here->DIOqpNegPtr) += dcrrdvd; + /* Contribution to diode current */ + here->DIOqpGain = (1 - model->DIOsoftRevRecParam) / here->DIOtTransitTime; + /* Linear contribution -(1-vp)/tau*ddt(Qp) */ + geqrrd = here->DIOqpGain*gqcsr; + ceqrrd = here->DIOqpGain*cqcsr - geqrrd*vqp; + *(ckt->CKTrhs + here->DIOposPrimeNode) -= ceqrrd; + *(ckt->CKTrhs + here->DIOnegNode) += ceqrrd; + *(here->DIOposPrimeQpPtr) += geqrrd; + *(here->DIOnegQpPtr) += -geqrrd; + } } } return(OK); diff --git a/src/spicelib/devices/dio/diomask.c b/src/spicelib/devices/dio/diomask.c index 1f4e11ce5..f786f96c9 100644 --- a/src/spicelib/devices/dio/diomask.c +++ b/src/spicelib/devices/dio/diomask.c @@ -1,7 +1,7 @@ /********** Copyright 1990 Regents of the University of California. All rights reserved. Author: 1985 Thomas L. Quarles -Modified by Paolo Nenzi 2003 and Dietmar Warning 2012 +Modified by Paolo Nenzi 2003, Dietmar Warning 2012 and Arpad Buermen 2025 **********/ /* */ @@ -199,6 +199,9 @@ DIOmAsk (CKTcircuit *ckt, GENmodel *inModel, int which, IFvalue *value) case DIO_MOD_NR: value->rValue = model->DIOrecEmissionCoeff; return(OK); + case DIO_MOD_VP: + value->rValue = model->DIOsoftRevRecParam; + return(OK); case DIO_MOD_RTH0: value->rValue = model->DIOrth0; return(OK); diff --git a/src/spicelib/devices/dio/diompar.c b/src/spicelib/devices/dio/diompar.c index 498421160..a6780034b 100644 --- a/src/spicelib/devices/dio/diompar.c +++ b/src/spicelib/devices/dio/diompar.c @@ -1,7 +1,7 @@ /********** Copyright 1990 Regents of the University of California. All rights reserved. Author: 1985 Thomas L. Quarles -Modified by Paolo Nenzi 2003 and Dietmar Warning 2012 +Modified by Paolo Nenzi 2003, Dietmar Warning 2012 and Arpad Buermen 2025 **********/ /* */ @@ -245,6 +245,10 @@ DIOmParam(int param, IFvalue *value, GENmodel *inModel) model->DIOrecEmissionCoeff = value->rValue; model->DIOrecEmissionCoeffGiven = TRUE; break; + case DIO_MOD_VP: + model->DIOsoftRevRecParam = value->rValue; + model->DIOsoftRevRecParamGiven = TRUE; + break; case DIO_MOD_RTH0: model->DIOrth0 = value->rValue; model->DIOrth0Given = TRUE; diff --git a/src/spicelib/devices/dio/diosetup.c b/src/spicelib/devices/dio/diosetup.c index df9555be8..867b7562c 100644 --- a/src/spicelib/devices/dio/diosetup.c +++ b/src/spicelib/devices/dio/diosetup.c @@ -2,7 +2,7 @@ Copyright 1990 Regents of the University of California. All rights reserved. Author: 1985 Thomas L. Quarles Modified: 2000 AlansFixes -Modified by Paolo Nenzi 2003 and Dietmar Warning 2012 +Modified by Paolo Nenzi 2003, Dietmar Warning 2012 and Arpad Buermen 2025 **********/ /* load the diode structure with those pointers needed later @@ -222,6 +222,9 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) if(!model->DIOrecSatCurGiven) { model->DIOrecSatCur = 1e-14; } + if (!model->DIOsoftRevRecParamGiven) { + model->DIOsoftRevRecParam = 0.0; + } /* set lower limit of saturation current */ if (model->DIOsatCur < ckt->CKTepsmin) @@ -412,6 +415,18 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) } } + /* rev-rec */ + if (model->DIOsoftRevRecParamGiven && model->DIOsoftRevRecParam!=0 && model->DIOtransitTime!=0) { + if(here->DIOqpNode == 0) { + error = CKTmkVolt(ckt, &tmp, here->DIOname, "qp"); + if(error) return(error); + here->DIOqpNode = tmp->number; + } + } else { + here->DIOqpNode = 0; + } + + int selfheat = ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given)); /* macro to make elements with built in test for out of memory */ @@ -450,7 +465,15 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ TSTALLOC(DIOposSwPrimeTempPtr, DIOposSwPrimeNode, DIOtempNode); } } - + + /* rev-rec */ + if (model->DIOsoftRevRecParamGiven && model->DIOsoftRevRecParam!=0 && model->DIOtransitTime!=0) { + TSTALLOC(DIOqpQpPtr , DIOqpNode, DIOqpNode); + TSTALLOC(DIOqpPosPrimePtr, DIOqpNode, DIOposPrimeNode); + TSTALLOC(DIOqpNegPtr , DIOqpNode, DIOnegNode); + TSTALLOC(DIOposPrimeQpPtr, DIOposPrimeNode, DIOqpNode); + TSTALLOC(DIOnegQpPtr, DIOnegNode, DIOqpNode); + } } } return(OK); @@ -474,7 +497,7 @@ DIOunsetup( if (here->DIOposPrimeNode > 0 && here->DIOposPrimeNode != here->DIOposNode) CKTdltNNum(ckt, here->DIOposPrimeNode); - here->DIOposPrimeNode = 0; + here->DIOposPrimeNode = 0; if(model->DIOresistSWGiven) { /* separate sidewall */ @@ -484,6 +507,11 @@ DIOunsetup( here->DIOposSwPrimeNode = 0; } + /* rev-rec */ + if (here->DIOqpNode > 0) + CKTdltNNum(ckt, here->DIOqpNode); + here->DIOqpNode = 0; + } } return OK; diff --git a/src/spicelib/devices/dio/diotrunc.c b/src/spicelib/devices/dio/diotrunc.c index b940528be..04070a1d8 100644 --- a/src/spicelib/devices/dio/diotrunc.c +++ b/src/spicelib/devices/dio/diotrunc.c @@ -22,6 +22,8 @@ DIOtrunc(GENmodel *inModel, CKTcircuit *ckt, double *timeStep) for(here=DIOinstances(model);here!=NULL;here = DIOnextInstance(here)){ CKTterr(here->DIOcapCharge,ckt,timeStep); if (model->DIOresistSWGiven) CKTterr(here->DIOcapChargeSW,ckt,timeStep); + if (model->DIOsoftRevRecParam!=0 && here->DIOtTransitTime!=0) + CKTterr(here->DIOsrcapCharge,ckt,timeStep); } } return(OK); From 88895f1394aae80c08d864bdcdaae5068f996b74 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 16 Mar 2026 18:04:39 +0100 Subject: [PATCH 146/161] Parameter np=xx added. xx may be a number or auto2n. If np is not set, 'linearize' behaves as usual, (TSTOP-TSTART)/TSTEP + 1.5 If np=, integer is used If np=auto2n, the number of points is 2^n, close to (TSTOP-TSTART)/TSTEP. --- src/frontend/linear.c | 45 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/src/frontend/linear.c b/src/frontend/linear.c index 3fc903824..ca44d7d8f 100644 --- a/src/frontend/linear.c +++ b/src/frontend/linear.c @@ -28,7 +28,9 @@ com_linearize(wordlist *wl) struct dvec *newtime, *v; struct dvec *oldtime; struct dvec *lin; - int len, i; + int expo, len = 1024, i; + bool nponly = FALSE, np = FALSE; + wordlist * wlnew; if (!plot_cur || !plot_cur->pl_typename || !ciprefix("tran", plot_cur->pl_typename)) { fprintf(cp_err, "Error: plot must be a transient analysis\n"); @@ -98,7 +100,34 @@ com_linearize(wordlist *wl) plot_new(new); plot_setcur(new->pl_typename); plot_list = new; - len = (int)((tstop - tstart) / tstep + 1.5); + + /* check if "np=" is the only entry in wl. +- If yes, linearize all vectors */ + if (wl && ciprefix("np=", wl->wl_word) && wl->wl_next == NULL) { + nponly = TRUE; + } + + wlnew = wl; + /* get the new length from 'np=xx' */ + while (wlnew) { + char* para = wlnew->wl_word; + if (ciprefix("np=", para)) { + np = TRUE; + para += 3; + len = atoi(para); + if (len == 0 && ciprefix("auto2n", para)) { + /* number of points as 2^n */ + expo = (int)round(log2((tstop - tstart) / tstep)); + len = 1 << expo; + } + break; + } + wlnew = wlnew->wl_next; + } + + if(!np) + len = (int)((tstop - tstart) / tstep + 1.5); + newtime = dvec_alloc(copy(oldtime->v_name), oldtime->v_type, oldtime->v_flags | VF_PERMANENT, @@ -109,12 +138,17 @@ com_linearize(wordlist *wl) newtime->v_realdata[i] = d; new->pl_scale = new->pl_dvecs = newtime; - if (wl) { + if (wl && !nponly) { + /* check for vectors given in the command line */ while (wl) { + if (ciprefix("np=", wl->wl_word)) { + wl = wl->wl_next; + continue; + } v = vec_fromplot(wl->wl_word, old); if (!v) { - fprintf(cp_err, "Error: no such vector %s\n", - wl->wl_word); + fprintf(cp_err, "Error: command 'linearize': no such vector %s\n", + wl->wl_word); wl = wl->wl_next; continue; } @@ -122,6 +156,7 @@ com_linearize(wordlist *wl) wl = wl->wl_next; } } else { + /* linearize all vectors of the current plot */ for (v = old->pl_dvecs; v; v = v->v_next) { if (v == old->pl_scale) continue; From 278841972c505cec614c43d4a2a96c02ebde38b3 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Fri, 9 Jan 2026 00:20:21 +0100 Subject: [PATCH 147/161] Add command line support for the 'version [-s|-f]' command With this commit the mentioned ngspice command(s) are also available on the command line. See ngspice --help for more information. --- src/main.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index c547d5475..01702c1f2 100644 --- a/src/main.c +++ b/src/main.c @@ -755,6 +755,8 @@ show_help(void) " -t, --term=TERM set the terminal type\n" " -h, --help display this help and exit\n" " -v, --version output version information and exit\n" + " -f, --version-full output full version information\n" + " --version-small output small version information\n" "\n" "Report bugs to %s.\n", cp_program, Bug_Addr); } @@ -952,6 +954,8 @@ int main(int argc, char **argv) {"define", required_argument, NULL, 'D'}, {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'v'}, + {"version-full", no_argument, NULL, 'f'}, + {"version-small", no_argument, NULL, 256}, {"batch", no_argument, NULL, 'b'}, {"autorun", no_argument, NULL, 'a'}, {"circuitfile", required_argument, NULL, 'c'}, @@ -969,7 +973,7 @@ int main(int argc, char **argv) int option_index = 0; - int c = getopt_long(argc, argv, "D:hvbac:ino:pqr:st:", + int c = getopt_long(argc, argv, "D:hvfbac:ino:pqr:st:", long_options, &option_index); if (c == -1) { @@ -1004,6 +1008,22 @@ int main(int argc, char **argv) sp_shutdown(EXIT_INFO); break; + case 'f': /* Full version info */ + { + wordlist wl = { "-f", NULL, NULL }; + com_version(&wl); + sp_shutdown(EXIT_INFO); + } + break; + + case 256: /* --version-small */ + { + wordlist wl = { "-s", NULL, NULL }; + com_version(&wl); + sp_shutdown(EXIT_INFO); + } + break; + case 'b': /* Batch mode */ { bool x_false = FALSE; From b3a78b02cc635c5a5b4fd87a011253141043257e Mon Sep 17 00:00:00 2001 From: dwarning Date: Fri, 20 Mar 2026 13:33:39 +0100 Subject: [PATCH 148/161] Special Nyquist scaling only for even length. Let nyquist bin not empty for odd vector --- src/frontend/com_fft.c | 15 ++++++++++----- src/maths/cmaths/cmath4.c | 7 +++++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/frontend/com_fft.c b/src/frontend/com_fft.c index f93baac97..8fb4278b5 100644 --- a/src/frontend/com_fft.c +++ b/src/frontend/com_fft.c @@ -185,7 +185,10 @@ com_fft(wordlist *wl) fdvec[i][j].cx_real = out[j][0]/scale; fdvec[i][j].cx_imag = out[j][1]/scale; } - + if (length % 2 == 0) { + fdvec[i][fpts-1].cx_real = out[fpts-1][0]/scale/2.0; + fdvec[i][fpts-1].cx_imag = 0.0; + } } fftw_destroy_plan(plan_forward); @@ -220,7 +223,7 @@ com_fft(wordlist *wl) fdvec[i][j].cx_real = in[2*j]/scale; fdvec[i][j].cx_imag = in[2*j+1]/scale; } - fdvec[i][fpts-1].cx_real = in[1]/scale; + fdvec[i][fpts-1].cx_real = in[1]/scale/2.0; fdvec[i][fpts-1].cx_imag = 0.0; tfree(in); @@ -416,15 +419,17 @@ com_psd(wordlist *wl) fdvec[i][0].cx_real = out[0][0]*out[0][0]/intres; fdvec[i][0].cx_imag = 0; noipower = fdvec[i][0].cx_real; - for (j = 1; j < fpts-1; j++) { + for (j = 1; j < fpts; j++) { fdvec[i][j].cx_real = 2.* (out[j][0]*out[j][0] + out[j][1]*out[j][1])/intres; fdvec[i][j].cx_imag = 0; noipower += fdvec[i][j].cx_real; if (!finite(noipower)) break; } - fdvec[i][fpts-1].cx_real = out[fpts-1][0]*out[fpts-1][0]/intres; - fdvec[i][fpts-1].cx_imag = 0; + if (length % 2 == 0) { + fdvec[i][fpts-1].cx_real = out[fpts-1][0]*out[fpts-1][0]/intres; + fdvec[i][fpts-1].cx_imag = 0; + } noipower += fdvec[i][fpts-1].cx_real; #else /* Green's FFT */ diff --git a/src/maths/cmaths/cmath4.c b/src/maths/cmaths/cmath4.c index a1f547d97..af661e968 100644 --- a/src/maths/cmaths/cmath4.c +++ b/src/maths/cmaths/cmath4.c @@ -781,7 +781,10 @@ cx_fft(void *data, short int type, int length, int *newlength, short int *newtyp outdata[i].cx_real = out[i][0]/scale; outdata[i].cx_imag = out[i][1]/scale; } - + if (length % 2 == 0) { + outdata[fpts-1].cx_real = out[fpts-1][0]/scale/2.0; + outdata[fpts-1].cx_imag = 0.0; + } fftw_free(ind); #else /* Green's FFT */ @@ -808,7 +811,7 @@ cx_fft(void *data, short int type, int length, int *newlength, short int *newtyp outdata[i].cx_real = datax[2*i]/scale; outdata[i].cx_imag = datax[2*i+1]/scale; } - outdata[fpts-1].cx_real = datax[1]/scale; + outdata[fpts-1].cx_real = datax[1]/scale/2.0; outdata[fpts-1].cx_imag = 0.0; #endif From 65e5ccb7bba8dfcbb31dcce69222c8bc5f534966 Mon Sep 17 00:00:00 2001 From: geraldfournier Date: Fri, 20 Mar 2026 13:37:06 +0100 Subject: [PATCH 149/161] Make fft scaling independent from rounding behaviour for odd data. Add a time slot to fft span. --- src/frontend/com_fft.c | 6 +++--- src/maths/cmaths/cmath4.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/frontend/com_fft.c b/src/frontend/com_fft.c index 8fb4278b5..8b74414fc 100644 --- a/src/frontend/com_fft.c +++ b/src/frontend/com_fft.c @@ -59,10 +59,11 @@ com_fft(wordlist *wl) length = (plot_cur->pl_scale)->v_length; time = (plot_cur->pl_scale)->v_realdata; - span = time[length-1] - time[0]; + span = time[length-1] - time[0] + time[length-1] - time[length-2]; #ifdef HAVE_LIBFFTW3 fpts = length/2 + 1; + scale = ((double)length)/2.0; #else /* size of fft input vector is power of two and larger or equal than spice vector */ N = 1; @@ -72,6 +73,7 @@ com_fft(wordlist *wl) M++; } fpts = N/2 + 1; + scale = ((double)N)/2; #endif win = TMALLOC(double, length); @@ -178,7 +180,6 @@ com_fft(wordlist *wl) fftw_execute(plan_forward); - scale = (double) fpts - 1.0; fdvec[i][0].cx_real = out[0][0]/scale/2.0; fdvec[i][0].cx_imag = 0.0; for (j = 1; j < fpts; j++) { @@ -215,7 +216,6 @@ com_fft(wordlist *wl) rffts(in, M, 1); fftFree(); - scale = (double) fpts - 1.0; /* Re(x[0]), Re(x[N/2]), Re(x[1]), Im(x[1]), Re(x[2]), Im(x[2]), ... Re(x[N/2-1]), Im(x[N/2-1]). */ fdvec[i][0].cx_real = in[0]/scale/2.0; fdvec[i][0].cx_imag = 0.0; diff --git a/src/maths/cmaths/cmath4.c b/src/maths/cmaths/cmath4.c index af661e968..04b0b5142 100644 --- a/src/maths/cmaths/cmath4.c +++ b/src/maths/cmaths/cmath4.c @@ -774,7 +774,7 @@ cx_fft(void *data, short int type, int length, int *newlength, short int *newtyp fftw_execute(plan_forward); - scale = (double) fpts - 1.0; + scale = ((double)length)/2.0; outdata[0].cx_real = out[0][0]/scale/2.0; outdata[0].cx_imag = 0.0; for (i = 1; i < fpts; i++) { @@ -803,7 +803,7 @@ cx_fft(void *data, short int type, int length, int *newlength, short int *newtyp rffts(datax, M, 1); fftFree(); - scale = (double) fpts - 1.0; + scale = ((double)N)/2; /* Re(x[0]), Re(x[N/2]), Re(x[1]), Im(x[1]), Re(x[2]), Im(x[2]), ... Re(x[N/2-1]), Im(x[N/2-1]). */ outdata[0].cx_real = datax[0]/scale/2.0; outdata[0].cx_imag = 0.0; From af67662a3fd7d7cdd67b23463fc5632b0222d858 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 20 Mar 2026 16:01:19 +0100 Subject: [PATCH 150/161] In case of transient simulation error, bail out when fft is called. --- src/frontend/com_fft.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/frontend/com_fft.c b/src/frontend/com_fft.c index 8b74414fc..062f40977 100644 --- a/src/frontend/com_fft.c +++ b/src/frontend/com_fft.c @@ -58,6 +58,13 @@ com_fft(wordlist *wl) } length = (plot_cur->pl_scale)->v_length; + + /* in case of tran error */ + if (length < 2) { + fprintf(cp_err, "Error: fft needs more than one time point, check the tran simulation!\n"); + goto done; + } + time = (plot_cur->pl_scale)->v_realdata; span = time[length-1] - time[0] + time[length-1] - time[length-2]; From 2d3e032a3f0ad0fde15bdec1836a8b9072c75df5 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 20 Mar 2026 16:51:24 +0100 Subject: [PATCH 151/161] Remove memory leak. --- src/xspice/enh/enhtrans.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/xspice/enh/enhtrans.c b/src/xspice/enh/enhtrans.c index ce22e2025..44a2b7a59 100644 --- a/src/xspice/enh/enhtrans.c +++ b/src/xspice/enh/enhtrans.c @@ -117,15 +117,13 @@ ENHtranslate_poly( l1->nextcard = l2; d->nextcard = l1; - /* PN 2004: Add original linenumber to ease the debug process - * for malfromned netlist - */ - + /* Add original linenumber to ease the debug process + * for malformed netlist */ l1->linenum = d->linenum; l2->linenum = d->linenum; - l1->linesource = copy("internal"); - l2->linesource = copy("internal"); + l1->linesource = "internal"; + l2->linesource = "internal"; /* Create the translated cards */ d->error = two2three_translate(d->line, &(l1->line), &(l2->line)); From aab3371f36aed64256d2241eb13787df33417312 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 21 Mar 2026 19:57:16 +0100 Subject: [PATCH 152/161] A memory leak occurs when command 'step' is followed by 'quit' without having reached the final TSTOP. New function DCtran_step_quit() removes the leak. --- src/frontend/breakp.c | 13 ++++++++++++- src/frontend/runcoms2.c | 5 +++++ src/include/ngspice/fteext.h | 27 ++------------------------- src/spicelib/analysis/dctran.c | 19 +++++++++++++++++++ 4 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/frontend/breakp.c b/src/frontend/breakp.c index 5dae629bc..8fd822eef 100644 --- a/src/frontend/breakp.c +++ b/src/frontend/breakp.c @@ -517,7 +517,7 @@ ft_bpcheck(struct plot *runplot, int iteration) if ((howmanysteps > 0) && (--howmanysteps == 0)) { if (steps > 1) - fprintf(cp_err, "Stopped after %d steps.\n", steps); + fprintf(cp_out, "Note: Stopped after %d steps.\n", steps); return (FALSE); } @@ -694,3 +694,14 @@ printcond(struct dbcomm *d, FILE *fp) } } } + + +/* just check if we are in 'step' mode */ +bool +ft_stepcheck(void) +{ + if ((steps > 0) && (howmanysteps == 0)) { + return (TRUE); + } + return (FALSE); +} diff --git a/src/frontend/runcoms2.c b/src/frontend/runcoms2.c index baf43ee79..1e98f0073 100644 --- a/src/frontend/runcoms2.c +++ b/src/frontend/runcoms2.c @@ -35,6 +35,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group extern void line_free_x(struct card *deck, bool recurse); extern INPmodel *modtab; extern NGHASHPTR modtabhash; +extern int DCtran_step_quit(CKTcircuit* ckt); #ifdef SHARED_MODULE extern void exec_controls(wordlist *newcontrols); @@ -219,6 +220,10 @@ com_remcirc(wordlist *wl) EVTunsetup(ft_curckt->ci_ckt); #endif + /* remove remnants of run after incomplete transient sim with 'step' */ + if (ft_curckt->ci_ckt) + DCtran_step_quit(ft_curckt->ci_ckt); + if_cktfree(ft_curckt->ci_ckt, ft_curckt->ci_symtab); for (v = ft_curckt->ci_vars; v; v = next) { next = v->va_next; diff --git a/src/include/ngspice/fteext.h b/src/include/ngspice/fteext.h index 7aa0202b6..cb6fffd81 100644 --- a/src/include/ngspice/fteext.h +++ b/src/include/ngspice/fteext.h @@ -26,9 +26,10 @@ Modified: 1999 Paolo Nenzi - 2000 AlansFixes extern void ft_checkkids(void); -/* breakpoint.c */ +/* breakp.c */ extern bool ft_bpcheck(struct plot *runplot, int iteration); +extern bool ft_stepcheck(void); extern void dbfree(struct dbcomm *db); extern void dbfree1(struct dbcomm *db); @@ -173,29 +174,6 @@ extern struct dvec *ft_evaluate(struct pnode *node); /* ftesopt.c */ extern struct variable *ft_getstat(struct circ *, char *); -/* ginterface.c - - extern bool gi_init(); - extern bool gi_endpause; - extern bool gi_rottext; - extern int gi_fntheight; - extern int gi_fntwidth; - extern int gi_maxx; - extern int gi_maxy; - extern int gi_nolst; - extern int gi_nocolors; - extern int gi_package; - extern void gi_arc(); - extern void gi_clearscreen(); - extern void gi_close(); - extern void gi_drawline(); - extern void gi_redraw(); - extern void gi_setcolor(); - extern void gi_resetcolor(); - extern void gi_setlinestyle(); - extern void gi_text(); - extern void gi_update(); -*/ /* graf.c */ @@ -385,6 +363,5 @@ extern struct dvec* copycut(struct dvec* ov, struct dvec* newscalevec, int istar extern bool ft_intrpt; extern bool ft_setflag; -/* error.c */ #endif diff --git a/src/spicelib/analysis/dctran.c b/src/spicelib/analysis/dctran.c index 4c55678d5..033ca6a61 100644 --- a/src/spicelib/analysis/dctran.c +++ b/src/spicelib/analysis/dctran.c @@ -969,3 +969,22 @@ chkStep: } /* NOTREACHED */ } + + +/* If we have a 'step' command, and then 'quit' before reaching the final time, + remove the run plot memory. */ +int +DCtran_step_quit(CKTcircuit* ckt) { + if (!ckt || !ckt->CKTcurJob) /* nothing to delete */ + return 0; + if (ckt->CKTcurJob->JOBtype != 4) /* only tran sim */ + return 0; + if (!ft_stepcheck()) /* only after 'step' */ + return 0; + TRANan* job = (TRANan*)ckt->CKTcurJob; + if (!job->TRANplot) /* already done */ + return 0; + SPfrontEnd->OUTendPlot(job->TRANplot); + job->TRANplot = NULL; + return(OK); +} From cd14f85cde585e155d78490cd299cefebc20e0af Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 25 Mar 2026 12:06:00 +0100 Subject: [PATCH 153/161] Remove ft_skywaterpdk, replace it by variable no_auto_braces --- src/frontend/inpcom.c | 2 +- src/frontend/options.c | 4 +--- src/include/ngspice/fteext.h | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 50ec5ab68..5af0e027b 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -8426,7 +8426,7 @@ static void inp_quote_params(struct card *c, struct card *end_c, { bool in_control = FALSE; - if (ft_skywaterpdk) + if (cp_getvar("no_auto_braces", CP_BOOL, NULL, 0)) return; for (; c && c != end_c; c = c->nextcard) { diff --git a/src/frontend/options.c b/src/frontend/options.c index 6e14d99b0..24f113001 100644 --- a/src/frontend/options.c +++ b/src/frontend/options.c @@ -23,7 +23,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group bool ft_acctprint = FALSE, ft_noacctprint = FALSE, ft_listprint = FALSE; bool ft_nodesprint = FALSE, ft_optsprint = FALSE, ft_noinitprint = FALSE; -bool ft_norefprint = FALSE, ft_skywaterpdk = FALSE; +bool ft_norefprint = FALSE; bool ft_ngdebug = FALSE, ft_nginfo = FALSE, ft_stricterror = FALSE, ft_spiniterror = FALSE; bool ft_codemodelerror = FALSE, ft_osdierror = FALSE; @@ -309,8 +309,6 @@ cp_usrset(struct variable *var, bool isset) ft_ngdebug = isset; } else if (eq(var->va_name, "nginfo")) { ft_nginfo = isset; - } else if (eq(var->va_name, "skywaterpdk")) { - ft_skywaterpdk = isset; } else if (eq(var->va_name, "noinit")) { ft_noinitprint = isset; } else if (eq(var->va_name, "norefvalue")) { diff --git a/src/include/ngspice/fteext.h b/src/include/ngspice/fteext.h index cb6fffd81..e161938a1 100644 --- a/src/include/ngspice/fteext.h +++ b/src/include/ngspice/fteext.h @@ -250,7 +250,6 @@ extern bool ft_stricterror; extern bool ft_spiniterror; extern bool ft_codemodelerror; extern bool ft_osdierror; -extern bool ft_skywaterpdk; /* parse.c */ From 643168c655edb754651f7bc303c849355b5a5cfe Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 25 Mar 2026 13:35:01 +0100 Subject: [PATCH 154/161] Prepare for ngspice-46 --- NEWS | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/NEWS b/NEWS index f0816b363..48a9045e1 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,37 @@ +Ngspice-46, March 29th, 2026 +============ +- New features: + + Updates to BSIM4. + + Enable CIDER with KLU for DC, OP, and TRAN analyses. + + Support Exxx n1 n2 nc1 nc2 TABLE = (x0, y0, x1, y1, x2, y2). + + Add analog code model astate, which reports previous states of a node. + + Improve code model pwlts by adding breakpoints. + + new functions vec() and var() for .param expressions. + + Add variable deltacheck to measure the CKTdelta[0]. + + Remove ancient IPC code. + + Update to VDMOS model. + + Equalise the last two time steps before a breakpoint. + + Update to diode model, especially for the sidewall diode. + + Enable optional voltage based truncation error correction. + + Add a function m3avg(vector) for filtering of trap ringing. + + Remove ngnutmeg from build list of old apps. + + Add filtering by moving window with function 'newvec = mtimeavg(vec)'. + + If compat mode PS, GND is not declared as global, and is not + replaced inside of a subcircuit. + + New variable measureprec to set the number of digits for 'meas' outputs. + + Improve paramerization for V PULSE source. + + Add parameter m (multiplier), while translating from G or F source + to code model spice2poly. + + Allow Cd as a valid C reference designator for a capacitor. + + Prepare for binning of N devices. + + Add parameter numPeriod to 'fourier' command. + + FM and FC exchange place in the parameter sequence of SFFM v and i source. + + Diode soft recovery model with iterated charge node. + + 'linearize' command with new parameter np=xx, xx may be a number or auto2n. + + update to the 'fft' command on scaling and frequency binning. + + Remove 'skywater' option, replace by equivalent variable 'no_auto_braces'. + + Ngspice-45.2, Sept. 5th, 2025 ============ - Bug-fix release From d93bc07c15ccb0c799fad3ad2453f57acbb1ee52 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 25 Mar 2026 13:59:09 +0100 Subject: [PATCH 155/161] Prepare for ngspice-46 --- configure.ac | 4 ++-- src/include/ngspice/sharedspice.h | 2 +- visualc/src/include/ngspice/config.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 0132c507d..a138a2763 100644 --- a/configure.ac +++ b/configure.ac @@ -16,7 +16,7 @@ # problem to the user. AC_PREREQ([2.70]) -m4_define([ngspice_major_version], [45.2+]) +m4_define([ngspice_major_version], [46]) m4_define([ngspice_minor_version], [0]) m4_define([ngspice_version], [ngspice_major_version]) @@ -117,7 +117,7 @@ LT_INIT([shared static]) # --> Set 'LT_NGSPICE_AGE' to 0. LT_NGSPICE_CURRENT=0 -LT_NGSPICE_REVISION=14 +LT_NGSPICE_REVISION=15 LT_NGSPICE_AGE=0 LIBNGSPICE_SO_VERSION=$LT_NGSPICE_CURRENT.$LT_NGSPICE_REVISION.$LT_NGSPICE_AGE diff --git a/src/include/ngspice/sharedspice.h b/src/include/ngspice/sharedspice.h index 7f209555b..5606ec4a5 100644 --- a/src/include/ngspice/sharedspice.h +++ b/src/include/ngspice/sharedspice.h @@ -124,7 +124,7 @@ are of type bool if sharedspice.h is used externally. */ #ifndef NGSPICE_PACKAGE_VERSION -#define NGSPICE_PACKAGE_VERSION "45.2+" +#define NGSPICE_PACKAGE_VERSION "46" #endif /* we have NG_BOOL instead of BOOL */ #ifndef HAS_NG_BOOL diff --git a/visualc/src/include/ngspice/config.h b/visualc/src/include/ngspice/config.h index 2fc43d11c..3865066ad 100644 --- a/visualc/src/include/ngspice/config.h +++ b/visualc/src/include/ngspice/config.h @@ -15,7 +15,7 @@ #define PACKAGE "ngspice" /* Version number of package */ -#define VERSION "45.2+" +#define VERSION "46" /* Define the directory for executables */ #define NGSPICEBINDIR "../bin" From f227a3abd6a29dd7fbe4f2b51573f731aa319abe Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Thu, 26 Mar 2026 16:15:10 +0100 Subject: [PATCH 156/161] Prevent a crash with shared ngspice when memory is exhausted: Add a pre-check if available memory is sufficient. If not, bail out. --- src/frontend/outitf.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/frontend/outitf.c b/src/frontend/outitf.c index 91cb49624..a9e47df3c 100644 --- a/src/frontend/outitf.c +++ b/src/frontend/outitf.c @@ -38,6 +38,11 @@ extern int EVTsetup_plot(CKTcircuit* ckt, char* plotname); extern IFsimulator SIMinfo; extern char Spice_Build_Date[]; +extern unsigned long long getMemorySize(void); +extern unsigned long long getPeakRSS(void); +extern unsigned long long getCurrentRSS(void); +extern unsigned long long getAvailableMemorySize(void); + static int beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analName, char *refName, int refType, int numNames, char **dataNames, int dataType, bool windowed, runDesc **runp); @@ -60,6 +65,7 @@ static bool getSpecial(dataDesc *desc, runDesc *run, IFvalue *val); static void freeRun(runDesc *run); static int InterpFileAdd(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr); static int InterpPlotAdd(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr); +static inline int vlength2delta(int len); /*Output data to spice module*/ #ifdef TCL_MODULE @@ -550,6 +556,20 @@ OUTpD_memory(runDesc *run, IFvalue *refValue, IFvalue *valuePtr) { int i, n = run->numData; + if (!cp_getvar("no_mem_check", CP_BOOL, NULL, 0)) { + /* Estimate the required memory */ + size_t memrequ = (size_t)n * vlength2delta(0) * sizeof(double); + size_t memavail = getAvailableMemorySize(); + + if (memrequ > memavail) { + fprintf(stderr, "\nError: memory required (%Id Bytes)\n" + " is more than memory available (%Id Bytes)!\n", + memrequ, memavail); + fprintf(stderr, "Setting the output memory is not possible.\n"); + controlled_exit(1); + } + } + for (i = 0; i < n; i++) { dataDesc *d; From 33b53f9df69d552da96c9e6a8942fd157e15e475 Mon Sep 17 00:00:00 2001 From: dwarning Date: Wed, 25 Mar 2026 21:31:48 +0100 Subject: [PATCH 157/161] diode: correct charge reporting for soft recovery option --- src/spicelib/devices/dio/dioask.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/spicelib/devices/dio/dioask.c b/src/spicelib/devices/dio/dioask.c index e40d5c4d0..52e0899bf 100644 --- a/src/spicelib/devices/dio/dioask.c +++ b/src/spicelib/devices/dio/dioask.c @@ -85,6 +85,8 @@ DIOask (CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value, return(OK); case DIO_CHARGE: value->rValue = *(ckt->CKTstate0+here->DIOcapCharge); + if ((here->DIOqpNode > 0) && (here->DIOtTransitTime!=0)) + value->rValue += here->DIOqpGain * *(ckt->CKTstate0 + here->DIOsrcapCharge); return(OK); case DIO_CAPCUR: value->rValue = *(ckt->CKTstate0+here->DIOcapCurrent); From ebdaf58ec76a06ffaac7e0f138360dd1cf5ee4b6 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 29 Mar 2026 14:13:38 +0200 Subject: [PATCH 158/161] Prepare for ngspice-46 --- FAQ | 15 ++++++++------- INSTALL | 22 ++++++++++++---------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/FAQ b/FAQ index bf849308a..ef26a2f68 100644 --- a/FAQ +++ b/FAQ @@ -1,7 +1,7 @@ - Ngspice F.A.Q.Version 2.9 (ngspice-45 release) + Ngspice F.A.Q.Version 2.10 (ngspice-46 release) Maintained by Holger Vogt - Last update: Aug 29 2025 + Last update: Mar 29 2026 This document contains the Frequently Asked Questions (and Answers) for ngspice project. @@ -256,7 +256,7 @@ The latest version released is: - ngspice-45 (released on August 31, 2025) + ngspice-46 (released on March 29, 2026) 2.2. What are the latest features in the current release? @@ -268,8 +268,9 @@ Ngspice, as the original Spice3 (and Xspice and Cider) is a command line simulator, but with a graphics output capability. Excellent - open source third party tool for schematic capture (KiCad, XSCHEM, - Qucs-S and others) are available. + open source third party tool for schematic capture (KiCad, XSCHEM, + Qucs-S and others) are available + (see https://ngspice.sourceforge.io/resources.html). 2.4. Who are the authors of ngspice? @@ -312,7 +313,7 @@ a GNU C/C++ compiler and a LINUX environment to compile it. Ngspice can be compiled under Windows using the mingw or cygwin environment as well as MS Visual Studio. It will readily compile on macOS, Intel CPUs or - Apple M1 - M4. Wasm, FreeBSD or Solaris will do, but are not officially + Apple Silicon. Wasm, FreeBSD or Solaris will do, but are not officially supported. @@ -357,7 +358,7 @@ 4.4. Disclaimer and Copyright - Copyright: Holger Vogt, 2025 + Copyright: Holger Vogt, 2026 License: Creative Commons Attribution Share-Alike (CC-BY-SA) v4.0. This document is provided as is. The information in it is not warranted to be correct: you use it at your own risk. diff --git a/INSTALL b/INSTALL index 224a2e57b..2cab4f65b 100644 --- a/INSTALL +++ b/INSTALL @@ -50,7 +50,7 @@ This file describes the procedures to install ngspice from sources. library and ngspice as a tcl/tk library. Compilation to 64 bit is recommended and available per default in - the ./compile_linux_new.sh compile script. 32 bit might be possible, + the ./compile_linux.sh and other compile scripts. 32 bit might be possible, but is not tested. The following software must be installed in your system to compile @@ -68,7 +68,7 @@ This file describes the procedures to install ngspice from sources. internal fft algorithms. If you want to compile the source from the git repository, or if you want to - use the compile script ./compile_linux_new.sh, you will need additional software: + 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: @@ -81,21 +81,22 @@ This file describes the procedures to install ngspice from sources. For compiling ngspice as a shared library, see section 1.4. -1.2 Install from tarball (e.g. ngspice-45.tar.gz) +1.2 Install from tarball (e.g. ngspice-46.tar.gz) This covers installation from a release distribution (for example - ngspice-45.tar.gz, the so called tar ball). + ngspice-46.tar.gz, the so called tar ball). After downloading the tar ball to a local directory, unpack it by command: - $ tar -zxvf ngspice-44.tar.gz + $ tar -zxvf ngspice-46.tar.gz Now change directories in to the top-level source directory (where this INSTALL file can be found). The most comfortable way to compile ngspice is running the compile script - compile_linux.sh within the terminal window by ./compile_linux.sh. The - script has to be declared as 'executable', and admin + compile_linux.sh within the terminal window by + sudo ./compile_linux.sh. + The script has to be declared as 'executable', and admin rights are required to allow the installation of ngspice. CentOS users may need to add -std=c99 to the CFLAGS in the ../configure @@ -568,7 +569,7 @@ This file describes the procedures to install ngspice from sources. 4 NGSPICE COMPILATION UNDER macOS M1 - M4 ======================================= - (tested on a mac mini with Sonoma 13.2.1 and M2 CPU) + (tested on a mac mini with Sequoia 15.7.4 and M2 CPU) 4.1 Prerequisites 1. Install xcode command line tools @@ -588,8 +589,9 @@ This file describes the procedures to install ngspice from sources. compile_macos_clang_M2_shared.sh -5 NGSPICE COMPILATION UNDER macOS (tested with Intel CPUs) - ======================================================== +5 NGSPICE COMPILATION UNDER macOS +(previously tested for ngspice-42 with Intel CPUs) + ================================================ 5.1 Use precompiled binary package 1. Install an X11 interface (like Xquartz) From 96404e993984065f9104d724672bcdcafd7f356f Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 30 Mar 2026 16:00:32 +0200 Subject: [PATCH 159/161] Exclude memory check for Apple Silicon Not yet working as getAvailableMemorySize delivers wrong values. --- src/frontend/outitf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/frontend/outitf.c b/src/frontend/outitf.c index a9e47df3c..56883b04d 100644 --- a/src/frontend/outitf.c +++ b/src/frontend/outitf.c @@ -556,6 +556,7 @@ OUTpD_memory(runDesc *run, IFvalue *refValue, IFvalue *valuePtr) { int i, n = run->numData; +#ifndef __APPLE__ if (!cp_getvar("no_mem_check", CP_BOOL, NULL, 0)) { /* Estimate the required memory */ size_t memrequ = (size_t)n * vlength2delta(0) * sizeof(double); @@ -569,6 +570,7 @@ OUTpD_memory(runDesc *run, IFvalue *refValue, IFvalue *valuePtr) controlled_exit(1); } } +#endif for (i = 0; i < n; i++) { From 4feeb94b12a2529f14f9bd7847f7253d704990af Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 30 Mar 2026 16:03:19 +0200 Subject: [PATCH 160/161] Improve error message, make fprintf independent from OS --- src/frontend/outitf.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/frontend/outitf.c b/src/frontend/outitf.c index 56883b04d..586813947 100644 --- a/src/frontend/outitf.c +++ b/src/frontend/outitf.c @@ -556,16 +556,19 @@ OUTpD_memory(runDesc *run, IFvalue *refValue, IFvalue *valuePtr) { int i, n = run->numData; + #ifndef __APPLE__ if (!cp_getvar("no_mem_check", CP_BOOL, NULL, 0)) { /* Estimate the required memory */ - size_t memrequ = (size_t)n * vlength2delta(0) * sizeof(double); + int timesteps = vlength2delta(0); + size_t memrequ = (size_t)n * timesteps * sizeof(double); size_t memavail = getAvailableMemorySize(); if (memrequ > memavail) { - fprintf(stderr, "\nError: memory required (%Id Bytes)\n" - " is more than memory available (%Id Bytes)!\n", - memrequ, memavail); + fprintf(stderr, "\nError: memory required (%zu Bytes), made of\n" + " %d nodes and approximately %d time steps,\n" + " is more than the memory available (%zu Bytes)!\n", + memrequ, n, timesteps, memavail); fprintf(stderr, "Setting the output memory is not possible.\n"); controlled_exit(1); } From 499c1d3dcaa3b36064647ef9841b69cb24ab9863 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 30 Mar 2026 16:08:41 +0200 Subject: [PATCH 161/161] We develop towards ngspice-47 --- configure.ac | 2 +- src/include/ngspice/sharedspice.h | 2 +- visualc/src/include/ngspice/config.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index a138a2763..2c4f15457 100644 --- a/configure.ac +++ b/configure.ac @@ -16,7 +16,7 @@ # problem to the user. AC_PREREQ([2.70]) -m4_define([ngspice_major_version], [46]) +m4_define([ngspice_major_version], [46+]) m4_define([ngspice_minor_version], [0]) m4_define([ngspice_version], [ngspice_major_version]) diff --git a/src/include/ngspice/sharedspice.h b/src/include/ngspice/sharedspice.h index 5606ec4a5..f453877ff 100644 --- a/src/include/ngspice/sharedspice.h +++ b/src/include/ngspice/sharedspice.h @@ -124,7 +124,7 @@ are of type bool if sharedspice.h is used externally. */ #ifndef NGSPICE_PACKAGE_VERSION -#define NGSPICE_PACKAGE_VERSION "46" +#define NGSPICE_PACKAGE_VERSION "46+" #endif /* we have NG_BOOL instead of BOOL */ #ifndef HAS_NG_BOOL diff --git a/visualc/src/include/ngspice/config.h b/visualc/src/include/ngspice/config.h index 3865066ad..c378057e0 100644 --- a/visualc/src/include/ngspice/config.h +++ b/visualc/src/include/ngspice/config.h @@ -15,7 +15,7 @@ #define PACKAGE "ngspice" /* Version number of package */ -#define VERSION "46" +#define VERSION "46+" /* Define the directory for executables */ #define NGSPICEBINDIR "../bin"