From ee62f4feb3b08f9b3b614817ee0b29f79fabc6eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81rp=C3=A1d=20B=C5=B1rmen?= Date: Fri, 25 Apr 2025 16:15:15 +0200 Subject: [PATCH 01/38] dtemp bug fixed. --- src/spicelib/devices/jfet2/jfet2par.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spicelib/devices/jfet2/jfet2par.c b/src/spicelib/devices/jfet2/jfet2par.c index 44c6b9fc3..9747c90d3 100644 --- a/src/spicelib/devices/jfet2/jfet2par.c +++ b/src/spicelib/devices/jfet2/jfet2par.c @@ -31,8 +31,8 @@ JFET2param(int param, IFvalue *value, GENinstance *inst, IFvalue *select) here->JFET2tempGiven = TRUE; break; case JFET2_DTEMP: - here->JFET2temp = value->rValue; - here->JFET2tempGiven = TRUE; + here->JFET2dtemp = value->rValue; + here->JFET2dtempGiven = TRUE; break; case JFET2_AREA: here->JFET2area = value->rValue; From 7a6a25846598c17d53f79d3548759f85e884500a Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 23 May 2025 14:23:48 +0200 Subject: [PATCH 02/38] Revert "Improve error messages when reading (and discarding) binned models," This reverts commit 33f18b485ad59f515ba94b73fafebbaba84f4def. --- src/frontend/subckt.c | 68 +++++++++++++---------------------- src/spicelib/parser/inpgmod.c | 3 +- 2 files changed, 25 insertions(+), 46 deletions(-) diff --git a/src/frontend/subckt.c b/src/frontend/subckt.c index d7ec7ce7c..4cb7be417 100644 --- a/src/frontend/subckt.c +++ b/src/frontend/subckt.c @@ -583,18 +583,11 @@ doit(struct card *deck, wordlist *modnames) { scale = 1; error = 0; - /* Second pass: do the replacements. - Check if binning is used for .model inside of the subcircuit. - Reduce .model lines to the one with appropriate w and l. - (Inspired by Skywater PDK with excessive use of binning (161 bins) - in the subcircuit referencing a MOS device) */ + /* Second pass: do the replacements. */ do { /* while (!error && numpasses-- && gotone) */ struct card *c = deck; struct card *prev_of_c = NULL; - bool foundmodel = FALSE; - gotone = FALSE; - for (; c; prev_of_c = c, c = c->nextcard) { if (ciprefix(invoke, c->line)) { /* found reference to .subckt (i.e. component with refdes X) */ @@ -604,13 +597,16 @@ doit(struct card *deck, wordlist *modnames) { gotone = TRUE; t = tofree = s = copy(c->line); /* s & t hold copy of component line */ - /* scname contains the refdes Xname */ + /* make scname point to first non-whitepace chars after refdes invocation + * e.g. if invocation is Xreference, *scname = reference + */ tofree2 = scname = gettok(&s); + /*scname += strlen(invoke); */ while ((*scname == ' ') || (*scname == '\t') || (*scname == ':')) scname++; - /* Now set s to point to last non-space chars in the x line (i.e. - * the name of the model invoked) + /* Now set s to point to last non-space chars in line (i.e. + * the name of the model invoked */ while (*s) s++; @@ -621,47 +617,38 @@ doit(struct card *deck, wordlist *modnames) { s--; s++; - /* Iterate through .subckt list and look for .subckt name - corresponding to the subckt name extracted from the x line */ + /* iterate through .subckt list and look for .subckt name invoked */ for (sss = subs; sss; sss = sss->su_next) if (eq(sss->su_name, s)) break; - /* At this point, - * c is the card with the x line. - * scname points to the netname of the x line involved. - * s is the subckt name extracted from the x line. - * sss points to the subcircuit referenced by the x line - * sss->su_def is the contents of the subcircuit. + + /* At this point, sss points to the .subckt invoked, + * and scname points to the netnames + * involved. */ + /* If no .subckt is found, don't complain -- this might be an * instance of a subckt that is defined above at higher level. */ if (sss) { // tprint(sss->su_def); - - /* copy of the contents between .subckt and .ends */ struct card *su_deck = inp_deckcopy(sss->su_def); /* If we have modern PDKs, we have to reduce the amount of memory required. We try to reduce the models to the one really used. - Otherwise su_deck is full of unused binning models. - c->w > 0 and c->l > 0 point to an x line with given w and l - (typically a call to a MOS device). */ + Otherwise su_deck is full of unused binning models.*/ if ((newcompat.hs || newcompat.spe) && c->w > 0 && c->l > 0) { /* extract wmin, wmax, lmin, lmax */ - struct card* enter_su_deck = su_deck; + struct card* new_deck = su_deck; struct card* prev = NULL; while (su_deck) { - /* find a .model line */ if (!ciprefix(".model", su_deck->line)) { prev = su_deck; su_deck = su_deck->nextcard; continue; } - /* check if line contains wmin, wmax, lmin, lmax - if available, extract its values, - if not, go to next line */ + char* curr_line = su_deck->line; float fwmin, fwmax, flmin, flmax; char *wmin = strstr(curr_line, " wmin="); @@ -729,39 +716,32 @@ doit(struct card *deck, wordlist *modnames) { su_deck = su_deck->nextcard; continue; } - /* check if x line's w and l are withing the limites of wmin, wmax, lmin, lmax */ + float csl = (float)scale * c->l; /* scale by nf */ float csw = (float)scale * c->w / c->nf; /*fprintf(stdout, "Debug: nf = %f\n", c->nf);*/ if (csl >= flmin && csl < flmax && csw >= fwmin && csw < fwmax) { - /* if within the limits, use the current .model card */ + /* use the current .model card */ prev = su_deck; su_deck = su_deck->nextcard; - foundmodel = TRUE; continue; } else { - /* if not within the limits, - delete the .model line not fitting the device */ struct card* tmpcard = su_deck->nextcard; line_free_x(prev->nextcard, FALSE); su_deck = prev->nextcard = tmpcard; } } - /* go back to the first card of su_deck */ - su_deck = enter_su_deck; + su_deck = new_deck; } - if (!foundmodel && (newcompat.hs || newcompat.spe) && c->w > 0 && c->l > 0) { - fprintf(stderr, "\nError: Could not find a model\n" - " for device %s in transistor subcircuit %s\n", scname, sss->su_name); - fprintf(stderr, " with w = %.3g and l = %.3g\n\n", c->w, c->l); + if (!su_deck) { + fprintf(stderr, "\nError: Could not find a model for device %s in subcircuit %s\n", + scname, sss->su_name); controlled_exit(1); } - foundmodel = FALSE; - struct card *rest_of_c = c->nextcard; /* Now we have to replace this line with the @@ -802,8 +782,8 @@ doit(struct card *deck, wordlist *modnames) { tfree(tofree); tfree(tofree2); - } /* if (ciprefix(invoke, c->line)) */ - } /* for (; c; prev_of_c = c, c = c->nextcard) */ + } + } } while (!error && numpasses-- && gotone); diff --git a/src/spicelib/parser/inpgmod.c b/src/spicelib/parser/inpgmod.c index ac7e88b09..64c402d7e 100644 --- a/src/spicelib/parser/inpgmod.c +++ b/src/spicelib/parser/inpgmod.c @@ -292,7 +292,6 @@ INPgetModBin(CKTcircuit *ckt, char *name, INPmodel **model, INPtables *tab, char for (modtmp = modtab; modtmp; modtmp = modtmp->INPnextModel) { - /* exact: 1, with binning extension .[0-9]: 2*/ if (model_name_match(name, modtmp->INPmodName) < 2) continue; @@ -335,8 +334,8 @@ INPgetModBin(CKTcircuit *ckt, char *name, INPmodel **model, INPtables *tab, char *model = modtmp; return NULL; } - fprintf(stderr, "Warning: no model found for w=%.3e and l=%.3e\n", w, l); } + return NULL; } From b05d9eb1507adcc8ac1533d0ddd6e52a89cda17d Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 27 May 2025 21:13:09 +0200 Subject: [PATCH 03/38] Prevent crash if file cannot be opened. --- src/frontend/inpcom.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 95304bc78..6fbc418fd 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -1138,12 +1138,12 @@ struct card *inp_readall(FILE *fp, const char *dir_name, const char* file_name, inp_fix_agauss_in_param(working, statfcn[ii]); inp_fix_temper_in_param(working); - +// tprint(working); inp_expand_macros_in_deck(NULL, working); inp_fix_param_values(working); inp_reorder_params(subckt_w_params, cc); -// tprint(working); + /* Special handling for large PDKs: We need to know W and L of transistor subcircuits by checking their x invocation */ inp_get_w_l_x(working); @@ -1179,6 +1179,7 @@ struct card *inp_readall(FILE *fp, const char *dir_name, const char* file_name, inp_repair_dc_ps(working); } bool expr_w_temper = FALSE; + if (!newcompat.s3) { /* Do all the compatibility stuff here */ working = cc->nextcard; @@ -7698,6 +7699,10 @@ void tprint(struct card *t) npr++; /*debug: print into file*/ FILE *fd = fopen(outfile, "w"); + if (!fd) { + fprintf(stderr, "Warning: cannot open debug output file tprint-outxx.txt\n"); + return; + } for (tmp = t; tmp; tmp = tmp->nextcard) if (*(tmp->line) != '*') fprintf(fd, "%6d %6d %s\n", tmp->linenum_orig, tmp->linenum, From b09778d47945a9400f458530fcf8acb390a26642 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 27 May 2025 21:13:26 +0200 Subject: [PATCH 04/38] Make all new entries lower case. --- src/frontend/inpc_probe.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/frontend/inpc_probe.c b/src/frontend/inpc_probe.c index f71a72e63..99c4bcc5d 100644 --- a/src/frontend/inpc_probe.c +++ b/src/frontend/inpc_probe.c @@ -332,7 +332,7 @@ void inp_probe(struct card* deck) /* special for KiCad: add shunt resistor if thisnode contains 'unconnected' */ if (*instname == 'x' && strstr(thisnode, "unconnected")) { /* nn makes the resistor name unique for a device with multiple unconnected nodes */ - char *rline = tprintf("R%s%d %s 0 1e15", thisnode, nn++, thisnode); + char *rline = tprintf("r%s%d %s 0 1e15", thisnode, nn++, thisnode); card = insert_new_line(card, rline, 0, card->linenum_orig, card->linesource); } char* nodesaves = tprintf("%s:%s#branch", instname, nodename); @@ -398,7 +398,7 @@ void inp_probe(struct card* deck) if (!strnode2) { } else { - newline = tprintf("Ediff%d_nodes vd_%s:%s 0 %s %s 1", ee, strnode1, strnode2, strnode1, strnode2); + newline = tprintf("ediff%d_nodes vd_%s:%s 0 %s %s 1", ee, strnode1, strnode2, strnode1, strnode2); char* nodesaves = tprintf("vd_%s:%s", strnode1, strnode2); allsaves = wl_cons(nodesaves, allsaves); @@ -434,7 +434,7 @@ void inp_probe(struct card* deck) tfree(strnode2); continue; } - newline = tprintf("Ediff%d_%s vd_%s 0 %s %s 1", ee, instname1, instname1, strnode1, strnode2); + newline = tprintf("ediff%d_%s vd_%s 0 %s %s 1", ee, instname1, instname1, strnode1, strnode2); char* nodesaves = tprintf("vd_%s", instname1); allsaves = wl_cons(nodesaves, allsaves); @@ -590,7 +590,7 @@ void inp_probe(struct card* deck) } nodename2 = get_terminal_name(instname2, node2, instances); } - char *newline = tprintf("Ediff%d_%s_%s vd_%s:%s_%s:%s 0 %s %s 1", ee, instname1, instname2, instname1, nodename1, instname2, nodename2, strnode1, strnode2); + char *newline = tprintf("ediff%d_%s_%s vd_%s:%s_%s:%s 0 %s %s 1", ee, instname1, instname2, instname1, nodename1, instname2, nodename2, strnode1, strnode2); char* nodesaves = tprintf("vd_%s:%s_%s:%s", instname1, nodename1, instname2, nodename2); allsaves = wl_cons(nodesaves, allsaves); tmpcard1 = insert_new_line(tmpcard1, newline, 0, tmpcard1->linenum_orig, tmpcard1->linesource); @@ -712,7 +712,7 @@ void inp_probe(struct card* deck) } nodename2 = get_terminal_name(instname1, node2, instances); } - char* newline = tprintf("Ediff%d_%s vd_%s:%s:%s 0 %s %s 1", ee, instname1, instname1, nodename1, nodename2, strnode1, strnode2); + char* newline = tprintf("ediff%d_%s vd_%s:%s:%s 0 %s %s 1", ee, instname1, instname1, nodename1, nodename2, strnode1, strnode2); char* nodesaves = tprintf("vd_%s:%s:%s", instname1, nodename1, nodename2); allsaves = wl_cons(nodesaves, allsaves); tmpcard1 = insert_new_line(tmpcard1, newline, 0, tmpcard1->linenum_orig, tmpcard1->linesource); @@ -1335,22 +1335,22 @@ static int setallvsources(struct card *tmpcard, NGHASHPTR instances, char *instn DS_CREATE(Bpowersave, 200); if (power) { - /* For example: Bq1Vref q1Vref 0 V = 1/3*( */ + /* For example: bq1vref q1vref 0 v = 1/3*( */ char numbuf[3]; - sadd(&BVrefline, "Bprobe_int_"); + sadd(&BVrefline, "bprobe_int_"); sadd(&BVrefline, instname); - sadd(&BVrefline, "Vref "); + sadd(&BVrefline, "vref "); sadd(&BVrefline, instname); - sadd(&BVrefline, "probe_int_Vref 0 V = 1/"); + sadd(&BVrefline, "probe_int_vref 0 v = 1/"); sadd(&BVrefline, itoa10(numnodes, numbuf)); sadd(&BVrefline, "*("); - /* For example: Bq1power q1:power 0 V = */ - sadd(&Bpowerline, "Bprobe_int_"); + /* For example: bq1power q1:power 0 v = */ + sadd(&Bpowerline, "bprobe_int_"); sadd(&Bpowerline, instname); sadd(&Bpowerline, "power "); sadd(&Bpowerline, instname); cadd(&Bpowerline, ':'); - sadd(&Bpowerline, "power 0 V = 0+"); /*FIXME 0+ required to suppress adding {} and numparam failure*/ + sadd(&Bpowerline, "power 0 v = 0+"); /*FIXME 0+ required to suppress adding {} and numparam failure*/ /* For example: q1:power */ sadd(&Bpowersave, instname); cadd(&Bpowersave, ':'); @@ -1414,20 +1414,20 @@ static int setallvsources(struct card *tmpcard, NGHASHPTR instances, char *instn if (power) { /* For example V(1)+V(2)+V(3)*/ if (nodenum == 1) - sadd(&BVrefline, "V("); + sadd(&BVrefline, "v("); else - sadd(&BVrefline, "+V("); + sadd(&BVrefline, "+v("); sadd(&BVrefline, newnode); cadd(&BVrefline, ')'); /*For example: (V(node1)-V(q1probe_int_Vref))*node1#branch+(V(node2)-V(q1Vref))*node2#branch */ if (nodenum == 1) - sadd(&Bpowerline, "(V("); + sadd(&Bpowerline, "(v("); else - sadd(&Bpowerline, "+(V("); + sadd(&Bpowerline, "+(v("); sadd(&Bpowerline, newnode); - sadd(&Bpowerline, ")-V("); + sadd(&Bpowerline, ")-v("); sadd(&Bpowerline, instname); - sadd(&Bpowerline, "probe_int_Vref))*i(vcurr_"); + sadd(&Bpowerline, "probe_int_vref))*i(vcurr_"); sadd(&Bpowerline, instname); sadd(&Bpowerline, ":probe_int_"); sadd(&Bpowerline, nodename1); From 8d76a9a56afac224105668a85764bbddaf48c36e Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Sat, 3 May 2025 08:55:29 +0100 Subject: [PATCH 05/38] Improve efficiency of linked list search. (See BUG 783). --- src/spicelib/analysis/cktdltn.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/spicelib/analysis/cktdltn.c b/src/spicelib/analysis/cktdltn.c index 7be581fb6..8e7c5e257 100644 --- a/src/spicelib/analysis/cktdltn.c +++ b/src/spicelib/analysis/cktdltn.c @@ -20,7 +20,7 @@ CKTdltNod(CKTcircuit* ckt, CKTnode* node) int CKTdltNNum(CKTcircuit* ckt, int num) { - CKTnode* n, * prev, * node, * sprev; + CKTnode* n, * prev, * node; int error; if (!ckt->prev_CKTlastNode->number || num <= ckt->prev_CKTlastNode->number) { @@ -30,12 +30,11 @@ CKTdltNNum(CKTcircuit* ckt, int num) prev = NULL; node = NULL; - sprev = NULL; for (n = ckt->CKTnodes; n; n = n->next) { if (n->number == num) { node = n; - sprev = prev; + break; } prev = n; } @@ -45,14 +44,14 @@ CKTdltNNum(CKTcircuit* ckt, int num) ckt->CKTmaxEqNum -= 1; - if (!sprev) { + if (!prev) { ckt->CKTnodes = node->next; } else { - sprev->next = node->next; + prev->next = node->next; } if (node == ckt->CKTlastNode) - ckt->CKTlastNode = sprev; + ckt->CKTlastNode = prev; error = SPfrontEnd->IFdelUid(ckt, node->name, UID_SIGNAL); tfree(node); From a385a8654bfd2a05691b6ed4119ceee3ad1a6a0d Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Wed, 28 May 2025 11:28:21 +0100 Subject: [PATCH 06/38] Fix Bug #792 - "N device instance line not parsed correct". Code added by 83d3890490 failed with a single parameter with no speces. --- src/spicelib/parser/inp2n.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/spicelib/parser/inp2n.c b/src/spicelib/parser/inp2n.c index 526455024..ef6c9a742 100644 --- a/src/spicelib/parser/inp2n.c +++ b/src/spicelib/parser/inp2n.c @@ -34,7 +34,7 @@ void INP2N(CKTcircuit *ckt, INPtables *tab, struct card *current) { GENmodel *mdfast; /* Pointer to the actual model. */ IFdevice *dev; CKTnode *node; - char *c, *token = NULL, *prev = NULL, *pprev = NULL; + char *c, *token = NULL, *prev = NULL, *pprev = NULL, *eqp; int i; line = current->line; @@ -44,15 +44,16 @@ void INP2N(CKTcircuit *ckt, INPtables *tab, struct card *current) { /* Find the last non-parameter token in the line. */ c = line; - for (i = 0; *c != '\0'; ++i) { + for (i = 0, eqp = NULL; *c != '\0'; ++i) { tfree(pprev); pprev = prev; prev = token; token = gettok_instance(&c); - if (strchr(token, '=')) + eqp = strchr(token, '='); + if (eqp) break; } - if (*c) { + if (eqp) { tfree(token); // A parameter or starts with '='. if (*c == '=') { /* Now prev points to a parameter pprev is the model. */ From 1d8724b85572f1b8764fb97a8b839654c365196e Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 31 May 2025 12:03:09 +0200 Subject: [PATCH 07/38] Linux line endings --- src/misc/misc_time.c | 318 +++++++++++++++++++++---------------------- 1 file changed, 159 insertions(+), 159 deletions(-) diff --git a/src/misc/misc_time.c b/src/misc/misc_time.c index 945de732f..cc986f432 100644 --- a/src/misc/misc_time.c +++ b/src/misc/misc_time.c @@ -1,159 +1,159 @@ -/********** -Copyright 1990 Regents of the University of California. All rights reserved. -**********/ - -/* - * Date and time utility functions - */ - -#include "ngspice/ngspice.h" -#include - -#if defined(HAS_WINGUI) || defined(__MINGW32__) || defined(_MSC_VER) -#define WIN32_LEAN_AND_MEAN - -#include -#ifndef HAVE_GETTIMEOFDAY -#include -#include // portable: uint64_t MSVC: __int64 - -/*/ MSVC defines this in winsock2.h!? -typedef struct timeval { - long tv_sec; - long tv_usec; -} timeval; -*/ -int gettimeofday(struct timeval * tp, void * unused) -{ - NG_IGNORE(unused); - // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's - // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC) - // until 00:00:00 January 1, 1970 - static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL); - - SYSTEMTIME system_time; - FILETIME file_time; - uint64_t time; - - GetSystemTime( &system_time ); - SystemTimeToFileTime( &system_time, &file_time ); - time = ((uint64_t)file_time.dwLowDateTime ) ; - time += ((uint64_t)file_time.dwHighDateTime) << 32; - - tp->tv_sec = (long) ((time - EPOCH) / 10000000L); - tp->tv_usec = (long) (system_time.wMilliseconds * 1000); - return 0; -} -#endif -#endif - -#include "misc_time.h" - -#ifdef USE_OMP -#include -#endif - -/* Return the date. Return value is static data. */ - -char * -datestring(void) -{ - -#ifdef HAVE_LOCALTIME - static char tbuf[45]; - struct tm *tp; - char *ap; - size_t i; - - time_t tloc; - time(&tloc); - tp = localtime(&tloc); - ap = asctime(tp); - (void) sprintf(tbuf, "%.20s", ap); - (void) strcat(tbuf, ap + 19); - i = strlen(tbuf); - tbuf[i - 1] = '\0'; - return (tbuf); - -#else - - return ("today"); - -#endif -} - -/* return time interval in seconds and milliseconds */ - -PerfTime timebegin; - -void timediff(PerfTime *now, PerfTime *begin, int *sec, int *msec) -{ - - *msec = (int) now->milliseconds - (int) begin->milliseconds; - *sec = (int) now->seconds - (int) begin->seconds; - if (*msec < 0) { - *msec += 1000; - (*sec)--; - } - return; - -} - -/* - * How many seconds have elapsed in running time. - * This is the routine called in IFseconds - */ - -double -seconds(void) -{ -#ifdef USE_OMP - // Usage of OpenMP time function - return(omp_get_wtime() - timebegin.secs); -#elif defined(HAVE_QUERYPERFORMANCECOUNTER) - // Windows (MSC and mingw) specific implementation - LARGE_INTEGER frequency, counter; - QueryPerformanceFrequency(&frequency); - QueryPerformanceCounter(&counter); - return ((double)counter.QuadPart / frequency.QuadPart - timebegin.secs); -#elif defined(HAVE_CLOCK_GETTIME) - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (ts.tv_sec + ts.tv_nsec / 1e9 - timebegin.secs); -#elif defined(HAVE_GETTIMEOFDAY) - // Usage of gettimeofday - struct timeval tv; - gettimeofday(&tv, NULL); - return (tv.tv_sec + tv.tv_usec / 1e6 - timebegin.secs); -#elif defined(HAVE_FTIME) - // Usage of ftime - struct timeb tb; - PerfTime timenow; - int sec, msec; - ftime(&tb); - timenow.seconds = tb.time; - timenow.milliseconds = tb.millitm; - timediff(&timenow, &timebegin, &sec, &msec); - return(sec + (double) msec / 1000.0); -#elif defined(HAVE_TIMES) - // Usage of times - struct tms tmsbuf; - clock_t ticks = times(&tmsbuf); - return((double) tmsbuf.tms_utime / HZ); -#elif defined(HAVE_GETRUSAGE) - // Usage of getrusage - struct rusage ruse; - getrusage(RUSAGE_SELF, &ruse); - return ((double)ruse.ru_utime.tv_sec + (double) ruse.ru_utime.tv_usec / 1000000.0); -#else - #error "No timer function available." -#endif -} - -void perf_timer_get_time(PerfTime *time) -{ - time->secs = seconds(); - time->seconds = (int)time->secs; - time->milliseconds = (int)((time->secs - time->seconds) * 1000.0); - -} +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +/* + * Date and time utility functions + */ + +#include "ngspice/ngspice.h" +#include + +#if defined(HAS_WINGUI) || defined(__MINGW32__) || defined(_MSC_VER) +#define WIN32_LEAN_AND_MEAN + +#include +#ifndef HAVE_GETTIMEOFDAY +#include +#include // portable: uint64_t MSVC: __int64 + +/*/ MSVC defines this in winsock2.h!? +typedef struct timeval { + long tv_sec; + long tv_usec; +} timeval; +*/ +int gettimeofday(struct timeval * tp, void * unused) +{ + NG_IGNORE(unused); + // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's + // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC) + // until 00:00:00 January 1, 1970 + static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL); + + SYSTEMTIME system_time; + FILETIME file_time; + uint64_t time; + + GetSystemTime( &system_time ); + SystemTimeToFileTime( &system_time, &file_time ); + time = ((uint64_t)file_time.dwLowDateTime ) ; + time += ((uint64_t)file_time.dwHighDateTime) << 32; + + tp->tv_sec = (long) ((time - EPOCH) / 10000000L); + tp->tv_usec = (long) (system_time.wMilliseconds * 1000); + return 0; +} +#endif +#endif + +#include "misc_time.h" + +#ifdef USE_OMP +#include +#endif + +/* Return the date. Return value is static data. */ + +char * +datestring(void) +{ + +#ifdef HAVE_LOCALTIME + static char tbuf[45]; + struct tm *tp; + char *ap; + size_t i; + + time_t tloc; + time(&tloc); + tp = localtime(&tloc); + ap = asctime(tp); + (void) sprintf(tbuf, "%.20s", ap); + (void) strcat(tbuf, ap + 19); + i = strlen(tbuf); + tbuf[i - 1] = '\0'; + return (tbuf); + +#else + + return ("today"); + +#endif +} + +/* return time interval in seconds and milliseconds */ + +PerfTime timebegin; + +void timediff(PerfTime *now, PerfTime *begin, int *sec, int *msec) +{ + + *msec = (int) now->milliseconds - (int) begin->milliseconds; + *sec = (int) now->seconds - (int) begin->seconds; + if (*msec < 0) { + *msec += 1000; + (*sec)--; + } + return; + +} + +/* + * How many seconds have elapsed in running time. + * This is the routine called in IFseconds + */ + +double +seconds(void) +{ +#ifdef USE_OMP + // Usage of OpenMP time function + return(omp_get_wtime() - timebegin.secs); +#elif defined(HAVE_QUERYPERFORMANCECOUNTER) + // Windows (MSC and mingw) specific implementation + LARGE_INTEGER frequency, counter; + QueryPerformanceFrequency(&frequency); + QueryPerformanceCounter(&counter); + return ((double)counter.QuadPart / frequency.QuadPart - timebegin.secs); +#elif defined(HAVE_CLOCK_GETTIME) + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (ts.tv_sec + ts.tv_nsec / 1e9 - timebegin.secs); +#elif defined(HAVE_GETTIMEOFDAY) + // Usage of gettimeofday + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec + tv.tv_usec / 1e6 - timebegin.secs); +#elif defined(HAVE_FTIME) + // Usage of ftime + struct timeb tb; + PerfTime timenow; + int sec, msec; + ftime(&tb); + timenow.seconds = tb.time; + timenow.milliseconds = tb.millitm; + timediff(&timenow, &timebegin, &sec, &msec); + return(sec + (double) msec / 1000.0); +#elif defined(HAVE_TIMES) + // Usage of times + struct tms tmsbuf; + clock_t ticks = times(&tmsbuf); + return((double) tmsbuf.tms_utime / HZ); +#elif defined(HAVE_GETRUSAGE) + // Usage of getrusage + struct rusage ruse; + getrusage(RUSAGE_SELF, &ruse); + return ((double)ruse.ru_utime.tv_sec + (double) ruse.ru_utime.tv_usec / 1000000.0); +#else + #error "No timer function available." +#endif +} + +void perf_timer_get_time(PerfTime *time) +{ + time->secs = seconds(); + time->seconds = (int)time->secs; + time->milliseconds = (int)((time->secs - time->seconds) * 1000.0); + +} From 29c3189a681f77a51ff52d64c43fc5fe90314e7c Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 2 Jun 2025 11:59:18 +0200 Subject: [PATCH 08/38] Enable expressions in a meas statement within a .control section, like meas tran yeval2 FIND v(2) WHEN v(1)= 0.9*v(2) --- examples/measure/meas_expression.cir | 13 ++++++ src/frontend/com_measure2.c | 2 +- src/frontend/inpcom.c | 68 ++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/examples/measure/meas_expression.cir b/examples/measure/meas_expression.cir index 4954477c4..a3a77176c 100644 --- a/examples/measure/meas_expression.cir +++ b/examples/measure/meas_expression.cir @@ -14,6 +14,19 @@ run ** evaluate '0.9*v(2)' in control language command let vint = 0.9*v(2) meas tran yeval2 FIND v(2) WHEN v(1)= vint +unlet vint + +* new expression evaluation +meas tran yeval3 FIND v(2) WHEN v(1)= 0.9*v(2) + +* standard meas with val being a number: +meas tran tdiff1 TRIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=3 + +* expression evaluation with vector of length 1 only: +let onevec = 1 +meas tran tdiff2 TRIG v(1) VAL=onevec-0.5 RISE=1 TARG v(1) VAL=onevec/2 RISE=3 + + plot V(1) v(2) .endc diff --git a/src/frontend/com_measure2.c b/src/frontend/com_measure2.c index 9f314215b..1e7483501 100644 --- a/src/frontend/com_measure2.c +++ b/src/frontend/com_measure2.c @@ -64,7 +64,7 @@ is_arith_char2(char c) return c != '\0' && strchr("*/<>?:|&^!%\\", c); } -static bool +bool str_has_arith_char2(char* s) { if (*s == '+' || *s == '-') diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 6fbc418fd..c3debe462 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -147,6 +147,7 @@ static void inp_compat(struct card *deck); static void inp_bsource_compat(struct card *deck); static bool inp_temper_compat(struct card *card); static void inp_meas_current(struct card *card); +static void inp_meas_control(struct card *card); static void inp_dot_if(struct card *deck); static char *inp_modify_exp(char *expression); static struct func_temper *inp_new_func(char *funcname, char *funcbody, @@ -1191,6 +1192,8 @@ struct card *inp_readall(FILE *fp, const char *dir_name, const char* file_name, inp_bsource_compat(working); inp_dot_if(working); expr_w_temper = inp_temper_compat(working); + /* check for expressions in meas command */ + inp_meas_control(working); } if (expr_w_temper_p) *expr_w_temper_p = expr_w_temper; @@ -9750,6 +9753,71 @@ int add_to_sourcepath(const char* filepath, const char* path) return 0; } +/* if there is an expression in FIND ... WHEN etc in a .control section, + use a vector with this expression: + meas tran yeval2 FIND v(2) WHEN v(1)= 0.9*v(2) + will become + let vexprint1 = 0.9*v(2) + meas tran yeval2 FIND v(2) WHEN v(1)=vexprint1 + unlet vint +*/ +static void inp_meas_control(struct card* card) +{ + int is_control = 0; + static int replaceno = 1; + struct card* prevcard; + + for (; card; prevcard = card, card = card->nextcard) { + + char* equal_ptr = NULL; + char* curr_line = card->line; + char* newcurrline = card->line; + int currlinenumber = card->linenum_orig; + + /* only commands inside .control ... .endc */ + if (ciprefix(".control", curr_line)) { + is_control++; + continue; + } + else if (ciprefix(".endc", curr_line)) { + is_control--; + continue; + } + else if (is_control < 1) { + continue; + } + curr_line = skip_ws(curr_line); + if (ciprefix("meas", curr_line) && (equal_ptr = find_assignment(curr_line)) != NULL) { + curr_line = equal_ptr + 1; + while (*curr_line != '\0' && equal_ptr) { + char* token = gettok(&curr_line); + if (str_has_arith_char(token)) { + char* newtok = tprintf("=vexprint%d", replaceno++); + char* begstr = copy_substring(newcurrline, equal_ptr); + char* endstr = copy(curr_line); + char* newline = tprintf("%s%s %s", begstr, newtok, endstr); + char* letline = tprintf("let %s=%s", newtok + 1, token); + char* unletline = tprintf("unlet %s", newtok + 1); + tfree(newtok); + tfree(begstr); + tfree(endstr); + prevcard = insert_new_line(prevcard, letline, 0, currlinenumber, card->linesource); + card = prevcard->nextcard; + tfree(card->line); + card->line = newline; + newcurrline = curr_line = card->line; + card = insert_new_line(card, unletline, 0, currlinenumber, card->linesource); + } + tfree(token); + /* next equal sign in line */ + equal_ptr = find_assignment(curr_line); + if (equal_ptr) + curr_line = equal_ptr + 1; + } + } + } +} + #if defined(_WIN32) From 30ab455b64c3caab8e836b15bafe5615db9496b8 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 6 Jun 2025 11:56:57 +0200 Subject: [PATCH 09/38] Enable real (from fft)or complex (from sp) frequency vetors in plot sp --- src/frontend/com_measure2.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/frontend/com_measure2.c b/src/frontend/com_measure2.c index 1e7483501..7fa30d352 100644 --- a/src/frontend/com_measure2.c +++ b/src/frontend/com_measure2.c @@ -717,7 +717,10 @@ measure_at( value = get_value(meas, d, i); //d->v_compdata[i].cx_real; else value = d->v_realdata[i]; - svalue = dScale->v_realdata[i]; + if (dScale->v_compdata) // .sp, s-param. + svalue = dScale->v_compdata[i].cx_real; + else // fft + svalue = dScale->v_realdata[i]; } else { value = d->v_realdata[i]; svalue = dScale->v_realdata[i]; From 4fcb74779e538cda95e05a8b55f5db0f674a822c Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Wed, 4 Jun 2025 09:47:38 +0100 Subject: [PATCH 10/38] Fix Bug #793 - "breakp.c error: compling without XSPICE failed". Additional changes to conditional compilation are needed for iplot without XSPICE. --- src/frontend/breakp.c | 4 ++++ src/frontend/plotting/graf.c | 21 +++++++++++++-------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/frontend/breakp.c b/src/frontend/breakp.c index ec50fd068..5dae629bc 100644 --- a/src/frontend/breakp.c +++ b/src/frontend/breakp.c @@ -293,7 +293,11 @@ com_iplot(wordlist *wl) d = TMALLOC(struct dbcomm, 1); d->db_analysis = NULL; d->db_number = debugnumber++; +#ifdef XSPICE d->db_iteration = event_auto_incr ? DB_AUTO_OFFSET : DB_NORMAL; +#else + d->db_iteration = DB_NORMAL; +#endif d->db_op = initial_steps; // Field re-use d->db_value1 = window; // Field re-use diff --git a/src/frontend/plotting/graf.c b/src/frontend/plotting/graf.c index 3fbfcb237..2e29e07fa 100644 --- a/src/frontend/plotting/graf.c +++ b/src/frontend/plotting/graf.c @@ -1329,10 +1329,10 @@ void gr_iplot(struct plot *plot) hit = 0; for (db = dbs; db; db = db->db_next) { if (db->db_type == DB_IPLOT || db->db_type == DB_IPLOTALL) { -#ifdef XSPICE if (db->db_iteration > 0) { - double event_node_offset = 0, event_node_spacing; struct dvec *v; +#ifdef XSPICE + double event_node_offset = 0, event_node_spacing; /* First call: set up event nodes spacing. */ @@ -1348,7 +1348,7 @@ void gr_iplot(struct plot *plot) } else { event_node_spacing = 0; } - +#endif /* Find any XSPICE event nodes in the node * list and set up plotting. There is a parallel path * for pushing new event values into their corresponding @@ -1356,9 +1356,11 @@ void gr_iplot(struct plot *plot) */ for (dc = db; dc; dc = dc->db_also) { - struct dbcomm *dd; - char *offp, save_sign; - int dup = 0; + struct dbcomm *dd; + int dup = 0; +#ifdef XSPICE + char *offp, save_sign; +#endif if (dc->db_nodename1 == NULL) continue; @@ -1374,6 +1376,7 @@ void gr_iplot(struct plot *plot) if (dup) continue; +#ifdef XSPICE /* Check for a nodename that is an expression. */ offp = strchr(dc->db_nodename1, '+'); @@ -1383,7 +1386,7 @@ void gr_iplot(struct plot *plot) save_sign = *offp; *offp = '\0'; // Trim to bare name. } - +#endif v = vec_fromplot(dc->db_nodename1, plot); if (v) { dc->db_nodename2 = (char *)v; // Save link to vector. @@ -1393,6 +1396,7 @@ void gr_iplot(struct plot *plot) dc->db_nodename1, plot->pl_name); } +#ifdef XSPICE if (v && (v->v_flags & VF_EVENT_NODE)) { /* Ask event simulator to call back with new values. */ @@ -1443,10 +1447,11 @@ void gr_iplot(struct plot *plot) "Offset (%s) ignored for analog node %s\n", offp, dc->db_nodename1); } +#endif } db->db_iteration = 0; } -#endif + if (db->db_graphid) { GRAPH *gr; From b57ef4a42d38703fe0f0da65944335db72e55200 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Fri, 6 Jun 2025 12:01:36 +0100 Subject: [PATCH 11/38] Snapshot support for new statistics added by e1677a18c4. That prevents a crash exiting examples/snapshot/adder_snload.script. --- src/frontend/spiceif.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/frontend/spiceif.c b/src/frontend/spiceif.c index d4976fe16..2615a5978 100644 --- a/src/frontend/spiceif.c +++ b/src/frontend/spiceif.c @@ -55,6 +55,7 @@ CDHW*/ #include "ngspice/iferrmsg.h" #include "ngspice/ifsim.h" #include "ngspice/hash.h" +#include "ngspice/devdefs.h" #include "circuits.h" #include "spiceif.h" @@ -1621,6 +1622,10 @@ void com_snload(wordlist *wl) _foo(ckt->CKTstat, STATistics, 1); ckt->CKTstat->STATdevNum = NULL; _foo(ckt->CKTstat->STATdevNum, STATdevList, -1); + ckt->CKTstat->devCounts = NULL; + _foo(ckt->CKTstat->devCounts, size_t, DEVmaxnum + 1); + ckt->CKTstat->devTimes = NULL; + _foo(ckt->CKTstat->devTimes, double, DEVmaxnum + 1); #ifdef XSPICE _foo(ckt->evt, Evt_Ckt_Data_t, 1); @@ -1776,6 +1781,8 @@ void com_snsave(wordlist *wl) /* Finally the stats */ _foo(ckt->CKTstat, STATistics, 1); _foo(ckt->CKTstat->STATdevNum, STATdevList, 1); + _foo(ckt->CKTstat->devCounts, size_t, DEVmaxnum + 1); + _foo(ckt->CKTstat->devTimes, double, DEVmaxnum + 1); #ifdef XSPICE /* FIXME struct ckt->evt->data and others are not stored From b7d434550ae1f498b968b2dd553ce8b94af85924 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 4 Jun 2025 12:31:13 +0200 Subject: [PATCH 12/38] Add function cm_get_neg_node_name as cm_get_node_name delivers only the pos node. --- src/include/ngspice/cmproto.h | 1 + src/include/ngspice/dllitf.h | 1 + src/xspice/cm/cm.c | 28 ++++++++++++++++++++++++++++ src/xspice/cm/cmexport.c | 1 + src/xspice/icm/dlmain.c | 4 ++++ 5 files changed, 35 insertions(+) diff --git a/src/include/ngspice/cmproto.h b/src/include/ngspice/cmproto.h index 17518160c..d137264c5 100644 --- a/src/include/ngspice/cmproto.h +++ b/src/include/ngspice/cmproto.h @@ -99,6 +99,7 @@ double cm_netlist_get_l(void); void cm_irreversible(unsigned int); const char *cm_get_node_name(const char *, unsigned int); +const char *cm_get_neg_node_name(const char *, unsigned int); bool cm_probe_node(unsigned int, unsigned int, void *); bool cm_schedule_output(unsigned int, unsigned int, double, void *); diff --git a/src/include/ngspice/dllitf.h b/src/include/ngspice/dllitf.h index eaeef3d77..dd79ee4fc 100644 --- a/src/include/ngspice/dllitf.h +++ b/src/include/ngspice/dllitf.h @@ -61,6 +61,7 @@ struct coreInfo_t { double ((*dllitf_cm_netlist_get_l)(void)); void ((*dllitf_cm_irreversible)(unsigned int)); const char * ((*dllitf_cm_get_node_name)(const char *, unsigned int)); + const char* ((*dllitf_cm_get_neg_node_name)(const char*, unsigned int)); bool ((*dllitf_cm_probe_node)(unsigned int, unsigned int, void *)); bool ((*dllitf_cm_schedule_output)(unsigned int, unsigned int, diff --git a/src/xspice/cm/cm.c b/src/xspice/cm/cm.c index bf3c56180..ce4fdcdc7 100644 --- a/src/xspice/cm/cm.c +++ b/src/xspice/cm/cm.c @@ -40,6 +40,7 @@ INTERFACES cm_irreversible() cm_get_node_name() + cm_get_neg_node_name() cm_probe_node() REFERENCED FILES @@ -852,6 +853,33 @@ const char *cm_get_node_name(const char *port_name, unsigned int index) return NULL; } +/* Get the neg name of a circuit node connected to a port. */ + +const char* cm_get_neg_node_name(const char* port_name, unsigned int index) +{ + MIFinstance* instance; + Mif_Conn_Data_t* conn; + Mif_Port_Data_t* port; + int i; + + instance = g_mif_info.instance; + for (i = 0; i < instance->num_conn; ++i) { + conn = instance->conn[i]; + if (!strcmp(port_name, conn->name)) { + if (index >= (unsigned int)conn->size) + return NULL; + port = conn->port[index]; + if (port->type == MIF_DIGITAL || port->type == MIF_USER_DEFINED) { + /* Event node, no name in port data. */ + return NULL; + } + return port->neg_node_str; + } + } + return NULL; +} + + /* Test the resolved value of a connected Digital/UDN node, given * an assumed value for a particular port. */ diff --git a/src/xspice/cm/cmexport.c b/src/xspice/cm/cmexport.c index eb7846363..56cb974eb 100644 --- a/src/xspice/cm/cmexport.c +++ b/src/xspice/cm/cmexport.c @@ -60,6 +60,7 @@ struct coreInfo_t coreInfo = cm_netlist_get_l, cm_irreversible, cm_get_node_name, + cm_get_neg_node_name, cm_probe_node, cm_schedule_output, cp_getvar, diff --git a/src/xspice/icm/dlmain.c b/src/xspice/icm/dlmain.c index 8c005cf56..dae5c7993 100644 --- a/src/xspice/icm/dlmain.c +++ b/src/xspice/icm/dlmain.c @@ -350,6 +350,10 @@ const char *cm_get_node_name(const char *port, unsigned int index) { return coreitf->dllitf_cm_get_node_name(port, index); } +const char *cm_get_neg_node_name(const char *port, unsigned int index) { + return coreitf->dllitf_cm_get_neg_node_name(port, index); +} + bool cm_probe_node(unsigned int conn_index, unsigned int port_index, void *value) { From 8d2e11b2185f4c3e606fccb8b62a9c5a16377e4d Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 6 Jun 2025 15:11:35 +0200 Subject: [PATCH 13/38] Add a generator for SEE (single event effects) pulses as a code model. To be used like aseegen1 NULL [%id(xcell.n1 m1) %id(xcell.n2 m2) %id(xcell.n1 m1) %id(xcell.n2 m2)] seemod1 .model seemod1 seegen (tdelay = 11n tperiod=25n tfall='tfall' trise='trise' let='let' cdepth='d') see README.SEEgenerator for details --- README.SEEgenerator | 173 +++++++++++++ examples/xspice/see/CMOSOpAmp/CMOS-OP1.cir | 33 +++ examples/xspice/see/CMOSOpAmp/cmos_sub.mod | 13 + examples/xspice/see/CMOSOpAmp/modelcard.nmos | 46 ++++ examples/xspice/see/CMOSOpAmp/modelcard.pmos | 38 +++ examples/xspice/see/CMOSOpAmp/seegen4.mod | 10 + examples/xspice/see/ihp_inverter_set.net | 45 ++++ .../xspice/see/ihp_simple_sram_seegen.net | 61 +++++ .../see/ihp_simple_sram_seegen_ctrl.net | 60 +++++ .../see/ihp_simple_sram_seegen_subckt.net | 69 ++++++ .../ihp_simple_sram_seegen_subckt_vary.net | 81 ++++++ examples/xspice/see/ihp_simple_sram_set.net | 64 +++++ examples/xspice/see/ihp_two_inverters_set.net | 48 ++++ examples/xspice/see/repeat_loop_seegen.net | 41 ++++ examples/xspice/see/seegen_cm1.cir | 22 ++ examples/xspice/see/set1.cir | 23 ++ src/xspice/icm/xtradev/modpath.lst | 1 + src/xspice/icm/xtradev/seegenerator/cfunc.mod | 231 ++++++++++++++++++ .../icm/xtradev/seegenerator/ifspec.ifs | 120 +++++++++ visualc/xspice/xtradev.vcxproj | 6 + 20 files changed, 1185 insertions(+) create mode 100644 README.SEEgenerator create mode 100644 examples/xspice/see/CMOSOpAmp/CMOS-OP1.cir create mode 100644 examples/xspice/see/CMOSOpAmp/cmos_sub.mod create mode 100644 examples/xspice/see/CMOSOpAmp/modelcard.nmos create mode 100644 examples/xspice/see/CMOSOpAmp/modelcard.pmos create mode 100644 examples/xspice/see/CMOSOpAmp/seegen4.mod create mode 100644 examples/xspice/see/ihp_inverter_set.net create mode 100644 examples/xspice/see/ihp_simple_sram_seegen.net create mode 100644 examples/xspice/see/ihp_simple_sram_seegen_ctrl.net create mode 100644 examples/xspice/see/ihp_simple_sram_seegen_subckt.net create mode 100644 examples/xspice/see/ihp_simple_sram_seegen_subckt_vary.net create mode 100644 examples/xspice/see/ihp_simple_sram_set.net create mode 100644 examples/xspice/see/ihp_two_inverters_set.net create mode 100644 examples/xspice/see/repeat_loop_seegen.net create mode 100644 examples/xspice/see/seegen_cm1.cir create mode 100644 examples/xspice/see/set1.cir create mode 100644 src/xspice/icm/xtradev/seegenerator/cfunc.mod create mode 100644 src/xspice/icm/xtradev/seegenerator/ifspec.ifs diff --git a/README.SEEgenerator b/README.SEEgenerator new file mode 100644 index 000000000..12c8d3858 --- /dev/null +++ b/README.SEEgenerator @@ -0,0 +1,173 @@ +SEE (single event effects) generator + +The SEE generator generates current pulses, which resemble the +charge generation and flow causes by a penetrating particle. + +How to use it: +Select LET and charge collection depth cdepth, define them as parameters. +Identify all nodes of a circuit netlist which are pn junctions, +and thus are sensitive to pulses. + +Set up the SEEgenerator by adding for example + +* charge collection depth (in µm) +.param d = 1 +* LET (linear energy transfer) in MeV*cm²/mg +.param let = 12 +aseegen1 NULL [%id(xcell.n1 m1) %id(xcell.n2 m2) %id(xcell.n1 m1) %id(xcell.n2 m2)] seemod1 +.model seemod1 seegen (tdelay = 11n tperiod=25n let='let' cdepth='d') + +to the netlist. + +Each sensitive node from the (flattend) netlist may be added to assegen1, together with its +reference node, for example GND for NMOS, nwell potential for PMOS. This procedure is +currently to be done manually, an automated setup is in preparation. + +After a transient simulation, plotting the data output versus a non-radiated device +may reveal the SEE influence. + +Several examples are gieven in ./src/axamples/xspice/see: inverters, SRAM cell, opamp, +also as loop with varying LET to detect the threshold. + +As literature please see for example + Ygor Quadros de Aguiar, Frédéric Wrobel. Jean-Luc Autran, Rubén García Alía + Single-Event Effects, from Space to Accelerator Environments + Springer 2025 + +Detailed description (will be added to the manual): + +NAME_TABLE: + +C_Function_Name: cm_seegen +Spice_Model_Name: seegen +Description: "single event effect generator" + + +PORT_TABLE: + +Port_Name: ctrl out +Description: "control input" "output" +Direction: in out +Default_Type: v i +Allowed_Types: [v,vd,i,id] [i,id] +Vector: no yes +Vector_Bounds: - [1 -] +Null_Allowed: yes no + + +PARAMETER_TABLE: + +Parameter_Name: tfall trise +Description: "pulse fall time" "pulse rise time" +Data_Type: real real +Default_Value: 500e-12 20e-12 +Limits: - - +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + + +PARAMETER_TABLE: + +Parameter_Name: tdelay inull +Description: "pulse delay" "max current" +Data_Type: real real +Default_Value: 0 0 +Limits: - - +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + + +PARAMETER_TABLE: + +Parameter_Name: tperiod ctrlthres +Description: "pulse repetition" "control voltage threshold" +Data_Type: real real +Default_Value: 0 0.5 +Limits: - - +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + + +PARAMETER_TABLE: + +Parameter_Name: let cdepth +Description: "lin energy transfer" "charge collection depth" +Data_Type: real real +Default_Value: 10 1 +Limits: - - +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + + +PARAMETER_TABLE: + +Parameter_Name: angle perlim +Description: "particle angle" "pulse repetition" +Data_Type: real boolean +Default_Value: 0 TRUE +Limits: [0 1.57079] - +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + +STATIC_VAR_TABLE: + +Static_Var_Name: last_t_value +Data_Type: pointer +Vector: no +Description: "next pulse start time" + +STATIC_VAR_TABLE: + +Static_Var_Name: pulse_number +Data_Type: pointer +Vector: no +Description: "number of pulse" + +STATIC_VAR_TABLE: + +Static_Var_Name: last_ctrl +Data_Type: pointer +Vector: no +Description: "last control value" + +Description +This code model generates "double exponentially" formed current pulses according to + +i(t) = inull * (exp(-(t-tdelay)/tfall) - (exp(-(t-tdelay)/trise) for t > tdelay +i(t) = 0 for t < tdelay + +with inull given as parameter input or (if not given), calculated as +inull = 1.035e-14 * let/cos(angle) * cdepth / (tfall - trise) +with data for silicon, cdepth in µm, let in MeV*cm²/mg, angle in radians. + +Minimum is one pulse output (a node pair, or a single node with the other grounded). +Several output node pairs may be defined per code model instance. Parameter tperiod +may then be used to create pulses in sequence. Per default only one sequence is running, +with one pulse for each node. +Parameter perlim, set to FALSE, allows running and repeating the sequence until +the end of the simulation. The first pulse is issued in the first +node pair of the node list in the vector [], the second (after time tperiod has elapsed), +is injected by the second node (pair) of the list and so on. When the sequence is repeated, +again the output starts pulsing at port (node pair) number 1. + +The control input ctrl (voltage or current) may be used +to start or repeat the whole sequence, depending on the circuit status. A rising voltage +at ctrl, when crossing the threshold given by ctrlthres, will initiate the sequence (including +tdelay and tperiod). + +This model will work in transient analysis. + +Example ngspice usage (with control) + +aseegen1 ctrl [%id(n1 m1) %id(n2 m2) %id(n1 m1) %id(n2 m2)] seemod1 +.model seemod1 seegen (tdelay = 8n tperiod=25n) + +Example ngspice usage (without control, ctrl replaced by NULL, parameters as offered by default) + +aseegen2 NULL [%id(n1 m1) %id(n5 n6) %id(n6 n7) %i(isingle) ] seemod2 +.model seemod2 seegen (tdelay = 0 tperiod=0 ctrlthres=0.5 inull=0 tfall=500p trise=20p perlim=FALSE) diff --git a/examples/xspice/see/CMOSOpAmp/CMOS-OP1.cir b/examples/xspice/see/CMOSOpAmp/CMOS-OP1.cir new file mode 100644 index 000000000..2e2b2e480 --- /dev/null +++ b/examples/xspice/see/CMOSOpAmp/CMOS-OP1.cir @@ -0,0 +1,33 @@ +.title KiCad schematic +.include "cmos_sub.mod" +.include "seegen4.mod" +V1 Vcc 0 DC 3.3 +XU1 VGP2 VGP4P8 Vbias VSN4N8 seegen4 +XMN9 Vbias Vbias 0 0 NCH W=5u L=1.4u +V5 in+ 0 DC 1.65 +R1 out in- 100k +R2 in in- 20k +V4 in 0 DC 1.65 SIN( 1.65 100m 1k 0 0 0 ) AC 1 +XMN3 out Vbias 0 0 NCH W=17.4u L=1.4u +C2 out 0 2p +XMP2 out VGP2 Vcc Vcc PCH W=14.5u L=1.4u +C1 VGP2 out 1.2p +XMP4 VGP4P8 VGP4P8 Vcc Vcc PCH W=2.8u L=1.4u +I1 Vcc Vbias 12u +XMN4 VGP4P8 in- VSN4N8 0 NCH W=2.8u L=1.4u +XMN8 VGP2 in+ VSN4N8 0 NCH W=2.8u L=1.4u +XMN2 VSN4N8 Vbias 0 0 NCH W=5u L=1.4u +XMP8 VGP2 VGP4P8 Vcc Vcc PCH W=2.8u L=1.4u + +.control +set xbrushwidth=2 + +tran 20n 2m +plot v(VGP4P8) +plot in out + +ac dec 10 1 1Meg +plot db(out) +.endc + +.end diff --git a/examples/xspice/see/CMOSOpAmp/cmos_sub.mod b/examples/xspice/see/CMOSOpAmp/cmos_sub.mod new file mode 100644 index 000000000..c72096db9 --- /dev/null +++ b/examples/xspice/see/CMOSOpAmp/cmos_sub.mod @@ -0,0 +1,13 @@ +* subcircuit model file + +.include modelcard.nmos +.include modelcard.pmos + +.subckt NCH D G S B W=1 L=1 +MN1 D G S B N1 W={W} L={L} AS={3*L*W} AD={3*L*W} PS={6*L+W} AS={6*L+W} +.ends + + +.subckt PCH D G S B W=1 L=1 +MP1 D G S B P1 W={W} L={L} AS={3*L*W} AD={3*L*W} PS={6*L+W} AS={6*L+W} +.ends diff --git a/examples/xspice/see/CMOSOpAmp/modelcard.nmos b/examples/xspice/see/CMOSOpAmp/modelcard.nmos new file mode 100644 index 000000000..06885ff57 --- /dev/null +++ b/examples/xspice/see/CMOSOpAmp/modelcard.nmos @@ -0,0 +1,46 @@ +*model = bsim3v3 +*Berkeley Spice Compatibility +*http://bsim.berkeley.edu/BSIM4/BSIM3/ftpv330.zip +* Lmin= .35 Lmax= 20 Wmin= .6 Wmax= 20 +.model N1 NMOS ++Level= 8 ++version=3.3.0 ++Tnom=27.0 ++Acnqsmod=1 elm=3 ++Capmod=3 ++Nch= 2.498E+17 Tox=9E-09 Xj=1.00000E-07 ++Lint=9.36e-8 Wint=1.47e-7 ++Lintnoi=1e-9 ++Vth0= .6322 K1= .756 K2= -3.83e-2 K3= -2.612 ++Dvt0= 2.812 Dvt1= 0.462 Dvt2=-9.17e-2 ++Nlx= 3.52291E-08 W0= 1.163e-6 ++K3b= 2.233 ++Vsat= 86301.58 Ua= 6.47e-9 Ub= 4.23e-18 Uc=-4.706281E-11 ++Rdsw= 650 U0= 388.3203 wr=1 ++A0= .3496967 Ags=.1 B0=0.546 B1= 1 ++Dwg = -6.0E-09 Dwb = -3.56E-09 Prwb = -.213 ++Keta=-3.605872E-02 A1= 2.778747E-02 A2= .9 ++Voff=-6.735529E-02 NFactor= 1.139926 Cit= 1.622527E-04 ++Cdsc=-2.147181E-05 ++Cdscb= 0 Dvt0w = 0 Dvt1w = 0 Dvt2w = 0 ++Cdscd = 0 Prwg = 0 ++Eta0= 1.0281729E-02 Etab=-5.042203E-03 ++Dsub= .31871233 ++Pclm= 1.114846 Pdiblc1= 2.45357E-03 Pdiblc2= 6.406289E-03 ++Drout= .31871233 Pscbe1= 5000000 Pscbe2= 5E-09 Pdiblcb = -.234 ++Pvag= 0 delta=0.01 ++ Wl = 0 Ww = -1.420242E-09 Wwl = 0 ++ Wln = 0 Wwn = .2613948 Ll = 1.300902E-10 ++ Lw = 0 Lwl = 0 Lln = .316394 ++ Lwn = 0 ++kt1=-.3 kt2=-.051 ++At= 22400 ++Ute=-1.48 ++Ua1= 3.31E-10 Ub1= 2.61E-19 Uc1= -3.42e-10 ++Kt1l=0 Kt1=-0.1 Prt=764.3 + + + + + + diff --git a/examples/xspice/see/CMOSOpAmp/modelcard.pmos b/examples/xspice/see/CMOSOpAmp/modelcard.pmos new file mode 100644 index 000000000..ab86a38ee --- /dev/null +++ b/examples/xspice/see/CMOSOpAmp/modelcard.pmos @@ -0,0 +1,38 @@ +*model = bsim3v3 +*Berkeley Spice Compatibility +*http://bsim.berkeley.edu/BSIM4/BSIM3/ftpv330.zip +* Lmin= .35 Lmax= 20 Wmin= .6 Wmax= 20 +.model P1 PMOS ++Level= 8 ++version=3.3.0 ++Tnom=27.0 ++Acnqsmod=1 elm=3 ++Nch= 3.533024E+17 Tox=9E-09 Xj=1.00000E-07 ++Lint=6.23e-8 Wint=1.22e-7 ++Lintnoi=1e-9 ++Vth0=-.6732829 K1= .8362093 K2=-8.606622E-02 K3= 1.82 ++Dvt0= 1.903801 Dvt1= .5333922 Dvt2=-.1862677 ++Nlx= 1.28e-8 W0= 2.1e-6 ++K3b= -0.24 Prwg=-0.001 Prwb=-0.323 ++Vsat= 103503.2 Ua= 1.39995E-09 Ub= 1.e-19 Uc=-2.73e-11 ++ Rdsw= 460 U0= 138.7609 ++A0= .4716551 Ags=0.12 ++Keta=-1.871516E-03 A1= .3417965 A2= 0.83 ++Voff=-.074182 NFactor= 1.54389 Cit=-1.015667E-03 ++Cdsc= 8.937517E-04 ++Cdscb= 1.45e-4 Cdscd=1.04e-4 ++ Dvt0w=0.232 Dvt1w=4.5e6 Dvt2w=-0.0023 ++Eta0= 6.024776E-02 Etab=-4.64593E-03 ++Dsub= .23222404 ++Pclm= .989 Pdiblc1= 2.07418E-02 Pdiblc2= 1.33813E-3 ++Drout= .3222404 Pscbe1= 118000 Pscbe2= 1E-09 ++Pvag= 0 ++kt1= -0.25 kt2= -0.032 prt=64.5 ++At= 33000 ++Ute= -1.5 ++Ua1= 4.312e-9 Ub1= 6.65e-19 Uc1= 0 ++Kt1l=0 + + + + diff --git a/examples/xspice/see/CMOSOpAmp/seegen4.mod b/examples/xspice/see/CMOSOpAmp/seegen4.mod new file mode 100644 index 000000000..c29d787fe --- /dev/null +++ b/examples/xspice/see/CMOSOpAmp/seegen4.mod @@ -0,0 +1,10 @@ +* SEE generator model +.subckt seegen4 n1 n2 n3 n4 +.param tochar = 2e-13 +.param tfall = 500p trise=50p +.param Inull = 'tochar/(tfall-trise)' +* Eponential current source without control input +* only NMOS nodes with reference GND (substrate). +aseegen1 NULL [%i(n1) %i(n2) %i(n3) %i(n4)] seemod1 +.model seemod1 seegen (tdelay = 0.62m tperiod=0.1m inull='Inull' perlim=FALSE) +.ends \ No newline at end of file diff --git a/examples/xspice/see/ihp_inverter_set.net b/examples/xspice/see/ihp_inverter_set.net new file mode 100644 index 000000000..c5793da8b --- /dev/null +++ b/examples/xspice/see/ihp_inverter_set.net @@ -0,0 +1,45 @@ +* IHP Open PDK +* simple inverter + +* Path to the PDK +*.include "D:\Spice_general\skywater-pdk\libraries\sky130_fd_pr\latest\models\corners/tt.spice" +.lib "D:\Spice_general\IHP-Open-PDK\ihp-sg13g2\libs.tech\ngspice\models\cornerMOSlv.lib" mos_tt +*.include lib_out1.lib + +.param vdd = 1.2 +.param deltat=11n + +* the voltage sources: +Vdd vd gnd DC 'vdd' +V1 in gnd pulse(0 'vdd' 0p 200p 100p 5n 10n) + +* Eponential current source +Iset out 0 EXP(0 2.5m 'deltat' 10p 'deltat' 500p) +*Cset out 0 10f + +Xnot1 in vdd vss out not1 +Vmeasvss vss 0 0 +Vmeasvdd vd vdd 0 + +.subckt not1 a vdd vss z +xm01 z a vdd vdd sg13_lv_pmos l=0.15u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u +xm02 z a vss vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u +c3 a vss 0.384f +c2 z vss 0.576f +.ends + +* simulation command: +.tran 100ps 50ns ; 0 10p + +.options method=gear + +.control +run +rusage +*set nolegend +set xbrushwidth=3 +plot i(Vmeasvss) i(Vmeasvdd) +plot in out +.endc + +.end diff --git a/examples/xspice/see/ihp_simple_sram_seegen.net b/examples/xspice/see/ihp_simple_sram_seegen.net new file mode 100644 index 000000000..26d7e5a33 --- /dev/null +++ b/examples/xspice/see/ihp_simple_sram_seegen.net @@ -0,0 +1,61 @@ +* IHP Open PDK +* simple SRAM cell, exponential current pulses + +* Path to the PDK +*.include "D:\Spice_general\skywater-pdk\libraries\sky130_fd_pr\latest\models\corners/tt.spice" +.lib "D:\Spice_general\IHP-Open-PDK\ihp-sg13g2\libs.tech\ngspice\models\cornerMOSlv.lib" mos_tt +*.include lib_out1.lib + +.param vdd = 1.2 +.param deltat=11n deltat2=27n +.param tochar = 1e-13 +.param talpha = 500p tbeta=10p +.param Inull = 'tochar/(talpha-tbeta)' + +* the voltage sources: +Vdd vd gnd DC 'vdd' +Vwl wl 0 0 PULSE 0 'vdd' 45n 1n 1n 7n 1 +Vbl bl 0 'vdd' +Vbln bln 0 0 + +*V1 in gnd pulse(0 'vdd' 0p 200p 100p 5n 10n) + +* Eponential current source without control input +aseegen1 NULL [%id(n1 m1) %id(n2 m2) %id(n1 m1) %id(n2 m2)] seemod1 +.model seemod1 seegen (tdelay = 11n tperiod=25n inull='Inull') + +Xnot1 n1 vdd vss n2 not1 +Xnot2 n2 vdd vss n1 not1 +xmo02 n2 wl bl vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u +xmo01 n1 wl bln vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u + +Vmeasvss vss 0 0 +Vmeasvdd vd vdd 0 +Vm1 m1 0 0 +Vm2 m2 0 0 + +.subckt not1 a vdd vss z +xm01 z a vdd vdd sg13_lv_pmos l=0.15u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u +xm02 z a vss vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u +c3 a vss 0.384f +c2 z vss 0.576f +.ends + +* starting condition for SRAM cell +.ic v(n2)=0 v(n1)='vdd' + +* simulation command: +.tran 100ps 100ns ; 0 10p + +.options method=gear + +.control +run +rusage +*set nolegend +set xbrushwidth=3 +plot i(Vmeasvss) i(Vmeasvdd) +plot n1 n2+2 wl+4 i(vm1)*10000+6 i(vm2)*10000+8 +.endc + +.end diff --git a/examples/xspice/see/ihp_simple_sram_seegen_ctrl.net b/examples/xspice/see/ihp_simple_sram_seegen_ctrl.net new file mode 100644 index 000000000..ce13a7dca --- /dev/null +++ b/examples/xspice/see/ihp_simple_sram_seegen_ctrl.net @@ -0,0 +1,60 @@ +* Simple SRAM cell in a subcircuit, double exponential current pulses +* control volate +* IHP Open PDK + +* Path to the PDK +.lib "D:\Spice_general\IHP-Open-PDK\ihp-sg13g2\libs.tech\ngspice\models\cornerMOSlv.lib" mos_tt + +.param vdd = 1.2 +.param deltat=11n deltat2=25n +.param tochar = 1e-13 +.param talpha = 500p tbeta=20p +.param Inull = 'tochar/(talpha-tbeta)' + +* the voltage sources: +Vdd vd gnd DC 'vdd' +Vwl wl 0 0 PULSE 0 'vdd' 50n 1n 1n 7n 1 +Vbl bl 0 'vdd' +Vbln bln 0 0 +Vctrl ctrl 0 pulse (0 1 10n 1n 1n 1 1) + +* Exponential current source with control input +aseegen1 ctrl [%id(n1 m1) %id(n2 m2) %id(n1 m1) %id(n2 m2)] seemod1 +.model seemod1 seegen (tdelay = 8n tperiod=25n) + +Xnot1 n1 vdd vss n2 not1 +Xnot2 n2 vdd vss n1 not1 +xmo02 n2 wl bl vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u +xmo01 n1 wl bln vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u + +Vmeasvss vss 0 0 +Vmeasvdd vd vdd 0 +Vm1 m1 0 0 +Vm2 m2 0 0 + +.subckt not1 a vdd vss z +xm01 z a vdd vdd sg13_lv_pmos l=0.15u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u +xm02 z a vss vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u +c3 a vss 0.384f +c2 z vss 0.576f +.ends + +* starting condition for SRAM cell +.ic v(n2)=0 v(n1)='vdd' + +* simulation command: +.tran 100ps 120ns + +.options method=gear + +.control +pre_osdi C:\Spice64\lib\ngspice\psp103_nqs.osdi +run +rusage +*set nolegend +set xbrushwidth=3 +plot i(Vmeasvss) i(Vmeasvdd) +plot n1 n2+2 wl+4 i(vm1)*10000+6 i(vm2)*10000+8 +.endc + +.end diff --git a/examples/xspice/see/ihp_simple_sram_seegen_subckt.net b/examples/xspice/see/ihp_simple_sram_seegen_subckt.net new file mode 100644 index 000000000..7b689f852 --- /dev/null +++ b/examples/xspice/see/ihp_simple_sram_seegen_subckt.net @@ -0,0 +1,69 @@ +* Simple SRAM cell in a subcircuit, double exponential current pulses +* IHP Open PDK + +* Path to the PDK +.lib "D:\Spice_general\IHP-Open-PDK\ihp-sg13g2\libs.tech\ngspice\models\cornerMOSlv.lib" mos_tt + +.param vdd = 1.2 +.param deltat=11n deltat2=27n +*.param tochar = 1e-13 ; tochar dependency on LET not yet defined +.param tfall = 500p trise=20p ; tau in exponent for pulse +.param let = 11 +.param cdepth = 0.9 +*.param Inull = 'tochar/(tfall-trise)' + +* the voltage sources: +Vdd vd gnd DC 'vdd' +Vwl wl 0 0 PULSE 0 'vdd' 45n 1n 1n 7n 1 +Vbl1 bl1 0 'vdd' +Vbl2 bl2 0 0 + +**** SEE generator without control input, double exponential current sources +aseegen1 NULL [%id(xcell.n1 m1) %id(xcell.n2 m2) %id(xcell.n1 m1) %id(xcell.n2 m2)] seemod1 +.model seemod1 seegen (tdelay = 11n tperiod=25n let='let' cdepth='cdepth' tfall='tfall' trise='trise') +* alternative syntax, if no current measurement required and reference nodes are GND +*aseegen1 NULL [%i(xcell.n1) %i(xcell.n2) %i(xcell.n1) %i(xcell.n2)] seemod1 + +**** the SRAM cell +Xcell bl1 bl2 wl vdd vss srcell + +.subckt srcell bl1 bl2 wl vdd vss +Xnot1 n1 vdd vss n2 not1 +Xnot2 n2 vdd vss n1 not1 +xmo02 n2 wl bl1 vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u +xmo01 n1 wl bl2 vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u +.ends + +**** Current measurements +Vmeasvss vss 0 0 +Vmeasvdd vd vdd 0 +Vm1 m1 0 0 +Vm2 m2 0 0 + +**** Inverter cell +.subckt not1 a vdd vss z +xm01 z a vdd vdd sg13_lv_pmos l=0.15u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u +xm02 z a vss vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u +c3 a vss 0.384f +c2 z vss 0.576f +.ends + +* starting condition for SRAM cell +.ic v(xcell.n2)=0 v(xcell.n1)='vdd' + +* simulation command: +.tran 100ps 120ns + +*.options method=gear + +.control +pre_osdi C:\Spice64\lib\ngspice\psp103_nqs.osdi +run +rusage +*set nolegend +set xbrushwidth=3 +plot i(Vmeasvss) i(Vmeasvdd) +plot xcell.n1 xcell.n2+2 wl+4 i(vm1)*10000+6 i(vm2)*10000+8 +.endc + +.end diff --git a/examples/xspice/see/ihp_simple_sram_seegen_subckt_vary.net b/examples/xspice/see/ihp_simple_sram_seegen_subckt_vary.net new file mode 100644 index 000000000..5bd6c80da --- /dev/null +++ b/examples/xspice/see/ihp_simple_sram_seegen_subckt_vary.net @@ -0,0 +1,81 @@ +* Simple SRAM cell in a subcircuit, double exponential current pulses +* total charge is varied. +* IHP Open PDK + +* Path to the PDK +.lib "D:\Spice_general\IHP-Open-PDK\ihp-sg13g2\libs.tech\ngspice\models\cornerMOSlv.lib" mos_tt + +.param vdd = 1.2 +*.param tochar = 1e-13 ; tochar dependency on LET not yet defined + +.param d = 1 +.param let = 12 + +.param tochar = 1.035e-14 * let * d +.csparam let = 'let' ; send param value to .control section +.param tfall = 500p trise = 100p ; tau in exponent for pulse +.param Inull = 'tochar/(tfall-trise)' + +* the voltage sources: +Vdd vd gnd DC 'vdd' +Vwl wl 0 0 PULSE 0 'vdd' 45n 1n 1n 7n 1 +Vbl1 bl1 0 'vdd' +Vbl2 bl2 0 0 + +**** SEE generator without control input, double exponential current sources +aseegen1 NULL [%id(xcell.n1 m1) %id(xcell.n2 m2) %id(xcell.n1 m1) %id(xcell.n2 m2)] seemod1 +.model seemod1 seegen (tdelay = 11n tperiod=25n tfall='tfall' trise='trise' let='let' cdepth='d') +* alternative syntax, if no current measurement required and reference nodes are GND +*aseegen1 NULL [%i(xcell.n1) %i(xcell.n2) %i(xcell.n1) %i(xcell.n2)] seemod1 + +**** the SRAM cell +Xcell bl1 bl2 wl vdd vss srcell + +.subckt srcell bl1 bl2 wl vdd vss +Xnot1 n1 vdd vss n2 not1 +Xnot2 n2 vdd vss n1 not1 +xmo02 n2 wl bl1 vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u +xmo01 n1 wl bl2 vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u +.ends + +**** Current measurements +Vmeasvss vss 0 0 +Vmeasvdd vd vdd 0 +Vm1 m1 0 0 +Vm2 m2 0 0 + +**** Inverter cell +.subckt not1 a vdd vss z +xm01 z a vdd vdd sg13_lv_pmos l=0.15u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u +xm02 z a vss vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u +c3 a vss 0.384f +c2 z vss 0.576f +.ends + +* starting condition for SRAM cell +.ic v(xcell.n2)=0 v(xcell.n1)='vdd' + +* simulation command: +.tran 100ps 120ns + +*.options method=gear + +.options noinit + +.control +pre_osdi C:\Spice64\lib\ngspice\psp103_nqs.osdi +set xbrushwidth=3 +let newlet = let + +repeat 5 + print newlet + run + plot xcell.n1 xcell.n2+2 wl+4 i(vm1)*10000+6 i(vm2)*10000+8 ylimit -1 10 + let newlet = newlet - 1 + alterparam let = $&newlet + reset +end +rusage +.endc + +.end diff --git a/examples/xspice/see/ihp_simple_sram_set.net b/examples/xspice/see/ihp_simple_sram_set.net new file mode 100644 index 000000000..394a8554e --- /dev/null +++ b/examples/xspice/see/ihp_simple_sram_set.net @@ -0,0 +1,64 @@ +* IHP Open PDK +* simple SRAM cell, exponential current pulses + +* Path to the PDK +*.include "D:\Spice_general\skywater-pdk\libraries\sky130_fd_pr\latest\models\corners/tt.spice" +.lib "D:\Spice_general\IHP-Open-PDK\ihp-sg13g2\libs.tech\ngspice\models\cornerMOSlv.lib" mos_tt +*.include lib_out1.lib + +.param vdd = 1.2 +.param deltat=11n deltat2=27n +.param tochar = 1e-13 +.param talpha = 500p tbeta=10p +.param Inull = 'tochar/(talpha-tbeta)' + +* the voltage sources: +Vdd vd gnd DC 'vdd' +Vwl wl 0 0 PULSE 0 'vdd' 45n 1n 1n 7n 1 +Vbl bl 0 'vdd' +Vbln bln 0 0 + +*V1 in gnd pulse(0 'vdd' 0p 200p 100p 5n 10n) + +* Eponential current source +Iset1 n1 m1 EXP(0 'Inull' 'deltat' 'tbeta' 'deltat' 'talpha') +Iset2 n2 m2 EXP(0 'Inull' 'deltat2' 'tbeta' 'deltat2' 'talpha') +Iset3 n1 m1 EXP(0 'Inull' 'deltat+50n' 'tbeta' 'deltat+50n' 'talpha') +Iset4 n2 m2 EXP(0 'Inull' 'deltat2+50n' 'tbeta' 'deltat2+50n' 'talpha') +*Cset out 0 10f + +Xnot1 n1 vdd vss n2 not1 +Xnot2 n2 vdd vss n1 not1 +xmo02 n2 wl bl vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u +xmo01 n1 wl bln vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u + +Vmeasvss vss 0 0 +Vmeasvdd vd vdd 0 +Vm1 m1 0 0 +Vm2 m2 0 0 + +.subckt not1 a vdd vss z +xm01 z a vdd vdd sg13_lv_pmos l=0.15u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u +xm02 z a vss vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u +c3 a vss 0.384f +c2 z vss 0.576f +.ends + +* starting condition for SRAM cell +.ic v(n2)=0 v(n1)='vdd' + +* simulation command: +.tran 100ps 100ns ; 0 10p + +.options method=gear + +.control +run +rusage +*set nolegend +set xbrushwidth=3 +plot i(Vmeasvss) i(Vmeasvdd) +plot n1 n2+2 wl+4 i(vm1)*10000+6 i(vm2)*10000+8 +.endc + +.end diff --git a/examples/xspice/see/ihp_two_inverters_set.net b/examples/xspice/see/ihp_two_inverters_set.net new file mode 100644 index 000000000..e31712d0b --- /dev/null +++ b/examples/xspice/see/ihp_two_inverters_set.net @@ -0,0 +1,48 @@ +* IHP Open PDK +* simple inverter + +* Path to the PDK +*.include "D:\Spice_general\skywater-pdk\libraries\sky130_fd_pr\latest\models\corners/tt.spice" +.lib "D:\Spice_general\IHP-Open-PDK\ihp-sg13g2\libs.tech\ngspice\models\cornerMOSlv.lib" mos_tt +*.include lib_out1.lib + +.param vdd = 1.2 +.param deltat=11n deltat2=27n + +* the voltage sources: +Vdd vd gnd DC 'vdd' +V1 in gnd pulse(0 'vdd' 0p 200p 100p 5n 10n) + +* Eponential current source +Iset1 out1 0 EXP(0 250u 'deltat' 10p 'deltat' 500p) +Iset2 out1 0 EXP(0 250u 'deltat2' 10p 'deltat2' 500p) +*Cset out 0 10f + +Xnot1 in vdd vss out1 not1 +Xnot2 out1 vdd vss out not1 + +Vmeasvss vss 0 0 +Vmeasvdd vd vdd 0 + +.subckt not1 a vdd vss z +xm01 z a vdd vdd sg13_lv_pmos l=0.15u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u +xm02 z a vss vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u +c3 a vss 0.384f +c2 z vss 0.576f +.ends + +* simulation command: +.tran 100ps 50ns ; 0 10p + +.options method=gear + +.control +run +rusage +*set nolegend +set xbrushwidth=3 +plot i(Vmeasvss) i(Vmeasvdd) +plot in out1+2 out+4 +.endc + +.end diff --git a/examples/xspice/see/repeat_loop_seegen.net b/examples/xspice/see/repeat_loop_seegen.net new file mode 100644 index 000000000..222814719 --- /dev/null +++ b/examples/xspice/see/repeat_loop_seegen.net @@ -0,0 +1,41 @@ +* Repeat loop, double exponential current pulses + +.param let = 10.5 cdepth = 1.2 +.csparam let = 'let' +.param tfall = 500p trise = 20p ; tau in exponent for pulse + +R1 n1 0 1e4 +R2 n2 0 1e4 +R3 n3 0 1e4 +R4 n4 0 1e4 + + +**** SEE generator without control input, double exponential current sources +aseegen1 NULL [%id(n1 0) %id(n2 0) %id(n3 0) %id(n4 0)] seemod1 +.model seemod1 seegen (tdelay = 11n tperiod=25n let='let' cdepth='cdepth' trise='trise' tfall='tfall') +* alternative syntax, if no current measurement required and reference nodes are GND +*aseegen1 NULL [%i(n1) %i(n2) %i(n3) %i(n4)] seemod1 + + + +* simulation command: +.tran 100ps 120ns + +*.options method=gear + +.control +set xbrushwidth=3 +*run +*plot n1 n2+2 n3+4 n4+6 +let newlet = let +repeat 10 + run + plot n1 n2+2 n3+4 n4+6 ylimit -3 7 + let newlet = newlet - 0.5 + alterparam let = $&newlet + reset +end +rusage +.endc + +.end diff --git a/examples/xspice/see/seegen_cm1.cir b/examples/xspice/see/seegen_cm1.cir new file mode 100644 index 000000000..a4bd7e371 --- /dev/null +++ b/examples/xspice/see/seegen_cm1.cir @@ -0,0 +1,22 @@ +Test of seegen code model + +aseegen1 NULL [%id(n1 p1) %id(n2 p2) %id(n3 p3)] seemod1 +.model seemod1 seegen (tdelay = 5n tperiod=4.5n) + +Rsee1 n1 0 1 +Vmeas1 p1 0 0 + +Rsee2 n2 0 1 +Vmeas2 p2 0 0 + +Rsee3 n3 0 1 +Vmeas3 p3 0 0 + +.control +tran 10p 35n +rusage time +set xbrushwidth=3 +plot i(Vmeas1) i(Vmeas2)+200u i(Vmeas3)+400u +.endc + +.end diff --git a/examples/xspice/see/set1.cir b/examples/xspice/see/set1.cir new file mode 100644 index 000000000..6fa666144 --- /dev/null +++ b/examples/xspice/see/set1.cir @@ -0,0 +1,23 @@ +SET pulse test + +.param alpha = 100p beta = 500p deltat = 1n + +* Arbitrary currnt source with expression +Bset1 1 0 I = ternary_fcn(TIME < 'deltat', 0, 2.5m * (exp(-(TIME-'deltat')/'alpha')-exp(-(TIME-'deltat')/'beta'))) +R1 1 11 1 +Vmeas 11 0 0 + +* Eponential current source +Iset 2 0 EXP(0 -2.5m 'deltat' 'alpha' 'deltat' 'beta') +R2 2 22 1 +Vmeas2 22 0 0 + + +.control +tran 1p 10n +set xbrushwidth=2 +plot I(Vmeas)-I(Vmeas2) +plot I(Vmeas) I(Vmeas2) +.endc + +.end diff --git a/src/xspice/icm/xtradev/modpath.lst b/src/xspice/icm/xtradev/modpath.lst index ec7a2f87f..53d9cbea3 100644 --- a/src/xspice/icm/xtradev/modpath.lst +++ b/src/xspice/icm/xtradev/modpath.lst @@ -10,3 +10,4 @@ zener memristor sidiode pswitch +seegenerator diff --git a/src/xspice/icm/xtradev/seegenerator/cfunc.mod b/src/xspice/icm/xtradev/seegenerator/cfunc.mod new file mode 100644 index 000000000..11bee5c74 --- /dev/null +++ b/src/xspice/icm/xtradev/seegenerator/cfunc.mod @@ -0,0 +1,231 @@ +/*.......1.........2.........3.........4.........5.........6.........7.........8 +================================================================================ + +FILE seegenerator/cfunc.mod + +Public Domain + +Universty Duisburg-Essen +Duisburg, Germany +Project Flowspace + +AUTHORS + + 19 May 2025 Holger Vogt + + +MODIFICATIONS + + + +SUMMARY + + This file contains the model-specific routines used to + functionally describe the see (single event effects) generator code model. + + +INTERFACES + + FILE ROUTINE CALLED + + +REFERENCED FILES + + Inputs from and outputs to ARGS structure. + + +NON-STANDARD FEATURES + + NONE + +===============================================================================*/ + +/*=== INCLUDE FILES ====================*/ + + + + +/*=== CONSTANTS ========================*/ + + + + +/*=== MACROS ===========================*/ + + + + +/*=== LOCAL VARIABLES & TYPEDEFS =======*/ + +static void +cm_seegen_callback(ARGS, Mif_Callback_Reason_t reason) +{ + switch (reason) { + case MIF_CB_DESTROY: { + double *last_t_value = STATIC_VAR (last_t_value); + if (last_t_value) + free(last_t_value); + STATIC_VAR (last_t_value) = NULL; + int *pulse_number = STATIC_VAR (pulse_number); + if (pulse_number) + free(pulse_number); + STATIC_VAR (pulse_number) = NULL; + break; + double *last_ctrl = STATIC_VAR (last_ctrl); + if (last_ctrl) + free(last_ctrl); + STATIC_VAR (last_ctrl) = NULL; + } + } +} + + +/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ + + + + + +/*============================================================================== + +FUNCTION void cm_seegen() + +AUTHORS + + 19 May 2025 Holger Vogt + +SUMMARY + + This function implements the see generator code model. + +INTERFACES + + FILE ROUTINE CALLED + + CMutil.c void cm_smooth_corner(); + void cm_smooth_discontinuity(); + void cm_climit_fcn() + +RETURNED VALUE + + Returns inputs and outputs via ARGS structure. + +GLOBAL VARIABLES + + NONE + +NON-STANDARD FEATURES + + model source: + Ygor Quadros de Aguiar, Frdric Wrobel. Jean-Luc Autran, Rubn Garca Ala + Single-Event Effects, from Space to Accelerator Environments + Springer 2025 + +==============================================================================*/ + +/*=== CM_SEEGEN ROUTINE ===*/ + +void cm_seegen(ARGS) /* structure holding parms, + inputs, outputs, etc. */ +{ + double tfall; /* pulse fall time */ + double trise; /* pulse rise time */ + double tdelay; /* delay until first pulse */ + double inull; /* max. current of pulse */ + double let; /* linear energy transfer */ + double cdepth; /* charge collection depth */ + double angle; /* particle entrance angle */ + double tperiod; /* pulse repetition period */ + double ctrlthres; /* control voltage threshold */ + double ctrl; /* control input */ + double out; /* output current */ + double *last_t_value; /* static storage of next pulse time */ + int *pulse_number; /* static storage of next pulse time */ + double *last_ctrl; /* static storage of last ctrl value */ + double tcurr = TIME; /* current simulation time */ + + if (ANALYSIS == MIF_AC) { + return; + } + + /* Retrieve frequently used parameters... */ + + tfall = PARAM(tfall); + trise = PARAM(trise); + tdelay = PARAM(tdelay); + tperiod = PARAM(tperiod); + inull = PARAM(inull); + let = PARAM(let); + cdepth = PARAM(cdepth); + angle = PARAM(angle); + ctrlthres = PARAM(ctrlthres); + + if (PORT_NULL(ctrl)) + ctrl = 1; + else + ctrl = INPUT(ctrl); + + if (INIT==1) { + /* Allocate storage for last_t_value */ + STATIC_VAR(last_t_value) = (double *) malloc(sizeof(double)); + last_t_value = (double *) STATIC_VAR(last_t_value); + *last_t_value = tdelay; + STATIC_VAR(pulse_number) = (int *) malloc(sizeof(int)); + pulse_number = (int *) STATIC_VAR(pulse_number); + *pulse_number = 1; + STATIC_VAR(last_ctrl) = (double *) malloc(sizeof(double)); + last_ctrl = (double *) STATIC_VAR(last_ctrl); + *last_ctrl = ctrl; + /* set breakpoints at first pulse start and pulse maximum times */ + double tatmax = *last_t_value + tfall * trise * log(trise/tfall) / (trise - tfall); + cm_analog_set_perm_bkpt(*last_t_value); + cm_analog_set_perm_bkpt(tatmax); + } + else { + + last_t_value = (double *) STATIC_VAR(last_t_value); + pulse_number = (int *) STATIC_VAR(pulse_number); + last_ctrl = (double *) STATIC_VAR(last_ctrl); + + if (*last_ctrl < ctrlthres && ctrl >= ctrlthres) { + *last_t_value = *last_t_value + tcurr; + *last_ctrl = ctrl; + } + + /* the double exponential current pulse function */ + if (tcurr < *last_t_value) + out = 0; + else { + if (inull == 0) { + double LETeff = let/cos(angle); + double Qc = 1.035e-14 * LETeff * cdepth; + inull = Qc / (tfall - trise); + } + out = inull * (exp(-(tcurr-*last_t_value)/tfall) - exp(-(tcurr-*last_t_value)/trise)); + } + if (tcurr > *last_t_value + tperiod * 0.9) { + /* return some info */ + cm_message_printf("port name: out, node pair no.: %d, \nnode names: %s, %s, pulse time: %e", + *pulse_number, cm_get_node_name("out", *pulse_number - 1), + cm_get_neg_node_name("out", *pulse_number - 1), *last_t_value); + /* set the time for the next pulse */ + *last_t_value = *last_t_value + tperiod; + /* set breakpoints at new pulse start and pulse maximum times */ + double tatmax = *last_t_value + tfall * trise * log(trise/tfall) / (trise - tfall); + cm_analog_set_perm_bkpt(*last_t_value); + cm_analog_set_perm_bkpt(tatmax); + (*pulse_number)++; + if (*pulse_number > PORT_SIZE(out)) { + if (PARAM(perlim) == FALSE) + *pulse_number = 1; + else + *last_t_value = 1e12; /* stop any output */ + } + } + if (*pulse_number - 1 < PORT_SIZE(out)) + OUTPUT(out[*pulse_number - 1]) = out; + } +} + + + diff --git a/src/xspice/icm/xtradev/seegenerator/ifspec.ifs b/src/xspice/icm/xtradev/seegenerator/ifspec.ifs new file mode 100644 index 000000000..58d28f039 --- /dev/null +++ b/src/xspice/icm/xtradev/seegenerator/ifspec.ifs @@ -0,0 +1,120 @@ +/*.......1.........2.........3.........4.........5.........6.........7.........8 +================================================================================ +Public Domain + + +Universty Duisburg-Essen +Duisburg, Germany +Project Flowspace + +AUTHORS + +Holger Vogt 19 May 2025 + + + +SUMMARY + + This file contains the interface specification file for the + analog seegen code model. + +===============================================================================*/ + +NAME_TABLE: + +C_Function_Name: cm_seegen +Spice_Model_Name: seegen +Description: "single event effect generator" + + +PORT_TABLE: + +Port_Name: ctrl out +Description: "control input" "output" +Direction: in out +Default_Type: v i +Allowed_Types: [v,vd,i,id] [i,id] +Vector: no yes +Vector_Bounds: - [1 -] +Null_Allowed: yes no + + +PARAMETER_TABLE: + +Parameter_Name: tfall trise +Description: "pulse fall time" "pulse rise time" +Data_Type: real real +Default_Value: 500e-12 20e-12 +Limits: - - +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + + +PARAMETER_TABLE: + +Parameter_Name: tdelay inull +Description: "pulse delay" "max current" +Data_Type: real real +Default_Value: 0 0 +Limits: - - +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + + +PARAMETER_TABLE: + +Parameter_Name: tperiod ctrlthres +Description: "pulse repetition" "control voltage threshold" +Data_Type: real real +Default_Value: 0 0.5 +Limits: - - +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + + +PARAMETER_TABLE: + +Parameter_Name: let cdepth +Description: "lin energy transfer" "charge collection depth" +Data_Type: real real +Default_Value: 10 1 +Limits: - - +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + + +PARAMETER_TABLE: + +Parameter_Name: angle perlim +Description: "particle angle" "pulse repetition" +Data_Type: real boolean +Default_Value: 0 TRUE +Limits: [0 1.57079] - +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + +STATIC_VAR_TABLE: + +Static_Var_Name: last_t_value +Data_Type: pointer +Vector: no +Description: "next pulse start time" + +STATIC_VAR_TABLE: + +Static_Var_Name: pulse_number +Data_Type: pointer +Vector: no +Description: "number of pulse" + +STATIC_VAR_TABLE: + +Static_Var_Name: last_ctrl +Data_Type: pointer +Vector: no +Description: "last control value" diff --git a/visualc/xspice/xtradev.vcxproj b/visualc/xspice/xtradev.vcxproj index 54a4add88..6a9b35f54 100644 --- a/visualc/xspice/xtradev.vcxproj +++ b/visualc/xspice/xtradev.vcxproj @@ -248,6 +248,10 @@ ..\..\src\xspice\%(RelativeDir);%(AdditionalIncludeDirectories) + + ..\..\src\xspice\%(RelativeDir);%(AdditionalIncludeDirectories) + + @@ -275,6 +279,8 @@ + + From 7f6b2335431172a927fc443d2bbd65f2d4ba2956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81rp=C3=A1d=20B=C5=B1rmen?= Date: Sat, 7 Jun 2025 10:22:32 +0200 Subject: [PATCH 14/38] MESFET m and ic parameters fixed. --- src/spicelib/devices/mes/mes.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/spicelib/devices/mes/mes.c b/src/spicelib/devices/mes/mes.c index 493069642..16f1f8710 100644 --- a/src/spicelib/devices/mes/mes.c +++ b/src/spicelib/devices/mes/mes.c @@ -12,7 +12,8 @@ Author: 1987 Thomas L. Quarles IFparm MESpTable[] = { /* parameters */ OPU("off", MES_OFF, IF_FLAG ,"Device initially off"), IOPU("area", MES_AREA, IF_REAL ,"Area factor"), - IOPUR("m", MES_AREA, IF_REAL ,"Parallel Multiplier"), + IOPUR("m", MES_M, IF_REAL ,"Parallel Multiplier"), + IOPAU("ic", MES_IC, IF_REALVEC,"Initial VDS,VGS vector"), IOPAU("icvds", MES_IC_VDS, IF_REAL ,"Initial D-S voltage"), IOPAU("icvgs", MES_IC_VGS, IF_REAL ,"Initial G-S voltage"), OPU("dnode", MES_DRAINNODE, IF_INTEGER,"Number of drain node"), From e82519388e9ae19f16c88481ce4c9b2d45f865c4 Mon Sep 17 00:00:00 2001 From: Vadim Kuznetsov Date: Thu, 22 May 2025 10:16:42 +0300 Subject: [PATCH 15/38] Add XSPICE models for transmission lines --- src/spinit.in | 1 + src/xspice/icm/GNUmakefile.in | 18 +- src/xspice/icm/tlines/cpline/cfunc.mod | 158 ++++++++ src/xspice/icm/tlines/cpline/ifspec.ifs | 176 +++++++++ src/xspice/icm/tlines/cpmlin/cfunc.mod | 496 ++++++++++++++++++++++++ src/xspice/icm/tlines/cpmlin/ifspec.ifs | 216 +++++++++++ src/xspice/icm/tlines/mlin/cfunc.mod | 133 +++++++ src/xspice/icm/tlines/mlin/ifspec.ifs | 173 +++++++++ src/xspice/icm/tlines/modpath.lst | 4 + src/xspice/icm/tlines/tline/cfunc.mod | 91 +++++ src/xspice/icm/tlines/tline/ifspec.ifs | 87 +++++ src/xspice/icm/tlines/udnpath.lst | 0 src/xspice/tlines/msline_common.c | 337 ++++++++++++++++ src/xspice/tlines/msline_common.h | 60 +++ src/xspice/tlines/tline_common.c | 86 ++++ src/xspice/tlines/tline_common.h | 63 +++ 16 files changed, 2095 insertions(+), 4 deletions(-) create mode 100644 src/xspice/icm/tlines/cpline/cfunc.mod create mode 100644 src/xspice/icm/tlines/cpline/ifspec.ifs create mode 100644 src/xspice/icm/tlines/cpmlin/cfunc.mod create mode 100644 src/xspice/icm/tlines/cpmlin/ifspec.ifs create mode 100644 src/xspice/icm/tlines/mlin/cfunc.mod create mode 100644 src/xspice/icm/tlines/mlin/ifspec.ifs create mode 100644 src/xspice/icm/tlines/modpath.lst create mode 100644 src/xspice/icm/tlines/tline/cfunc.mod create mode 100644 src/xspice/icm/tlines/tline/ifspec.ifs create mode 100644 src/xspice/icm/tlines/udnpath.lst create mode 100644 src/xspice/tlines/msline_common.c create mode 100644 src/xspice/tlines/msline_common.h create mode 100644 src/xspice/tlines/tline_common.c create mode 100644 src/xspice/tlines/tline_common.h diff --git a/src/spinit.in b/src/spinit.in index ee3794b65..669f6f444 100644 --- a/src/spinit.in +++ b/src/spinit.in @@ -25,6 +25,7 @@ if $?xspice_enabled @XSPICEINIT@ codemodel @pkglibdir@/xtradev.cm @XSPICEINIT@ codemodel @pkglibdir@/xtraevt.cm @XSPICEINIT@ codemodel @pkglibdir@/table.cm +@XSPICEINIT@ codemodel @pkglibdir@/tlines.cm end diff --git a/src/xspice/icm/GNUmakefile.in b/src/xspice/icm/GNUmakefile.in index e1344da26..d26ed30b8 100644 --- a/src/xspice/icm/GNUmakefile.in +++ b/src/xspice/icm/GNUmakefile.in @@ -7,11 +7,11 @@ include makedefs # The codemodels to make -CMDIRS = spice2poly digital analog xtradev xtraevt table +CMDIRS = spice2poly digital analog xtradev xtraevt table tlines #Invoke $(MAKE) for each of the CMDDIRS -all: dstring.o # One common dstring object file for all code modules +all: dstring.o msline_common.o tline_common.o# Common object files for all code modules for cm in $(CMDIRS) ; do \ $(MAKE) cm=$$cm $$cm/$$cm.cm \ || exit 1; \ @@ -36,6 +36,8 @@ uninstall: clean: rm -f dstring.o + rm -f msline_common.o + rm -f tline_common.o for cm in $(CMDIRS) ; do \ $(MAKE) cm=$$cm cm-clean \ || exit 1; \ @@ -49,6 +51,12 @@ NGSRCBUILDDIR = $(CURDIR)/../.. dstring.o: $(NGSRCDIR)/misc/dstring.c $(NGSRCDIR)/include/ngspice/dstring.h $(CC) $(CFLAGS) -I$(NGSRCDIR)/include -I$(NGSRCBUILDDIR)/include -fPIC -o $@ -c $< +msline_common.o: $(srcdir)/../tlines/msline_common.c $(srcdir)/../tlines/msline_common.h + $(CC) $(CFLAGS) -I$(srcdir)/../tlines -I$(NGSRCDIR)/include -I$(NGSRCBUILDDIR)/include -fPIC -o $@ -c $< + +tline_common.o: $(srcdir)/../tlines/tline_common.c $(srcdir)/../tlines/tline_common.h + $(CC) $(CFLAGS) -I$(srcdir)/../tlines -I$(NGSRCDIR)/include -I$(NGSRCBUILDDIR)/include -fPIC -o $@ -c $< + ifdef cm ifeq ($(OS),Windows_NT) @@ -70,6 +78,8 @@ cm-gens := \ cm-objs := \ $(cm)/dlmain.o \ dstring.o \ + tline_common.o \ + msline_common.o \ $(modlst:%=$(cm)/%/cfunc.o) \ $(modlst:%=$(cm)/%/ifspec.o) \ $(udnlst:%=$(cm)/%/udnfunc.o) @@ -160,11 +170,11 @@ $(cm)/dlmain.o : $(srcdir)/dlmain.c $(cm-descr) $(do-deps) $(cm)/%/cfunc.o : $(cm)/%/cfunc.c - $(COMPILE) $(gen_pp) -I$(srcdir)/$( +#include +#include +#include +#include + +#include "msline_common.h" +#include "tline_common.h" + + +static void copy_complex(double complex s, Complex_t *d) +{ + d->real = creal(s); + d->imag = cimag(s); +} + +cpline_state_t *sim_points = NULL; + + +void cm_cpline (ARGS) +{ + Complex_t z11, z12, z13, z14; + + /* how to get properties of this component, e.g. L, W */ + double l = PARAM(l); + double ze = PARAM(ze); + double zo = PARAM(zo); + double ere = PARAM(ere); + double ero = PARAM(ero); + double ae = PARAM(ae); + double ao = PARAM(ao); + ae = pow(10, 0.05*ae); + ao = pow(10, 0.05*ao); + + if(INIT) { + + } + + /* Compute the output */ + if(ANALYSIS == DC) { + + double V1 = INPUT(p1s); + double V2 = INPUT(p2s); + double V3 = INPUT(p3s); + double V4 = INPUT(p4s); + double I1 = INPUT(p1); + double I2 = INPUT(p2); + double I3 = INPUT(p3); + double I4 = INPUT(p4); + + double z = sqrt(ze*zo); + + double V2out = V1 + z*I1; + double V1out = V2 + z*I2; + OUTPUT(p1) = V1out + I1*z; + OUTPUT(p2) = V2out + I2*z; + + double V3out = V4 + z*I4; + double V4out = V3 + z*I3; + OUTPUT(p3) = V3out + I3*z; + OUTPUT(p4) = V4out + I4*z; + + cm_analog_auto_partial(); + } + else if(ANALYSIS == AC) { + double o = RAD_FREQ; + + double complex _Z11, _Z12, _Z13, _Z14; + double complex arg_e = log(ae)*l/2.0 + I*o*l/C0*sqrt(ere); + double complex arg_o = log(ao)*l/2.0 + I*o*l/C0*sqrt(ero); + + _Z11 = zo / (2*ctanh(arg_o)) + ze / (2*ctanh(arg_e)); + _Z12 = zo / (2*csinh(arg_o)) + ze / (2*csinh(arg_e)); + _Z13 = ze / (2*csinh(arg_e)) - zo / (2*csinh(arg_o)); + _Z14 = ze / (2*ctanh(arg_e)) - zo / (2*ctanh(arg_o)); + + copy_complex(_Z11,&z11); + copy_complex(_Z12,&z12); + copy_complex(_Z13,&z13); + copy_complex(_Z14,&z14); + + AC_GAIN(p1,p1) = z11; AC_GAIN(p2,p2) = z11; + AC_GAIN(p3,p3) = z11; AC_GAIN(p4,p4) = z11; + + AC_GAIN(p1,p2) = z12; AC_GAIN(p2,p1) = z12; + AC_GAIN(p3,p4) = z12; AC_GAIN(p4,p3) = z12; + + AC_GAIN(p1,p3) = z13; AC_GAIN(p3,p1) = z13; + AC_GAIN(p2,p4) = z13; AC_GAIN(p4,p2) = z13; + + AC_GAIN(p1,p4) = z14; AC_GAIN(p4,p1) = z14; + AC_GAIN(p2,p3) = z14; AC_GAIN(p3,p2) = z14; + } + else if(ANALYSIS == TRANSIENT) { + double t = TIME; + double Vp[PORT_NUM]; + double Ip[PORT_NUM]; + + Vp[0] = INPUT(p1s); + Vp[1] = INPUT(p2s); + Vp[2] = INPUT(p3s); + Vp[3] = INPUT(p4s); + Ip[0] = INPUT(p1); + Ip[1] = INPUT(p2); + Ip[2] = INPUT(p3); + Ip[3] = INPUT(p4); + double delay = l/(C0); + append_cpline_state(&sim_points, t, Vp, Ip, 1.2*delay); + if (t > delay) { + cpline_state_t *pp = find_cpline_state(sim_points, t - delay); + if (pp != NULL) { + + double J1e = 0.5*(Ip[3] + Ip[0]); + double J1o = 0.5*(Ip[0] - Ip[3]); + double J2e = 0.5*(Ip[1] + Ip[2]); + double J2o = 0.5*(Ip[1] - Ip[2]); + + + double J1et = 0.5*(pp->Ip[3] + pp->Ip[0]); + double J1ot = 0.5*(pp->Ip[0] - pp->Ip[3]); + double J2et = 0.5*(pp->Ip[1] + pp->Ip[2]); + double J2ot = 0.5*(pp->Ip[1] - pp->Ip[2]); + + + double V1et = 0.5*(pp->Vp[3] + pp->Vp[0]); + double V1ot = 0.5*(pp->Vp[0] - pp->Vp[3]); + double V2et = 0.5*(pp->Vp[1] + pp->Vp[2]); + double V2ot = 0.5*(pp->Vp[1] - pp->Vp[2]); + + double V1e = ze*J1e + V2et + ze*J2et; + double V1o = zo*J1o + V2ot + zo*J2ot; + double V2e = ze*J2e + V1et + ze*J1et; + double V2o = zo*J2o + V1ot + zo*J1ot; + + double V1 = V1o + V1e; + double V2 = V2o + V2e; + double V3 = V2e - V2o; + double V4 = V1e - V1o; + + OUTPUT(p1) = V1; + OUTPUT(p2) = V2; + OUTPUT(p3) = V3; + OUTPUT(p4) = V4; + } + cm_analog_auto_partial(); + } else { + cm_analog_auto_partial(); + } + } +} + diff --git a/src/xspice/icm/tlines/cpline/ifspec.ifs b/src/xspice/icm/tlines/cpline/ifspec.ifs new file mode 100644 index 000000000..aa5639010 --- /dev/null +++ b/src/xspice/icm/tlines/cpline/ifspec.ifs @@ -0,0 +1,176 @@ +/* =========================================================================== +FILE ifspec.ifs + +(c) vadim Kuznetsov 2025 + +=========================================================================== */ + +/* Ports connection + 4 --||||||-- 3 + + 1 --||||||-- 2 +*/ + +NAME_TABLE: + +Spice_Model_Name: cpline +C_Function_Name: cm_cpline +Description: "Generic transmission line" + + +PORT_TABLE: +Port_Name: p1 +Description: "Terminals Line1" +Direction: inout +Default_Type: hd +Allowed_Types: [hd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: p2 +Description: "Terminals Line1" +Direction: inout +Default_Type: hd +Allowed_Types: [hd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: p3 +Description: "Terminals Line2" +Direction: inout +Default_Type: hd +Allowed_Types: [hd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: p4 +Description: "Terminals Line2" +Direction: inout +Default_Type: hd +Allowed_Types: [hd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: p1s +Description: "Sensing terminals line 1" +Direction: in +Default_Type: vd +Allowed_Types: [vd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: p2s +Description: "Sensing terminals line 1" +Direction: in +Default_Type: vd +Allowed_Types: [vd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: p3s +Description: "Sensing terminals line 1" +Direction: in +Default_Type: vd +Allowed_Types: [vd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: p4s +Description: "Sensing terminals line 1" +Direction: in +Default_Type: vd +Allowed_Types: [vd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + + +PARAMETER_TABLE: +Parameter_Name: l +Description: "length" +Data_Type: real +Default_Value: 1.0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: ze +Description: "characteristic impedance of even mode" +Data_Type: real +Default_Value: 50.0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: zo +Description: "characteristic impedance of odd mode" +Data_Type: real +Default_Value: 50.0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +PARAMETER_TABLE: +Parameter_Name: ae +Description: "attenuation per length (dB) even mode" +Data_Type: real +Default_Value: 0.0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +PARAMETER_TABLE: +Parameter_Name: ao +Description: "attenuation per length (dB) odd mode" +Data_Type: real +Default_Value: 0.0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +PARAMETER_TABLE: +Parameter_Name: ere +Description: "dielectric constant even mode" +Data_Type: real +Default_Value: 1.0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +PARAMETER_TABLE: +Parameter_Name: ero +Description: "dielectric constant odd mode" +Data_Type: real +Default_Value: 1.0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + diff --git a/src/xspice/icm/tlines/cpmlin/cfunc.mod b/src/xspice/icm/tlines/cpmlin/cfunc.mod new file mode 100644 index 000000000..c1975dfec --- /dev/null +++ b/src/xspice/icm/tlines/cpmlin/cfunc.mod @@ -0,0 +1,496 @@ +/* =========================================================================== + FILE cfunc.mod + + (c) Vadim Kuznetsov 2025 + + */ + +#include +#include +#include +#include +#include + + +#include "msline_common.h" +#include "tline_common.h" + +static double ae, ao, be, bo, ze, zo, ee, eo; + +static void copy_complex(double complex s, Complex_t *d) +{ + d->real = creal(s); + d->imag = cimag(s); +} + + +static cpline_state_t *state = NULL; + +static void analyseQuasiStatic (double W, double h, double s, + double t, double er, + int SModel, double* Zle, + double* Zlo, double* ErEffe, + double* ErEffo); + +static void analyseDispersion (double W, double h, double s, + double t, double er, double Zle, + double Zlo, double ErEffe, + double ErEffo, double frequency, + int DModel, double *ZleFreq, + double *ZloFreq, + double *ErEffeFreq, + double *ErEffoFreq); + +static void calcPropagation (double W, double s, + double er, double h, double t, double tand, double rho, double D, + int SModel, int DModel, double frequency) +{ + + // quasi-static analysis + double Zle, ErEffe, Zlo, ErEffo; + analyseQuasiStatic (W, h, s, t, er, SModel, &Zle, &Zlo, &ErEffe, &ErEffo); + + // analyse dispersion of Zl and Er + double ZleFreq, ErEffeFreq, ZloFreq, ErEffoFreq; + analyseDispersion (W, h, s, t, er, Zle, Zlo, ErEffe, ErEffo, frequency, DModel, + &ZleFreq, &ZloFreq, &ErEffeFreq, &ErEffoFreq); + + // analyse losses of line + double ace, aco, ade, ado; + analyseLoss (W, t, er, rho, D, tand, Zle, Zlo, ErEffe, + frequency, HAMMERSTAD, &ace, &ade); + analyseLoss (W, t, er, rho, D, tand, Zlo, Zle, ErEffo, + frequency, HAMMERSTAD, &aco, &ado); + + // compute propagation constants for even and odd mode + double k0 = 2 * M_PI * frequency / C0; + ae = ace + ade; + ao = aco + ado; + be = sqrt (ErEffeFreq) * k0; + bo = sqrt (ErEffoFreq) * k0; + ze = ZleFreq; + zo = ZloFreq; + ee = ErEffeFreq; + eo = ErEffoFreq; +} + + + +/* The function calculates the quasi-static dielectric constants and + characteristic impedances for the even and odd mode based upon the + given line and substrate properties for parallel coupled microstrip + lines. */ +static void analyseQuasiStatic (double W, double h, double s, + double t, double er, + int SModel, double* Zle, + double* Zlo, double* ErEffe, + double* ErEffo) { + // initialize default return values + *ErEffe = er; *ErEffo = er; + *Zlo = 42.2; *Zle = 55.7; + + // normalized width and gap + double u = W / h; + double g = s / h; + + // HAMMERSTAD and JENSEN + if (SModel == HAMMERSTAD) { + double Zl1, Fe, Fo, a, b, fo, Mu, Alpha, Beta, ErEff; + double Pe, Po, r, fo1, q, p, n, Psi, Phi, m, Theta; + + // modifying equations for even mode + m = 0.2175 + pow (4.113 + pow (20.36 / g, 6.), -0.251) + + log (pow (g, 10.) / (1 + pow (g / 13.8, 10.))) / 323; + Alpha = 0.5 * exp (-g); + Psi = 1 + g / 1.45 + pow (g, 2.09) / 3.95; + Phi = 0.8645 * pow (u, 0.172); + Pe = Phi / (Psi * (Alpha * pow (u, m) + (1 - Alpha) * pow (u, -m))); + // TODO: is this ... Psi * (Alpha ... or ... Psi / (Alpha ... ? + + // modifying equations for odd mode + n = (1 / 17.7 + exp (-6.424 - 0.76 * log (g) - pow (g / 0.23, 5.))) * + log ((10 + 68.3 * sqr (g)) / (1 + 32.5 * pow (g, 3.093))); + Beta = 0.2306 + log (pow (g, 10.) / (1 + pow (g / 3.73, 10.))) / 301.8 + + log (1 + 0.646 * pow (g, 1.175)) / 5.3; + Theta = 1.729 + 1.175 * log (1 + 0.627 / (g + 0.327 * pow (g, 2.17))); + Po = Pe - Theta / Psi * exp (Beta * pow (u, -n) * log (u)); + + // further modifying equations + r = 1 + 0.15 * (1 - exp (1 - sqr (er - 1) / 8.2) / (1 + pow (g, -6.))); + fo1 = 1 - exp (-0.179 * pow (g, 0.15) - + 0.328 * pow (g, r) / log (M_E + pow (g / 7, 2.8))); + q = exp (-1.366 - g); + p = exp (-0.745 * pow (g, 0.295)) / cosh (pow (g, 0.68)); + fo = fo1 * exp (p * log (u) + q * sin (M_PI * log10 (u))); + + Mu = g * exp (-g) + u * (20 + sqr (g)) / (10 + sqr (g)); + Hammerstad_ab (Mu, er, &a, &b); + Fe = pow (1 + 10 / Mu, -a * b); + Hammerstad_ab (u, er, &a, &b); + Fo = fo * pow (1 + 10 / u, -a * b); + + // finally compute effective dielectric constants and impedances + *ErEffe = (er + 1) / 2 + (er - 1) / 2 * Fe; + *ErEffo = (er + 1) / 2 + (er - 1) / 2 * Fo; + + Hammerstad_er (u, er, a, b, &ErEff); // single microstrip + + // first variant + Zl1 = Z0 / (u + 1.98 * pow (u, 0.172)); + Zl1 /= sqrt (ErEff); + + // second variant + Hammerstad_zl (u, &Zl1); + Zl1 /= sqrt (ErEff); + + *Zle = Zl1 / (1 - Zl1 * Pe / Z0); + *Zlo = Zl1 / (1 - Zl1 * Po / Z0); + } + // KIRSCHNING and JANSEN + else if (SModel == KIRSCHING) { + double a, b, ae, be, ao, bo, v, co, d, ErEff, Zl1; + double q1, q2, q3, q4, q5, q6, q7, q8, q9, q10; + + // consider effect of finite strip thickness (JANSEN only) + double ue = u; + double uo = u; + if (t != 0 && s > 10 * (2 * t)) { + double dW = 0; + // SCHNEIDER, referred by JANSEN + if (u >= M_1_PI / 2 && M_1_PI / 2 > 2 * t / h) + dW = t * (1 + log (2 * h / t)) / M_PI; + else if (W > 2 * t) + dW = t * (1 + log (4 * M_PI * W / t)) / M_PI; + // JANSEN + double dt = 2 * t * h / s / er; + double We = W + dW * (1 - 0.5 * exp (-0.69 * dW / dt)); + double Wo = We + dt; + ue = We / h; + uo = Wo / h; + } + + // even relative dielectric constant + v = ue * (20 + sqr (g)) / (10 + sqr (g)) + g * exp (-g); + Hammerstad_ab (v, er, &ae, &be); + Hammerstad_er (v, er, ae, be, ErEffe); + + // odd relative dielectric constant + Hammerstad_ab (uo, er, &a, &b); + Hammerstad_er (uo, er, a, b, &ErEff); + d = 0.593 + 0.694 * exp (-0.562 * uo); + bo = 0.747 * er / (0.15 + er); + co = bo - (bo - 0.207) * exp (-0.414 * uo); + ao = 0.7287 * (ErEff - (er + 1) / 2) * (1 - exp (-0.179 * uo)); + *ErEffo = ((er + 1) / 2 + ao - ErEff) * exp (-co * pow (g, d)) + ErEff; + + // characteristic impedance of single line + Hammerstad_zl (u, &Zl1); + Zl1 /= sqrt (ErEff); + + // even characteristic impedance + q1 = 0.8695 * pow (ue, 0.194); + q2 = 1 + 0.7519 * g + 0.189 * pow (g, 2.31); + q3 = 0.1975 + pow (16.6 + pow (8.4 / g, 6.), -0.387) + + log (pow (g, 10.) / (1 + pow (g / 3.4, 10.))) / 241; + q4 = q1 / q2 * 2 / + (exp (-g) * pow (ue, q3) + (2 - exp (-g)) * pow (ue, -q3)); + *Zle = sqrt (ErEff / *ErEffe) * Zl1 / (1 - Zl1 * sqrt (ErEff) * q4 / Z0); + + // odd characteristic impedance + q5 = 1.794 + 1.14 * log (1 + 0.638 / (g + 0.517 * pow (g, 2.43))); + q6 = 0.2305 + log (pow (g, 10.) / (1 + pow (g / 5.8, 10.))) / 281.3 + + log (1 + 0.598 * pow (g, 1.154)) / 5.1; + q7 = (10 + 190 * sqr (g)) / (1 + 82.3 * cubic (g)); + q8 = exp (-6.5 - 0.95 * log (g) - pow (g / 0.15, 5.)); + q9 = log (q7) * (q8 + 1 / 16.5); + q10 = (q2 * q4 - q5 * exp (log (uo) * q6 * pow (uo, -q9))) / q2; + *Zlo = sqrt (ErEff / *ErEffo) * Zl1 / (1 - Zl1 * sqrt (ErEff) * q10 / Z0); + } +} + +/* The function computes the dispersion effects on the dielectric + constants and characteristic impedances for the even and odd mode + of parallel coupled microstrip lines. */ +static void analyseDispersion (double W, double h, double s, + double t, double er, double Zle, + double Zlo, double ErEffe, + double ErEffo, double frequency, + int DModel, double *ZleFreq, + double *ZloFreq, + double *ErEffeFreq, + double *ErEffoFreq) { + + // initialize default return values + *ZleFreq = Zle; + *ErEffeFreq = ErEffe; + *ZloFreq = Zlo; + *ErEffoFreq = ErEffo; + + // normalized width and gap + double u = W / h; + double g = s / h; + double ue, uo; + double B, dW, dt; + + // compute u_odd, u_even + if (t > 0.0) { + if (u < 0.1592) { + B = 2 * M_PI * W; + } else { + B = h; + } + dW = t * (1.0 + log(2 * B / t)) / M_PI; + dt = t / (er * g); + ue = (W + dW * (1.0 - 0.5 * exp( -0.69 * dW / dt ))) / h; + uo = ue + dt / h; + } else { + ue = u; + uo = u; + } + + // GETSINGER + if (DModel == GETSINGER) { + // even mode dispersion + Getsinger_disp (h, er, ErEffe, Zle / 2, + frequency, ErEffeFreq, ZleFreq); + *ZleFreq *= 2; + // odd mode dispersion + Getsinger_disp (h, er, ErEffo, Zlo * 2, + frequency, ErEffoFreq, ZloFreq); + *ZloFreq /= 2; + } + // KIRSCHNING and JANSEN + else if (DModel == DISP_KIRSCHING) { + double p1, p2, p3, p4, p5, p6, p7, Fe; + double fn = frequency * h * 1e-6; + + // even relative dielectric constant dispersion + p1 = 0.27488 * (0.6315 + 0.525 / pow (1 + 0.0157 * fn, 20.)) * ue - + 0.065683 * exp (-8.7513 * ue); + p2 = 0.33622 * (1 - exp (-0.03442 * er)); + p3 = 0.0363 * exp (-4.6 * ue) * (1 - exp (- pow (fn / 38.7, 4.97))); + p4 = 1 + 2.751 * (1 - exp (- pow (er / 15.916, 8.))); + p5 = 0.334 * exp (-3.3 * cubic (er / 15)) + 0.746; + p6 = p5 * exp (- pow (fn / 18, 0.368)); + p7 = 1 + 4.069 * p6 * pow (g, 0.479) * + exp (-1.347 * pow (g, 0.595) - 0.17 * pow (g, 2.5)); + Fe = p1 * p2 * pow ((p3 * p4 + 0.1844 * p7) * fn, 1.5763); + *ErEffeFreq = er - (er - ErEffe) / (1 + Fe); + + // odd relative dielectric constant dispersion + double p8, p9, p10, p11, p12, p13, p14, p15, Fo; + p1 = 0.27488 * (0.6315 + 0.525 / pow (1 + 0.0157 * fn, 20.)) * uo - + 0.065683 * exp (-8.7513 * uo); + p3 = 0.0363 * exp (-4.6 * uo) * (1 - exp (- pow (fn / 38.7, 4.97))); + p8 = 0.7168 * (1 + 1.076 / (1 + 0.0576 * (er - 1))); + p9 = p8 - 0.7913 * (1 - exp (- pow (fn / 20, 1.424))) * + atan (2.481 * pow (er / 8, 0.946)); + p10 = 0.242 * pow (er - 1, 0.55); + p11 = 0.6366 * (exp (-0.3401 * fn) - 1) * + atan (1.263 * pow (uo / 3, 1.629)); + p12 = p9 + (1 - p9) / (1 + 1.183 * pow (uo, 1.376)); + p13 = 1.695 * p10 / (0.414 + 1.605 * p10); + p14 = 0.8928 + 0.1072 * (1 - exp (-0.42 * pow (fn / 20, 3.215))); + p15 = fabs (1 - 0.8928 * (1 + p11) * + exp (-p13 * pow (g, 1.092)) * p12 / p14); + Fo = p1 * p2 * pow ((p3 * p4 + 0.1844) * fn * p15, 1.5763); + *ErEffoFreq = er - (er - ErEffo) / (1 + Fo); + + // dispersion of even characteristic impedance + double t, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21; + q11 = 0.893 * (1 - 0.3 / (1 + 0.7 * (er - 1))); + t = pow (fn / 20, 4.91); + q12 = 2.121 * t / (1 + q11 * t) * exp (-2.87 * g) * pow (g, 0.902); + q13 = 1 + 0.038 * pow (er / 8, 5.1); + t = quadr (er / 15); + q14 = 1 + 1.203 * t / (1 + t); + q15 = 1.887 * exp (-1.5 * pow (g, 0.84)) * pow (g, q14) / + (1 + 0.41 * pow (fn / 15, 3.) * + pow (u, 2 / q13) / (0.125 + pow (u, 1.626 / q13))); + q16 = q15 * (1 + 9 / (1 + 0.403 * sqr (er - 1))); + q17 = 0.394 * (1 - exp (-1.47 * pow (u / 7, 0.672))) * + (1 - exp (-4.25 * pow (fn / 20, 1.87))); + q18 = 0.61 * (1 - exp (-2.31 * pow (u / 8, 1.593))) / + (1 + 6.544 * pow (g, 4.17)); + q19 = 0.21 * quadr (g) / (1 + 0.18 * pow (g, 4.9)) / (1 + 0.1 * sqr (u)) / + (1 + pow (fn / 24, 3.)); + q20 = q19 * (0.09 + 1 / (1 + 0.1 * pow (er - 1, 2.7))); + t = pow (u, 2.5); + q21 = fabs (1 - 42.54 * pow (g, 0.133) * exp (-0.812 * g) * t / + (1 + 0.033 * t)); + + double re, qe, pe, de, Ce, q0, ZlFreq, ErEffFreq; + Kirschning_er (u, fn, er, ErEffe, &ErEffFreq); + Kirschning_zl (u, fn, er, ErEffe, ErEffFreq, Zle, &q0, &ZlFreq); + re = pow (fn / 28.843, 12.); + qe = 0.016 + pow (0.0514 * er * q21, 4.524); + pe = 4.766 * exp (-3.228 * pow (u, 0.641)); + t = pow (er - 1, 6.); + de = 5.086 * qe * re / (0.3838 + 0.386 * qe) * + exp (-22.2 * pow (u, 1.92)) / (1 + 1.2992 * re) * t / (1 + 10 * t); + Ce = 1 + 1.275 * (1 - exp (-0.004625 * pe * pow (er, 1.674) * + pow (fn / 18.365, 2.745))) - q12 + q16 - q17 + q18 + q20; + *ZleFreq = Zle * pow ((0.9408 * pow (ErEffFreq, Ce) - 0.9603) / + ((0.9408 - de) * pow (ErEffe, Ce) - 0.9603), q0); + + // dispersion of odd characteristic impedance + double q22, q23, q24, q25, q26, q27, q28, q29; + Kirschning_er (u, fn, er, ErEffo, &ErEffFreq); + Kirschning_zl (u, fn, er, ErEffo, ErEffFreq, Zlo, &q0, &ZlFreq); + q29 = 15.16 / (1 + 0.196 * sqr (er - 1)); + t = sqr (er - 1); + q25 = 0.3 * sqr (fn) / (10 + sqr (fn)) * (1 + 2.333 * t / (5 + t)); + t = pow ((er - 1) / 13, 12.); + q26 = 30 - 22.2 * t / (1 + 3 * t) - q29; + t = pow (er - 1, 1.5); + q27 = 0.4 * pow (g, 0.84) * (1 + 2.5 * t / (5 + t)); + t = pow (er - 1, 3.); + q28 = 0.149 * t / (94.5 + 0.038 * t); + q22 = 0.925 * pow (fn / q26, 1.536) / (1 + 0.3 * pow (fn / 30, 1.536)); + q23 = 1 + 0.005 * fn * q27 / (1 + 0.812 * pow (fn / 15, 1.9)) / + (1 + 0.025 * sqr (u)); + t = pow (u, 0.894); + q24 = 2.506 * q28 * t / (3.575 + t) * + pow ((1 + 1.3 * u) * fn / 99.25, 4.29); + *ZloFreq = ZlFreq + (Zlo * pow (*ErEffoFreq / ErEffo, q22) - ZlFreq * q23) / + (1 + q24 + pow (0.46 * g, 2.2) * q25); + + } +} + +void cm_cpmline (ARGS) +{ + Complex_t z11, z12, z13, z14; + + /* how to get properties of this component, e.g. L, W */ + double W = PARAM(w); + double l = PARAM(l); + double s = PARAM(s); + int SModel = PARAM(model); + int DModel = PARAM(disp); + + /* how to get properties of the substrate, e.g. Er, H */ + double er = PARAM(er); + double h = PARAM(h); + double t = PARAM(t); + double tand = PARAM(tand); + double rho = PARAM(rho); + double D = PARAM(d); + + + + /* Compute the output */ + if(ANALYSIS == DC) { + calcPropagation(W,s,er,h,t,tand,rho,D,SModel,DModel,0); + + double V1 = INPUT(p1s); + double V2 = INPUT(p2s); + double V3 = INPUT(p3s); + double V4 = INPUT(p4s); + double I1 = INPUT(p1); + double I2 = INPUT(p2); + double I3 = INPUT(p3); + double I4 = INPUT(p4); + + double z = sqrt(ze*zo); + + double V2out = V1 + z*I1; + double V1out = V2 + z*I2; + OUTPUT(p1) = V1out + I1*z; + OUTPUT(p2) = V2out + I2*z; + + double V3out = V4 + z*I4; + double V4out = V3 + z*I3; + OUTPUT(p3) = V3out + I3*z; + OUTPUT(p4) = V4out + I4*z; + + cm_analog_auto_partial(); + } + else if(ANALYSIS == AC) { + double o = RAD_FREQ; + calcPropagation(W,s,er,h,t,tand,rho,D,SModel,DModel, o/(2*M_PI)); + double complex _Z11, _Z12, _Z13, _Z14; + double complex ge = ae + I*be; + double complex go = ao + I*bo; + + _Z11 = zo / (2*ctanh(go*l)) + ze / (2*ctanh(ge*l)); + _Z12 = zo / (2*csinh(go*l)) + ze / (2*csinh(ge*l)); + _Z13 = ze / (2*csinh(ge*l)) - zo / (2*csinh(go*l)); + _Z14 = ze / (2*ctanh(ge*l)) - zo / (2*ctanh(go*l)); + + copy_complex(_Z11,&z11); + copy_complex(_Z12,&z12); + copy_complex(_Z13,&z13); + copy_complex(_Z14,&z14); + + AC_GAIN(p1,p1) = z11; AC_GAIN(p2,p2) = z11; + AC_GAIN(p3,p3) = z11; AC_GAIN(p4,p4) = z11; + + AC_GAIN(p1,p2) = z12; AC_GAIN(p2,p1) = z12; + AC_GAIN(p3,p4) = z12; AC_GAIN(p4,p3) = z12; + + AC_GAIN(p1,p3) = z13; AC_GAIN(p3,p1) = z13; + AC_GAIN(p2,p4) = z13; AC_GAIN(p4,p2) = z13; + + AC_GAIN(p1,p4) = z14; AC_GAIN(p4,p1) = z14; + AC_GAIN(p2,p3) = z14; AC_GAIN(p3,p2) = z14; + } + else if(ANALYSIS == TRANSIENT) { + calcPropagation(W,s,er,h,t,tand,rho,D,SModel,DModel,0); + double t = TIME; + double Vp[PORT_NUM]; + double Ip[PORT_NUM]; + double Vnew[PORT_NUM]; + Vp[0] = INPUT(p1s); + Vp[1] = INPUT(p2s); + Vp[2] = INPUT(p3s); + Vp[3] = INPUT(p4s); + Ip[0] = INPUT(p1); + Ip[1] = INPUT(p2); + Ip[2] = INPUT(p3); + Ip[3] = INPUT(p4); + double delay = l/(C0); + append_cpline_state(&state, t, Vp, Ip, 1.2*delay); + if (t > delay) { + cpline_state_t *pp = find_cpline_state(state, t - delay); + if (pp != NULL) { + + double J1e = 0.5*(Ip[3] + Ip[0]); + double J1o = 0.5*(Ip[0] - Ip[3]); + double J2e = 0.5*(Ip[1] + Ip[2]); + double J2o = 0.5*(Ip[1] - Ip[2]); + + + double J1et = 0.5*(pp->Ip[3] + pp->Ip[0]); + double J1ot = 0.5*(pp->Ip[0] - pp->Ip[3]); + double J2et = 0.5*(pp->Ip[1] + pp->Ip[2]); + double J2ot = 0.5*(pp->Ip[1] - pp->Ip[2]); + + + double V1et = 0.5*(pp->Vp[3] + pp->Vp[0]); + double V1ot = 0.5*(pp->Vp[0] - pp->Vp[3]); + double V2et = 0.5*(pp->Vp[1] + pp->Vp[2]); + double V2ot = 0.5*(pp->Vp[1] - pp->Vp[2]); + + double V1e = ze*J1e + V2et + ze*J2et; + double V1o = zo*J1o + V2ot + zo*J2ot; + double V2e = ze*J2e + V1et + ze*J1et; + double V2o = zo*J2o + V1ot + zo*J1ot; + + double V1 = V1o + V1e; + double V2 = V2o + V2e; + double V3 = V2e - V2o; + double V4 = V1e - V1o; + + OUTPUT(p1) = V1; + OUTPUT(p2) = V2; + OUTPUT(p3) = V3; + OUTPUT(p4) = V4; + } + cm_analog_auto_partial(); + } else { + cm_analog_auto_partial(); + } + } +} + diff --git a/src/xspice/icm/tlines/cpmlin/ifspec.ifs b/src/xspice/icm/tlines/cpmlin/ifspec.ifs new file mode 100644 index 000000000..04a58eb67 --- /dev/null +++ b/src/xspice/icm/tlines/cpmlin/ifspec.ifs @@ -0,0 +1,216 @@ +/* =========================================================================== +FILE ifspec.ifs + +(c) vadim Kuznetsov 2025 + +=========================================================================== */ + +/* Ports connection + 4 --||||||-- 3 + + 1 --||||||-- 2 +*/ + +NAME_TABLE: + +Spice_Model_Name: cpmlin +C_Function_Name: cm_cpmline +Description: "Generic transmission line" + + +PORT_TABLE: +Port_Name: p1 +Description: "Terminals Line1" +Direction: inout +Default_Type: hd +Allowed_Types: [hd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: p2 +Description: "Terminals Line1" +Direction: inout +Default_Type: hd +Allowed_Types: [hd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: p3 +Description: "Terminals Line2" +Direction: inout +Default_Type: hd +Allowed_Types: [hd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: p4 +Description: "Terminals Line2" +Direction: inout +Default_Type: hd +Allowed_Types: [hd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: p1s +Description: "Sensing terminals line 1" +Direction: in +Default_Type: vd +Allowed_Types: [vd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: p2s +Description: "Sensing terminals line 1" +Direction: in +Default_Type: vd +Allowed_Types: [vd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: p3s +Description: "Sensing terminals line 1" +Direction: in +Default_Type: vd +Allowed_Types: [vd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: p4s +Description: "Sensing terminals line 1" +Direction: in +Default_Type: vd +Allowed_Types: [vd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + + +PARAMETER_TABLE: +Parameter_Name: l +Description: "length" +Data_Type: real +Default_Value: 1.0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: w +Description: "width" +Data_Type: real +Default_Value: 1e-3 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: s +Description: "gap" +Data_Type: real +Default_Value: 1e-3 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + + +PARAMETER_TABLE: +Parameter_Name: model +Description: "Model type" +Data_Type: int +Default_Value: 0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +PARAMETER_TABLE: +Parameter_Name: disp +Description: "Dispersion type" +Data_Type: int +Default_Value: 0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: er +Description: "Substrate dielectric permittivity" +Data_Type: real +Default_Value: 9.8 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: h +Description: "Substrate thickness" +Data_Type: real +Default_Value: 1e-3 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: t +Description: "Metal strip thickness" +Data_Type: real +Default_Value: 35e-6 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: tand +Description: "Substrate dielectric loss" +Data_Type: real +Default_Value: 2e-4 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +PARAMETER_TABLE: +Parameter_Name: rho +Description: "Metal resistance" +Data_Type: real +Default_Value: 0.022e-6 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: d +Description: "RMS Substrate roughness" +Data_Type: real +Default_Value: 0.15e-6 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + diff --git a/src/xspice/icm/tlines/mlin/cfunc.mod b/src/xspice/icm/tlines/mlin/cfunc.mod new file mode 100644 index 000000000..7aea193ab --- /dev/null +++ b/src/xspice/icm/tlines/mlin/cfunc.mod @@ -0,0 +1,133 @@ +/* =========================================================================== + FILE cfunc.mod + + (c) Vadim Kuznetsov 2025 + + */ + +#include +#include +#include + +#include "tline_common.h" + +#include "msline_common.h" + +static tline_state_t *sim_points = NULL; + +static double zl, alpha, beta, ereff; + +static void calcPropagation (double W, int SModel, int DModel, + double er, double h, double t, double tand, double rho, double D, + double frequency) { + + /* local variables */ + double ac, ad; + double ZlEff, ErEff, WEff, ZlEffFreq, ErEffFreq; + + // quasi-static effective dielectric constant of substrate + line and + // the impedance of the microstrip line + mslineAnalyseQuasiStatic (W, h, t, er, SModel, &ZlEff, &ErEff, &WEff); + + // analyse dispersion of Zl and Er (use WEff here?) + mslineAnalyseDispersion (W, h, er, ZlEff, ErEff, frequency, DModel, + &ZlEffFreq, &ErEffFreq); + + // analyse losses of line + analyseLoss (W, t, er, rho, D, tand, ZlEff, ZlEff, ErEff, + frequency, HAMMERSTAD, &ac, &ad); + + // calculate propagation constants and reference impedance + zl = ZlEffFreq; + ereff = ErEffFreq; + alpha = ac + ad; + beta = sqrt (ErEffFreq) * 2 * M_PI * frequency / C0; +} + +void cm_mlin (ARGS) +{ + Complex_t z11, z21; + + + /* how to get properties of this component, e.g. L, W */ + double W = PARAM(w); + double l = PARAM(l); + int SModel = PARAM(model); + int DModel = PARAM(disp); + int TModel = PARAM(tranmodel); + + /* how to get properties of the substrate, e.g. Er, H */ + double er = PARAM(er); + double h = PARAM(h); + double t = PARAM(t); + double tand = PARAM(tand); + double rho = PARAM(rho); + double D = PARAM(d); + + + + /* Initialize/access instance specific storage for capacitor voltage */ + if(INIT) { + + } + + /* Compute the output */ + if(ANALYSIS == DC) { + + calcPropagation(W,SModel,DModel,er,h,t,tand,rho,D,0); + double V1 = INPUT(V1sens); + double V2 = INPUT(V2sens); + double I1 = INPUT(port1); + double I2 = INPUT(port2); + double V2out = V1 + zl*I1; + double V1out = V2 + zl*I2; + OUTPUT(port1) = V1out + I1*zl; + OUTPUT(port2) = V2out + I2*zl; + + cm_analog_auto_partial(); + } + else if(ANALYSIS == AC) { + double frequency = RAD_FREQ/(2.0*M_PI); + calcPropagation(W,SModel,DModel,er,h,t,tand,rho,D,frequency); + + double complex g = alpha + beta*I; + double complex _Z11 = zl / ctanh(g*l); + double complex _Z21 = zl / csinh(g*l); + + z11.real = creal(_Z11); z11.imag = cimag(_Z11); + z21.real = creal(_Z21); z21.imag = cimag(_Z21); + + AC_GAIN(port1,port1) = z11; AC_GAIN(port2,port2) = z11; + AC_GAIN(port1,port2) = z21; AC_GAIN(port2,port1) = z21; + } + else if(ANALYSIS == TRANSIENT) { + calcPropagation(W,SModel,DModel,er,h,t,tand,rho,D,0); + double t = TIME; + double V1 = INPUT(V1sens); + double V2 = INPUT(V2sens); + double I1 = INPUT(port1); + double I2 = INPUT(port2); + double delay = l/(C0) * sqrt(ereff); + if (TModel == TRAN_FULL) { + append_state(&sim_points, t, V1, V2, I1, I2, 1.2*delay); + } + if (t > delay && TModel == TRAN_FULL) { + tline_state_t *pp = get_state(sim_points, t - delay); + if (pp != NULL) { + double V2out = pp->V1 + zl*(pp->I1); + double V1out = pp->V2 + zl*(pp->I2); + OUTPUT(port1) = V1out + I1*zl; + OUTPUT(port2) = V2out + I2*zl; + } + cm_analog_auto_partial(); + } else { + double V2out = V1 + zl*I1; + double V1out = V2 + zl*I2; + OUTPUT(port1) = V1out + I1*zl; + OUTPUT(port2) = V2out + I2*zl; + cm_analog_auto_partial(); + } + + } +} + diff --git a/src/xspice/icm/tlines/mlin/ifspec.ifs b/src/xspice/icm/tlines/mlin/ifspec.ifs new file mode 100644 index 000000000..1e3404e69 --- /dev/null +++ b/src/xspice/icm/tlines/mlin/ifspec.ifs @@ -0,0 +1,173 @@ +/* =========================================================================== +FILE ifspec.ifs + +(c) vadim Kuznetsov 2025 + +=========================================================================== */ + +NAME_TABLE: + +Spice_Model_Name: mlin +C_Function_Name: cm_mlin +Description: "Microstrip line" + + +PORT_TABLE: +Port_Name: port1 +Description: "Microstrip terminals" +Direction: inout +Default_Type: hd +Allowed_Types: [hd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: port2 +Description: "Microstrip terminals" +Direction: inout +Default_Type: hd +Allowed_Types: [hd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: V1sens +Description: "Sensing terminals" +Direction: in +Default_Type: vd +Allowed_Types: [vd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: V2sens +Description: "Sensisng terminals" +Direction: in +Default_Type: vd +Allowed_Types: [vd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + + +PARAMETER_TABLE: +Parameter_Name: l +Description: "length" +Data_Type: real +Default_Value: 1e-2 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +PARAMETER_TABLE: +Parameter_Name: w +Description: "width" +Data_Type: real +Default_Value: 1e-3 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +PARAMETER_TABLE: +Parameter_Name: model +Description: "Model type" +Data_Type: int +Default_Value: 0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +PARAMETER_TABLE: +Parameter_Name: disp +Description: "Dispersion type" +Data_Type: int +Default_Value: 0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: er +Description: "Substrate dielectric permittivity" +Data_Type: real +Default_Value: 9.8 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: h +Description: "Substrate thickness" +Data_Type: real +Default_Value: 1e-3 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: t +Description: "Metal strip thickness" +Data_Type: real +Default_Value: 35e-6 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: tand +Description: "Substrate dielectric loss" +Data_Type: real +Default_Value: 2e-4 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +PARAMETER_TABLE: +Parameter_Name: rho +Description: "Metal resistance" +Data_Type: real +Default_Value: 0.022e-6 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: d +Description: "RMS Substrate roughness" +Data_Type: real +Default_Value: 0.15e-6 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +PARAMETER_TABLE: +Parameter_Name: tranmodel +Description: "RMS Substrate roughness" +Data_Type: int +Default_Value: 0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + + + diff --git a/src/xspice/icm/tlines/modpath.lst b/src/xspice/icm/tlines/modpath.lst new file mode 100644 index 000000000..a7ce53ef9 --- /dev/null +++ b/src/xspice/icm/tlines/modpath.lst @@ -0,0 +1,4 @@ +mlin +tline +cpline +cpmlin diff --git a/src/xspice/icm/tlines/tline/cfunc.mod b/src/xspice/icm/tlines/tline/cfunc.mod new file mode 100644 index 000000000..61ec1f904 --- /dev/null +++ b/src/xspice/icm/tlines/tline/cfunc.mod @@ -0,0 +1,91 @@ +/* =========================================================================== + FILE cfunc.mod + + (c) Vadim Kuznetsov 2025 + + */ + +#include +#include +#include + +#include "msline_common.h" +#include "tline_common.h" + +static tline_state_t *sim_points = NULL; + + +void cm_tline (ARGS) +{ + Complex_t z11, z21; + + + /* how to get properties of this component, e.g. L, W */ + double z = PARAM(z); + double l = PARAM(l); + double a = PARAM(a); + + double alpha = pow(10,0.05*a); + alpha = log(alpha)/2.0; + + /* Initialize/access instance specific storage for capacitor voltage */ + if(INIT) { + + } + + /* Compute the output */ + if(ANALYSIS == DC) { + + double V1 = INPUT(V1sens); + double V2 = INPUT(V2sens); + double I1 = INPUT(in); + double I2 = INPUT(out); + double V2out = V1 + z*I1; + double V1out = V2 + z*I2; + OUTPUT(in) = V1out + I1*z; + OUTPUT(out) = V2out + I2*z; + + cm_analog_auto_partial(); + } + else if(ANALYSIS == AC) { + double beta = RAD_FREQ/C0; + double complex g = alpha + beta*I; + double complex _Z11 = z / ctanh(g*l); + double complex _Z21 = z / csinh (g*l); + + z11.real = creal(_Z11); + z11.imag = cimag(_Z11); + z21.real = creal(_Z21); + z21.imag = cimag(_Z21); + + + AC_GAIN(in, in) = z11; AC_GAIN(out,out) = z11; + AC_GAIN(in,out) = z21; AC_GAIN(out,in) = z21; + } + else if(ANALYSIS == TRANSIENT) { + double t = TIME; + double V1 = INPUT(V1sens); + double V2 = INPUT(V2sens); + double I1 = INPUT(in); + double I2 = INPUT(out); + double delay = l/(C0); + append_state(&sim_points, t, V1, V2, I1, I2, 1.2*delay); + if (t > delay) { + tline_state_t *pp = get_state(sim_points, t - delay); + if (pp != NULL) { + double V2out = pp->V1 + z*(pp->I1); + double V1out = pp->V2 + z*(pp->I2); + OUTPUT(in) = V1out + I1*z; + OUTPUT(out) = V2out + I2*z; + } + cm_analog_auto_partial(); + } else { + double V2out = V1 + z*I1; + double V1out = V2 + z*I2; + OUTPUT(in) = V1out + I1*z; + OUTPUT(out) = V2out + I2*z; + cm_analog_auto_partial(); + } + } +} + diff --git a/src/xspice/icm/tlines/tline/ifspec.ifs b/src/xspice/icm/tlines/tline/ifspec.ifs new file mode 100644 index 000000000..b3caa7491 --- /dev/null +++ b/src/xspice/icm/tlines/tline/ifspec.ifs @@ -0,0 +1,87 @@ +/* =========================================================================== +FILE ifspec.ifs + +(c) vadim Kuznetsov 2025 + +=========================================================================== */ + +NAME_TABLE: + +Spice_Model_Name: tline +C_Function_Name: cm_tline +Description: "Generic transmission line" + + +PORT_TABLE: +Port_Name: in +Description: "Terminals" +Direction: inout +Default_Type: hd +Allowed_Types: [hd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: out +Description: "Terminals" +Direction: inout +Default_Type: hd +Allowed_Types: [hd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: V1sens +Description: "Sensing terminals" +Direction: in +Default_Type: vd +Allowed_Types: [vd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PORT_TABLE: +Port_Name: V2sens +Description: "Sensisng terminals" +Direction: in +Default_Type: vd +Allowed_Types: [vd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + + + +PARAMETER_TABLE: +Parameter_Name: l +Description: "length" +Data_Type: real +Default_Value: 1.0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: z +Description: "characteristic impedance" +Data_Type: real +Default_Value: 50.0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: a +Description: "attenuation per length (dB)" +Data_Type: real +Default_Value: 0.0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + diff --git a/src/xspice/icm/tlines/udnpath.lst b/src/xspice/icm/tlines/udnpath.lst new file mode 100644 index 000000000..e69de29bb diff --git a/src/xspice/tlines/msline_common.c b/src/xspice/tlines/msline_common.c new file mode 100644 index 000000000..0cac78357 --- /dev/null +++ b/src/xspice/tlines/msline_common.c @@ -0,0 +1,337 @@ +/* msline_common.c + * common definitions for microstrip devices + * (c) Vadim Kuznetsov 2025 + */ + +#include +#include + +#include "tline_common.h" +#include "msline_common.h" + +/* This function calculates the quasi-static impedance of a microstrip + * line, the value of the effective dielectric constant and the + * effective width due to the finite conductor thickness for the given + * microstrip line and substrate properties. */ +void mslineAnalyseQuasiStatic (double W, double h, double t, + double er, int Model, + double *ZlEff, double *ErEff, + double *WEff) { + + double z, e; + + // default values + e = er; + z = z0; + *WEff = W; + + // WHEELER + if (Model == WHEELER) { + double a, b, c, d, x, dW1, dWr, Wr; + + // compute strip thickness effect + if (t != 0) { + dW1 = t / M_PI * log (4 * M_E / sqrt (sqr (t / h) + + sqr (M_1_PI / (W / t + 1.10)))); + } + else dW1 = 0; + dWr = (1 + 1 / er) / 2 * dW1; + Wr = W + dWr; *WEff =Wr; + + // compute characteristic impedance + if (W / h < 3.3) { + c = log (4 * h / Wr + sqrt (sqr (4 * h / Wr) + 2)); + b = (er - 1) / (er + 1) / 2 * (log (M_PI_2) + log (2 * M_2_PI) / er); + z = (c - b) * Z0 / M_PI / sqrt (2 * (er + 1)); + } + else { + c = 1 + log (M_PI_2) + log (Wr / h / 2 + 0.94); + d = M_1_PI / 2 * (1 + log (sqr (M_PI) / 16)) * (er - 1) / sqr (er); + x = 2 * M_LN2 / M_PI + Wr / h / 2 + (er + 1) / 2 / M_PI / er * c + d; + z = Z0 / 2 / x / sqrt (er); + } + + // compute effective dielectric constant + if (W / h < 1.3) { + a = log (8 * h / Wr) + sqr (Wr / h) / 32; + b = (er - 1) / (er + 1) / 2 * (log (M_PI_2) + log (2 * M_2_PI) / er); + e = (er + 1) / 2 * sqr (a / (a - b)); + } + else { + a = (er - 1) / 2 / M_PI / er * (log (2.1349 * Wr / h + 4.0137) - + 0.5169 / er); + b = Wr / h / 2 + M_1_PI * log (8.5397 * Wr / h + 16.0547); + e = er * sqr ((b - a) / b); + } + } + // SCHNEIDER + else if (Model == SCHNEIDER) { + + double dW = 0, u = W / h; + + // consider strip thickness equations + if (t != 0 && t < W / 2) { + double arg = (u < M_1_PI / 2) ? 2 * M_PI * W / t : h / t; + dW = t / M_PI * (1 + log (2 * arg)); + if (t / dW >= 0.75) dW = 0; + } + *WEff = W + dW; u = *WEff / h; + + // effective dielectric constant + e = (er + 1) / 2 + (er - 1) / 2 / sqrt (1 + 10 / u); + + // characteristic impedance + if (u < 1.0) { + z = M_1_PI / 2 * log (8 / u + u / 4); + } + else { + z = 1 / (u + 2.42 - 0.44 / u + pow ((1. - 1. / u), 6.)); + } + z = Z0 * z / sqrt (e); + } + // HAMMERSTAD and JENSEN + else if (Model == HAMMERSTAD) { + double a, b, du1, du, u, ur, u1, zr, z1; + + u = W / h; // normalized width + t = t / h; // normalized thickness + + // compute strip thickness effect + if (t != 0) { + du1 = t / M_PI * log (1 + 4 * M_E / t / sqr (coth (sqrt (6.517 * u)))); + } + else du1 = 0; + du = du1 * (1 + sech (sqrt (er - 1))) / 2; + u1 = u + du1; + ur = u + du; + *WEff = ur * h; + + // compute impedances for homogeneous medium + Hammerstad_zl (ur, &zr); + Hammerstad_zl (u1, &z1); + + // compute effective dielectric constant + Hammerstad_ab (ur, er, &a, &b); + Hammerstad_er (ur, er, a, b, &e); + + // compute final characteristic impedance and dielectric constant + // including strip thickness effects + z = zr / sqrt (e); + e = e * sqr (z1 / zr); + } + + *ZlEff = z; + *ErEff = e; +} + +/* This function calculates the frequency dependent value of the + * effective dielectric constant and the microstrip line impedance for + * the given frequency. */ +void mslineAnalyseDispersion (double W, double h, double er, + double ZlEff, double ErEff, + double frequency, int Model, + double* ZlEffFreq, + double* ErEffFreq) { + + double e, z; + + // default values + z = *ZlEffFreq = ZlEff; + e = *ErEffFreq = ErEff; + + // GETSINGER + if (Model == GETSINGER) { + Getsinger_disp (h, er, ErEff, ZlEff, frequency, &e, &z); + } + // SCHNEIDER + else if (Model == DISP_SCHNEIDER) { + double k, f; + k = sqrt (ErEff / er); + f = 4 * h * frequency / C0 * sqrt (er - 1); + f = sqr (f); + e = ErEff * sqr ((1 + f) / (1 + k * f)); + z = ZlEff * sqrt (ErEff / e); + } + // YAMASHITA + else if (Model == YAMASHITA) { + double k, f; + k = sqrt (er / ErEff); + f = 4 * h * frequency / C0 * sqrt (er - 1) * + (0.5 + sqr (1 + 2 * log10 (1 + W / h))); + e = ErEff * sqr ((1 + k * pow (f, 1.5) / 4) / (1 + pow (f, 1.5) / 4)); + } + // KOBAYASHI + else if (Model == KOBAYASHI) { + double n, no, nc, fh, fk; + fk = C0 * atan (er * sqrt ((ErEff - 1) / (er - ErEff))) / + (2 * M_PI * h * sqrt (er - ErEff)); + fh = fk / (0.75 + (0.75 - 0.332 / pow (er, 1.73)) * W / h); + no = 1 + 1 / (1 + sqrt (W / h)) + 0.32 * cubic (1 / (1 + sqrt (W / h))); + if (W / h < 0.7) { + nc = 1 + 1.4 / (1 + W / h) * (0.15 - 0.235 * + exp (-0.45 * frequency / fh)); + } + else nc = 1; + n = no * nc < 2.32 ? no * nc : 2.32; + e = er - (er - ErEff) / (1 + pow (frequency / fh, n)); + } + // PRAMANICK and BHARTIA + else if (Model == PRAMANICK) { + double Weff, We, f; + f = 2 * MU0 * h * frequency * sqrt (ErEff / er) / ZlEff; + e = er - (er - ErEff) / (1 + sqr (f)); + Weff = Z0 * h / ZlEff / sqrt (ErEff); + We = W + (Weff - W) / (1 + sqr (f)); + z = Z0 * h / We / sqrt (e); + } + // HAMMERSTAD and JENSEN + else if (Model == DISP_HAMMERSTAD) { + double f, g; + g = sqr (M_PI) / 12 * (er - 1) / ErEff * sqrt (2 * M_PI * ZlEff / Z0); + f = 2 * MU0 * h * frequency / ZlEff; + e = er - (er - ErEff) / (1 + g * sqr (f)); + z = ZlEff * sqrt (ErEff / e) * (e - 1) / (ErEff - 1); + } + // KIRSCHNING and JANSEN + else if (Model == DISP_KIRSCHING) { + double r17, u = W / h, fn = frequency * h / 1e6; + + // dispersion of dielectric constant + Kirschning_er (u, fn, er, ErEff, &e); + + // dispersion of characteristic impedance + Kirschning_zl (u, fn, er, ErEff, e, ZlEff, &r17, &z); + } + + *ZlEffFreq = z; + *ErEffFreq = e; +} + + +/* Computes the exponent factors a(u) and b(er) used within the + * effective relative dielectric constant calculations for single and + * coupled microstrip lines by Hammerstad and Jensen. */ +void Hammerstad_ab (double u, double er, double *a, + double *b) { + *a = 1 + log ((quadr (u) + sqr (u / 52)) / (quadr (u) + 0.432)) / 49 + + log (1 + cubic (u / 18.1)) / 18.7; + *b = 0.564 * pow ((er - 0.9) / (er + 3), 0.053); +} + +/* The function computes the effective dielectric constant of a single + * microstrip. The equation is used in single and coupled microstrip + * calculations. */ +void Hammerstad_er (double u, double er, double a, + double b, double* e) { + *e = (er + 1) / 2 + (er - 1) / 2 * pow (1 + 10 / u, -a * b); +} + +/* This function computes the characteristic impedance of single + * microstrip line based upon the given width-height ratio. The + * equation is used in single and coupled microstrip calculations as + * well. */ +void Hammerstad_zl (double u, double *zl) { + double fu = 6 + (2 * M_PI - 6) * exp (- pow (30.666 / u, 0.7528)); + *zl = Z0 / 2 / M_PI * log (fu / u + sqrt (1 + sqr (2 / u))); +} + +/* Calculates dispersion effects for effective dielectric constant and + * characteristic impedance as defined by Getsinger (for single and + * coupled microstrips). */ +void Getsinger_disp (double h, double er, double ErEff, + double ZlEff, double frequency, + double *e, double *z) { + double g, f, d; + g = 0.6 + 0.009 * ZlEff; + f = frequency * 2 * MU0 * h / ZlEff; + *e = er - (er - ErEff) / (1 + g * sqr (f)); + d = (er - *e) * (*e - ErEff) / *e / (er - ErEff); + *z = ZlEff * sqrt (*e / ErEff) / (1 + d); // group delay model +} + +/* This function computes the dispersion of the effective dielectric + * constant of a single microstrip line. It is defined in a separate + * function because it is used within the coupled microstrip lines as + * well. */ +void Kirschning_er (double u, double fn, double er, + double ErEff, double* ErEffFreq) { + double p, p1, p2, p3, p4; + p1 = 0.27488 + (0.6315 + 0.525 / pow (1. + 0.0157 * fn, 20.)) * u - + 0.065683 * exp (-8.7513 * u); + p2 = 0.33622 * (1 - exp (-0.03442 * er)); + p3 = 0.0363 * exp (-4.6 * u) * (1 - exp (- pow (fn / 38.7, 4.97))); + p4 = 1 + 2.751 * (1 - exp (- pow (er / 15.916, 8.))); + p = p1 * p2 * pow ((0.1844 + p3 * p4) * fn, 1.5763); + *ErEffFreq = er - (er - ErEff) / (1 + p); +} + +/* Computes dispersion effects of characteristic impedance of a single + * microstrip line according to Kirschning and Jansen. Also used in + * coupled microstrip lines calculations. */ +void Kirschning_zl (double u, double fn, double er, + double ErEff, double ErEffFreq, + double ZlEff, double* r17, + double* ZlEffFreq) { + double r1, r2, r3, r4, r5, r6, r7, r8, r9, r10; + double r11, r12, r13, r14, r15, r16; + r1 = 0.03891 * pow (er, 1.4); + r2 = 0.267 * pow (u, 7.); + r3 = 4.766 * exp (-3.228 * pow (u, 0.641)); + r4 = 0.016 + pow (0.0514 * er, 4.524); + r5 = pow (fn / 28.843, 12.); + r6 = 22.20 * pow (u, 1.92); + r7 = 1.206 - 0.3144 * exp (-r1) * (1 - exp (-r2)); + r8 = 1 + 1.275 * (1 - exp (-0.004625 * r3 * + pow (er, 1.674) * pow (fn / 18.365, 2.745))); + r9 = 5.086 * r4 * r5 / (0.3838 + 0.386 * r4) * + exp (-r6) / (1 + 1.2992 * r5) * + pow (er - 1., 6.) / (1 + 10 * pow (er - 1., 6.)); + r10 = 0.00044 * pow (er, 2.136) + 0.0184; + r11 = pow (fn / 19.47, 6.) / (1 + 0.0962 * pow (fn / 19.47, 6.)); + r12 = 1 / (1 + 0.00245 * sqr (u)); + r13 = 0.9408 * pow (ErEffFreq, r8) - 0.9603; + r14 = (0.9408 - r9) * pow (ErEff, r8) - 0.9603; + r15 = 0.707 * r10 * pow (fn / 12.3, 1.097); + r16 = 1 + 0.0503 * sqr (er) * r11 * (1 - exp (- pow (u / 15., 6.))); + *r17 = r7 * (1 - 1.1241 * r12 / r16 * + exp (-0.026 * pow (fn, 1.15656) - r15)); + *ZlEffFreq = ZlEff * pow (r13 / r14, *r17); +} + +/* The function calculates the conductor and dielectric losses of a + * single microstrip line. */ +void analyseLoss (double W, double t, double er, + double rho, double D, double tand, + double ZlEff1, double ZlEff2, + double ErEff, + double frequency, int Model, + double* ac, double* ad) { + *ac = *ad = 0; + + // HAMMERSTAD and JENSEN + if (Model == HAMMERSTAD) { + double Rs, ds, l0, Kr, Ki; + + // conductor losses + if (t != 0.0) { + Rs = sqrt (M_PI * frequency * MU0 * rho); // skin resistance + ds = rho / Rs; // skin depth + // valid for t > 3 * ds + if (t < 3 * ds && frequency != 0) { + fprintf (stderr, + "WARNING: conductor loss calculation invalid for line " + "height t (%g) < 3 * skin depth (%g)\n", t, 3 * ds); + } + // current distribution factor + Ki = exp (-1.2 * pow ((ZlEff1 + ZlEff2) / 2 / Z0, 0.7)); + // D is RMS surface roughness + Kr = 1 + M_2_PI * atan (1.4 * sqr (D / ds)); + *ac = Rs / (ZlEff1 * W) * Ki * Kr; + } + + // dielectric losses + l0 = C0 / frequency; + *ad = M_PI * er / (er - 1) * (ErEff - 1) / sqrt (ErEff) * tand / l0; + } +} + diff --git a/src/xspice/tlines/msline_common.h b/src/xspice/tlines/msline_common.h new file mode 100644 index 000000000..a4c72c3a4 --- /dev/null +++ b/src/xspice/tlines/msline_common.h @@ -0,0 +1,60 @@ +/* msline_common.h + * common definitions for microstrip devices + * (c) Vadim Kuznetsov 2025 + */ + + +#ifndef MSLINE_COMMON_H +#define MSLINE_COMMON_H + +//TRAN model +#define TRAN_DC 0 +#define TRAN_FULL 1 + +// MS line model +#define HAMMERSTAD 0 +#define KIRSCHING 1 +#define WHEELER 2 +#define SCHNEIDER 3 + + +// Dispersion model +#define DISP_KIRSCHING 0 +#define KOBAYASHI 1 +#define YAMASHITA 2 +#define DISP_HAMMERSTAD 3 +#define GETSINGER 4 +#define DISP_SCHNEIDER 5 +#define PRAMANICK 6 + +void Hammerstad_ab (double, double, + double*, double*); +void Hammerstad_er (double, double, double, + double, double*); +void Hammerstad_zl (double, double*); +void Getsinger_disp (double, double, double, + double, double, + double*, double*); +void Kirschning_er (double, double, double, + double, double*); +void Kirschning_zl (double, double, double, + double, double, double, + double*, double*); + +void mslineAnalyseQuasiStatic (double W, double h, double t, + double er, int Model, + double *ZlEff, double *ErEff, + double *WEff); + +void mslineAnalyseDispersion (double W, double h, double er, + double ZlEff, double ErEff, + double frequency, int Model, + double* ZlEffFreq, + double* ErEffFreq); + +void analyseLoss (double, double, double, double, + double, double, double, double, + double, double, int, + double*, double*); + +#endif diff --git a/src/xspice/tlines/tline_common.c b/src/xspice/tlines/tline_common.c new file mode 100644 index 000000000..53bd4293f --- /dev/null +++ b/src/xspice/tlines/tline_common.c @@ -0,0 +1,86 @@ +/* tline_common.c + * common definitions for all transmission lines + * (c) Vadim Kuznetsov 2025 + */ + +#include +#include + +#include "tline_common.h" + +void append_state(tline_state_t **first, double time, double V1, double V2, + double I1, double I2, double tmax) +{ + tline_state_t *pp = (tline_state_t *) malloc(sizeof(tline_state_t)); + + pp->next = NULL; + pp->time = time; + pp->V1 = V1; pp->I1 = I1; + pp->V2 = V2; pp->I2 = I2; + + if (*first == NULL) { + *first = pp; + } else { + tline_state_t *pn = *first; + while (pn->next != NULL) { + pn = pn->next; + } + pn->next = pp; + + double t0 = (*first)->time; + + if ((time - t0) > tmax) { + tline_state_t *new_first = (*first)->next; + free(*first); + *first = new_first; + } + } +} + +tline_state_t *get_state(tline_state_t *first, double time) +{ + tline_state_t *pp = first; + while (pp != NULL && pp->time < time) { + pp = pp->next; + } + return pp; +} + + +void append_cpline_state(cpline_state_t **first, double time, double *Vp, double *Ip, double tmax) +{ + cpline_state_t *pp = (cpline_state_t *) malloc(sizeof(cpline_state_t)); + + pp->next = NULL; + pp->time = time; + memcpy(pp->Vp, Vp, PORT_NUM*sizeof(double)); + memcpy(pp->Ip, Ip, PORT_NUM*sizeof(double)); + + if (*first == NULL) { + *first = pp; + } else { + cpline_state_t *pn = *first; + while (pn->next != NULL) { + pn = pn->next; + } + pn->next = pp; + + double t0 = (*first)->time; + + if ((time - t0) > tmax) { + cpline_state_t *new_first = (*first)->next; + free(*first); + *first = new_first; + } + } +} + +cpline_state_t *find_cpline_state(cpline_state_t *first, double time) +{ + cpline_state_t *pp = first; + while (pp != NULL && pp->time < time) { + pp = pp->next; + } + return pp; +} + diff --git a/src/xspice/tlines/tline_common.h b/src/xspice/tlines/tline_common.h new file mode 100644 index 000000000..f531e54c3 --- /dev/null +++ b/src/xspice/tlines/tline_common.h @@ -0,0 +1,63 @@ +/* tline_common.h + * common definitions for all transmission lines + * (c) Vadim Kuznetsov 2025 + */ + + +#ifndef TLINE_COMMON_H +#define TLINE_COMMON_H + +// Constants +#define Z0 (120*M_PI) +#define z0 50.0 +#define MU0 (4*M_PI*1e-7) + +#define C0 299792458.0 + +#define GMIN 1e-12 + + +// Functions +#define sqr(x) (x*x) +#define cubic(x) (x*x*x) +#define quadr(x) (x*x*x*x) + +#define coth(x) (1.0/tanh(x)) +#define sech(x) (1.0/cosh(x)) +#define cosech(x) (1.0/sinh(x)) + +// Data structures to hold transient state + +typedef struct tline_state { + double time; + double I1; + double I2; + double V1; + double V2; + + struct tline_state *next; +} tline_state_t; + +// Functions to retrieve previous transient state +void append_state(tline_state_t **first, double time, double V1, double V2, + double I1, double I2, double tmax); + +tline_state_t *get_state(tline_state_t *first, double time); + +#define PORT_NUM 4 + +typedef struct cpline_state { + double time; + double Ip[PORT_NUM]; + double Vp[PORT_NUM]; + + struct cpline_state *next; +} cpline_state_t; + +void append_cpline_state(cpline_state_t **first, double time, double *Vp, double *Ip, double tmax); + +cpline_state_t *find_cpline_state(cpline_state_t *first, double time); + + + +#endif From 55f81b9ecd393e0e88ebb69f438b6965e55c1d7f Mon Sep 17 00:00:00 2001 From: Vadim Kuznetsov Date: Mon, 9 Jun 2025 20:36:23 +0300 Subject: [PATCH 16/38] Add examples --- .../xspice/transmission_lines/cpline_ac.cir | 18 +++++++++++++ .../xspice/transmission_lines/cpline_tran.cir | 23 +++++++++++++++++ .../xspice/transmission_lines/cpmline_ac.cir | 18 +++++++++++++ examples/xspice/transmission_lines/mlin.cir | 22 ++++++++++++++++ .../xspice/transmission_lines/mlin_tran.cir | 25 +++++++++++++++++++ 5 files changed, 106 insertions(+) create mode 100644 examples/xspice/transmission_lines/cpline_ac.cir create mode 100644 examples/xspice/transmission_lines/cpline_tran.cir create mode 100644 examples/xspice/transmission_lines/cpmline_ac.cir create mode 100644 examples/xspice/transmission_lines/mlin.cir create mode 100644 examples/xspice/transmission_lines/mlin_tran.cir diff --git a/examples/xspice/transmission_lines/cpline_ac.cir b/examples/xspice/transmission_lines/cpline_ac.cir new file mode 100644 index 000000000..f1ca315a3 --- /dev/null +++ b/examples/xspice/transmission_lines/cpline_ac.cir @@ -0,0 +1,18 @@ +* Coupled lines SP + +V1 p1 0 dc 0 ac 1 portnum 1 z0 50 +V2 p2 0 dc 0 ac 1 portnum 2 z0 50 +V3 p3 0 dc 0 ac 1 portnum 3 z0 50 +V4 p4 0 dc 0 ac 1 portnum 4 z0 50 + +A1 %hd(p1 0) %hd(p2 0) %hd(p3 0) %hd(p4 0) CPLINE1 +.MODEL CPLINE1 CPLINE(ze=84.48 zo=53.99 l=25e-3 ere=3.34 ero=2.829 ao=0 ae=0) + +.control + +sp lin 100 0.2e9 4.2e9 + +plot abs(s_1_1) abs(s_3_1) abs(s_2_1) abs(s_4_1) +plot abs(s_2_1) + +.endc diff --git a/examples/xspice/transmission_lines/cpline_tran.cir b/examples/xspice/transmission_lines/cpline_tran.cir new file mode 100644 index 000000000..c577354e3 --- /dev/null +++ b/examples/xspice/transmission_lines/cpline_tran.cir @@ -0,0 +1,23 @@ +* Coupled lines SP + +V1 1 0 PULSE(0 1 1n 10p 10p 980p) + +R2 p1 1 0.1 + +R1 p4 0 50.0 +R3 p3 0 50.0 +R4 p2 0 50.0 + +A1 %hd(p1 0) %hd(p2 0) %hd(p3 0) %hd(p4 0) %vd(p1 0) %vd(p2 0) %vd(p3 0) %vd(p4 0) CPLINE1 +.MODEL CPLINE1 CPLINE(ze=100 zo=50 l=100e-3 ere=1 ero=1 ao=0 ae=0) + +.control + +tran 10p 5n + +let v2 = -v(p2) +let v3 = -v(p3) + +plot v(1) v(p2) v(p3) v(p4) + +.endc diff --git a/examples/xspice/transmission_lines/cpmline_ac.cir b/examples/xspice/transmission_lines/cpmline_ac.cir new file mode 100644 index 000000000..035d17984 --- /dev/null +++ b/examples/xspice/transmission_lines/cpmline_ac.cir @@ -0,0 +1,18 @@ +* Coupled lines SP + +V1 p1 0 dc 0 ac 1 portnum 1 z0 50 +V2 p2 0 dc 0 ac 1 portnum 2 z0 50 +V3 p3 0 dc 0 ac 1 portnum 3 z0 50 +V4 p4 0 dc 0 ac 1 portnum 4 z0 50 + +A1 %hd(p1 0) %hd(p2 0) %hd(p3 0) %hd(p4 0) %vd(p1 0) %vd(p2 0) %vd(p3 0) %vd(p4 0) CPMLIN1 +.MODEL CPMLIN1 CPMLIN(w=1e-3 l=20e-3 s=0.3e-3 er=9.8 h=1e-3 t=35e-6 tand=1e-3 rho=0.022e-6 d1=0.15e-6 model=0 disp=0) + +.control + +sp lin 100 0.2e9 4.2e9 + +plot abs(s_1_1) abs(s_3_1) abs(s_2_1) abs(s_4_1) +plot abs(s_3_1) + +.endc diff --git a/examples/xspice/transmission_lines/mlin.cir b/examples/xspice/transmission_lines/mlin.cir new file mode 100644 index 000000000..e57fa5055 --- /dev/null +++ b/examples/xspice/transmission_lines/mlin.cir @@ -0,0 +1,22 @@ +* MLIN test + +V1 1 0 AC 1 DC 1 +R1 in 1 50.0 +R2 out 0 1000.1 +A1 %hd(in 0) %hd(out 0) %vd(in 0) %vd(out 0) MLIN1 +.MODEL MLIN1 MLIN(w=1e-3 l=10e-3 er=9.8 h=1e-3 t=35e-6 tand=1e-3 rho=0.022e-6 d=0.15e-6 model=0 disp=0) + +.control + +op +print all + +ac LIN 200 1e9 12e9 + +let z = v(in)/-i(v1) +let y = imag(z) +let r = real(z) +plot abs(z) ylog +plot y r + +.endc diff --git a/examples/xspice/transmission_lines/mlin_tran.cir b/examples/xspice/transmission_lines/mlin_tran.cir new file mode 100644 index 000000000..8db27d820 --- /dev/null +++ b/examples/xspice/transmission_lines/mlin_tran.cir @@ -0,0 +1,25 @@ +* MLIN test + +V1 1 4 PULSE(0 1 1n 10p 10p 980p) +V3 4 0 DC 1 +R1 out 2 20.0 +V2 2 0 0 +R2 in 1 1m +*R3 in ins 1e12 +*R4 out outs 1e12 +A1 %hd(in 0) %hd(out 0) %vd(in 0) %vd(out 0) MLIN1 +.MODEL MLIN1 MLIN(w=1e-3 l=50e-3 er=9.8 h=1e-3 t=35e-6 tand=1e-3 rho=0.022e-6 d1=0.15e-6 model=0 disp=0 tranmodel=1) +*A1 %hd(in 0) %hd(out 0) %vd(in 0) %vd(out 0) TLIN1 +*.MODEL TLIN1 TLINE(l=100e-3 z=50.0 a=0.0) + +.control + +*op +*print all + +tran 10p 5n + +plot v(in) v(out) +plot -i(v1) i(V2) + +.endc From 2b7e29179baf9229150445e0e29e29dd6c5574bc Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 8 Jun 2025 10:09:28 +0200 Subject: [PATCH 17/38] Add a monitoring output the the seegen instance --- examples/xspice/see/CMOSOpAmp/CMOS-OP1.cir | 4 +-- examples/xspice/see/CMOSOpAmp/cmos_sub.mod | 4 +-- examples/xspice/see/CMOSOpAmp/seegen4.mod | 4 +-- .../xspice/see/ihp_simple_sram_seegen.net | 2 +- .../see/ihp_simple_sram_seegen_ctrl.net | 2 +- .../see/ihp_simple_sram_seegen_subckt.net | 4 +-- .../ihp_simple_sram_seegen_subckt_vary.net | 4 +-- examples/xspice/see/repeat_loop_seegen.net | 4 +-- examples/xspice/see/seegen_cm1.cir | 2 +- src/xspice/icm/xtradev/seegenerator/cfunc.mod | 6 +++-- .../icm/xtradev/seegenerator/ifspec.ifs | 26 ++++++++++++++----- 11 files changed, 38 insertions(+), 24 deletions(-) diff --git a/examples/xspice/see/CMOSOpAmp/CMOS-OP1.cir b/examples/xspice/see/CMOSOpAmp/CMOS-OP1.cir index 2e2b2e480..ba2f849a0 100644 --- a/examples/xspice/see/CMOSOpAmp/CMOS-OP1.cir +++ b/examples/xspice/see/CMOSOpAmp/CMOS-OP1.cir @@ -7,7 +7,7 @@ XMN9 Vbias Vbias 0 0 NCH W=5u L=1.4u V5 in+ 0 DC 1.65 R1 out in- 100k R2 in in- 20k -V4 in 0 DC 1.65 SIN( 1.65 100m 1k 0 0 0 ) AC 1 +V4 in 0 DC 1.65 SIN( 1.65 100m 20k 0 0 0 ) AC 1 XMN3 out Vbias 0 0 NCH W=17.4u L=1.4u C2 out 0 2p XMP2 out VGP2 Vcc Vcc PCH W=14.5u L=1.4u @@ -23,7 +23,7 @@ XMP8 VGP2 VGP4P8 Vcc Vcc PCH W=2.8u L=1.4u set xbrushwidth=2 tran 20n 2m -plot v(VGP4P8) +plot v(VGP4P8) v(xu1.mon)*5000+3 plot in out ac dec 10 1 1Meg diff --git a/examples/xspice/see/CMOSOpAmp/cmos_sub.mod b/examples/xspice/see/CMOSOpAmp/cmos_sub.mod index c72096db9..a38707089 100644 --- a/examples/xspice/see/CMOSOpAmp/cmos_sub.mod +++ b/examples/xspice/see/CMOSOpAmp/cmos_sub.mod @@ -4,10 +4,10 @@ .include modelcard.pmos .subckt NCH D G S B W=1 L=1 -MN1 D G S B N1 W={W} L={L} AS={3*L*W} AD={3*L*W} PS={6*L+W} AS={6*L+W} +MN1 D G S B N1 W={W} L={L} AS={3*L*W} AD={3*L*W} PS={6*L+W} PD={6*L+W} .ends .subckt PCH D G S B W=1 L=1 -MP1 D G S B P1 W={W} L={L} AS={3*L*W} AD={3*L*W} PS={6*L+W} AS={6*L+W} +MP1 D G S B P1 W={W} L={L} AS={3*L*W} AD={3*L*W} PS={6*L+W} PD={6*L+W} .ends diff --git a/examples/xspice/see/CMOSOpAmp/seegen4.mod b/examples/xspice/see/CMOSOpAmp/seegen4.mod index c29d787fe..55969ce88 100644 --- a/examples/xspice/see/CMOSOpAmp/seegen4.mod +++ b/examples/xspice/see/CMOSOpAmp/seegen4.mod @@ -5,6 +5,6 @@ .param Inull = 'tochar/(tfall-trise)' * Eponential current source without control input * only NMOS nodes with reference GND (substrate). -aseegen1 NULL [%i(n1) %i(n2) %i(n3) %i(n4)] seemod1 -.model seemod1 seegen (tdelay = 0.62m tperiod=0.1m inull='Inull' perlim=FALSE) +aseegen1 NULL mon [%i(n1) %i(n2) %i(n3) %i(n4)] seemod1 +.model seemod1 seegen (tdelay = 0.62m tperiod=0.01m inull='Inull' perlim=FALSE) .ends \ No newline at end of file diff --git a/examples/xspice/see/ihp_simple_sram_seegen.net b/examples/xspice/see/ihp_simple_sram_seegen.net index 26d7e5a33..d6e8900ff 100644 --- a/examples/xspice/see/ihp_simple_sram_seegen.net +++ b/examples/xspice/see/ihp_simple_sram_seegen.net @@ -21,7 +21,7 @@ Vbln bln 0 0 *V1 in gnd pulse(0 'vdd' 0p 200p 100p 5n 10n) * Eponential current source without control input -aseegen1 NULL [%id(n1 m1) %id(n2 m2) %id(n1 m1) %id(n2 m2)] seemod1 +aseegen1 NULL mon [%id(n1 m1) %id(n2 m2) %id(n1 m1) %id(n2 m2)] seemod1 .model seemod1 seegen (tdelay = 11n tperiod=25n inull='Inull') Xnot1 n1 vdd vss n2 not1 diff --git a/examples/xspice/see/ihp_simple_sram_seegen_ctrl.net b/examples/xspice/see/ihp_simple_sram_seegen_ctrl.net index ce13a7dca..e7f5b6ca7 100644 --- a/examples/xspice/see/ihp_simple_sram_seegen_ctrl.net +++ b/examples/xspice/see/ihp_simple_sram_seegen_ctrl.net @@ -19,7 +19,7 @@ Vbln bln 0 0 Vctrl ctrl 0 pulse (0 1 10n 1n 1n 1 1) * Exponential current source with control input -aseegen1 ctrl [%id(n1 m1) %id(n2 m2) %id(n1 m1) %id(n2 m2)] seemod1 +aseegen1 ctrl mon [%id(n1 m1) %id(n2 m2) %id(n1 m1) %id(n2 m2)] seemod1 .model seemod1 seegen (tdelay = 8n tperiod=25n) Xnot1 n1 vdd vss n2 not1 diff --git a/examples/xspice/see/ihp_simple_sram_seegen_subckt.net b/examples/xspice/see/ihp_simple_sram_seegen_subckt.net index 7b689f852..f927e4344 100644 --- a/examples/xspice/see/ihp_simple_sram_seegen_subckt.net +++ b/examples/xspice/see/ihp_simple_sram_seegen_subckt.net @@ -19,10 +19,10 @@ Vbl1 bl1 0 'vdd' Vbl2 bl2 0 0 **** SEE generator without control input, double exponential current sources -aseegen1 NULL [%id(xcell.n1 m1) %id(xcell.n2 m2) %id(xcell.n1 m1) %id(xcell.n2 m2)] seemod1 +aseegen1 NULL mon [%id(xcell.n1 m1) %id(xcell.n2 m2) %id(xcell.n1 m1) %id(xcell.n2 m2)] seemod1 .model seemod1 seegen (tdelay = 11n tperiod=25n let='let' cdepth='cdepth' tfall='tfall' trise='trise') * alternative syntax, if no current measurement required and reference nodes are GND -*aseegen1 NULL [%i(xcell.n1) %i(xcell.n2) %i(xcell.n1) %i(xcell.n2)] seemod1 +*aseegen1 NULL mon [%i(xcell.n1) %i(xcell.n2) %i(xcell.n1) %i(xcell.n2)] seemod1 **** the SRAM cell Xcell bl1 bl2 wl vdd vss srcell diff --git a/examples/xspice/see/ihp_simple_sram_seegen_subckt_vary.net b/examples/xspice/see/ihp_simple_sram_seegen_subckt_vary.net index 5bd6c80da..30b57790d 100644 --- a/examples/xspice/see/ihp_simple_sram_seegen_subckt_vary.net +++ b/examples/xspice/see/ihp_simple_sram_seegen_subckt_vary.net @@ -23,10 +23,10 @@ Vbl1 bl1 0 'vdd' Vbl2 bl2 0 0 **** SEE generator without control input, double exponential current sources -aseegen1 NULL [%id(xcell.n1 m1) %id(xcell.n2 m2) %id(xcell.n1 m1) %id(xcell.n2 m2)] seemod1 +aseegen1 NULL mon [%id(xcell.n1 m1) %id(xcell.n2 m2) %id(xcell.n1 m1) %id(xcell.n2 m2)] seemod1 .model seemod1 seegen (tdelay = 11n tperiod=25n tfall='tfall' trise='trise' let='let' cdepth='d') * alternative syntax, if no current measurement required and reference nodes are GND -*aseegen1 NULL [%i(xcell.n1) %i(xcell.n2) %i(xcell.n1) %i(xcell.n2)] seemod1 +*aseegen1 NULL mon [%i(xcell.n1) %i(xcell.n2) %i(xcell.n1) %i(xcell.n2)] seemod1 **** the SRAM cell Xcell bl1 bl2 wl vdd vss srcell diff --git a/examples/xspice/see/repeat_loop_seegen.net b/examples/xspice/see/repeat_loop_seegen.net index 222814719..9f212ff07 100644 --- a/examples/xspice/see/repeat_loop_seegen.net +++ b/examples/xspice/see/repeat_loop_seegen.net @@ -11,10 +11,10 @@ R4 n4 0 1e4 **** SEE generator without control input, double exponential current sources -aseegen1 NULL [%id(n1 0) %id(n2 0) %id(n3 0) %id(n4 0)] seemod1 +aseegen1 NULL mon [%id(n1 0) %id(n2 0) %id(n3 0) %id(n4 0)] seemod1 .model seemod1 seegen (tdelay = 11n tperiod=25n let='let' cdepth='cdepth' trise='trise' tfall='tfall') * alternative syntax, if no current measurement required and reference nodes are GND -*aseegen1 NULL [%i(n1) %i(n2) %i(n3) %i(n4)] seemod1 +*aseegen1 NULL mon [%i(n1) %i(n2) %i(n3) %i(n4)] seemod1 diff --git a/examples/xspice/see/seegen_cm1.cir b/examples/xspice/see/seegen_cm1.cir index a4bd7e371..8d4915e78 100644 --- a/examples/xspice/see/seegen_cm1.cir +++ b/examples/xspice/see/seegen_cm1.cir @@ -1,6 +1,6 @@ Test of seegen code model -aseegen1 NULL [%id(n1 p1) %id(n2 p2) %id(n3 p3)] seemod1 +aseegen1 NULL mon [%id(n1 p1) %id(n2 p2) %id(n3 p3)] seemod1 .model seemod1 seegen (tdelay = 5n tperiod=4.5n) Rsee1 n1 0 1 diff --git a/src/xspice/icm/xtradev/seegenerator/cfunc.mod b/src/xspice/icm/xtradev/seegenerator/cfunc.mod index 11bee5c74..5f21e626b 100644 --- a/src/xspice/icm/xtradev/seegenerator/cfunc.mod +++ b/src/xspice/icm/xtradev/seegenerator/cfunc.mod @@ -222,8 +222,10 @@ void cm_seegen(ARGS) /* structure holding parms, *last_t_value = 1e12; /* stop any output */ } } - if (*pulse_number - 1 < PORT_SIZE(out)) - OUTPUT(out[*pulse_number - 1]) = out; + if (*pulse_number - 1 < PORT_SIZE(out)) { + OUTPUT(out[*pulse_number - 1]) = out; + OUTPUT(mon) = out; + } } } diff --git a/src/xspice/icm/xtradev/seegenerator/ifspec.ifs b/src/xspice/icm/xtradev/seegenerator/ifspec.ifs index 58d28f039..cee53b78f 100644 --- a/src/xspice/icm/xtradev/seegenerator/ifspec.ifs +++ b/src/xspice/icm/xtradev/seegenerator/ifspec.ifs @@ -29,14 +29,26 @@ Description: "single event effect generator" PORT_TABLE: -Port_Name: ctrl out -Description: "control input" "output" +Port_Name: ctrl mon +Description: "control input" "monitor" Direction: in out -Default_Type: v i -Allowed_Types: [v,vd,i,id] [i,id] -Vector: no yes -Vector_Bounds: - [1 -] -Null_Allowed: yes no +Default_Type: v v +Allowed_Types: [v,vd,i,id] [v] +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + + +PORT_TABLE: + +Port_Name: out +Description: "output" +Direction: out +Default_Type: i +Allowed_Types: [i,id] +Vector: yes +Vector_Bounds: [1 -] +Null_Allowed: no PARAMETER_TABLE: From 63f5d102ec1dae5d46783346472edc25d2d97494 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 8 Jun 2025 11:09:17 +0200 Subject: [PATCH 18/38] No autostart when ctrl is set. Fix a bug when repeating the sequence. --- src/xspice/icm/xtradev/seegenerator/cfunc.mod | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/xspice/icm/xtradev/seegenerator/cfunc.mod b/src/xspice/icm/xtradev/seegenerator/cfunc.mod index 5f21e626b..c9855d549 100644 --- a/src/xspice/icm/xtradev/seegenerator/cfunc.mod +++ b/src/xspice/icm/xtradev/seegenerator/cfunc.mod @@ -169,7 +169,11 @@ void cm_seegen(ARGS) /* structure holding parms, /* Allocate storage for last_t_value */ STATIC_VAR(last_t_value) = (double *) malloc(sizeof(double)); last_t_value = (double *) STATIC_VAR(last_t_value); - *last_t_value = tdelay; + /* no start if ctrl is set */ + if (PORT_NULL(ctrl)) + *last_t_value = tdelay; + else + *last_t_value = 1e12; STATIC_VAR(pulse_number) = (int *) malloc(sizeof(int)); pulse_number = (int *) STATIC_VAR(pulse_number); *pulse_number = 1; @@ -187,10 +191,12 @@ void cm_seegen(ARGS) /* structure holding parms, pulse_number = (int *) STATIC_VAR(pulse_number); last_ctrl = (double *) STATIC_VAR(last_ctrl); + /* reset the pulse sequence, to start anew upon a rising ctrl */ if (*last_ctrl < ctrlthres && ctrl >= ctrlthres) { - *last_t_value = *last_t_value + tcurr; - *last_ctrl = ctrl; + *last_t_value = tcurr + tdelay; + *pulse_number = 1; } + *last_ctrl = ctrl; /* the double exponential current pulse function */ if (tcurr < *last_t_value) From 31d58e47a03e47689d1a1340f5ec3d9a9badf88d Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 8 Jun 2025 11:20:24 +0200 Subject: [PATCH 19/38] Add ouput 'mon' --- README.SEEgenerator | 47 +++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/README.SEEgenerator b/README.SEEgenerator index 12c8d3858..af2d02fd6 100644 --- a/README.SEEgenerator +++ b/README.SEEgenerator @@ -14,14 +14,18 @@ Set up the SEEgenerator by adding for example .param d = 1 * LET (linear energy transfer) in MeV*cm²/mg .param let = 12 -aseegen1 NULL [%id(xcell.n1 m1) %id(xcell.n2 m2) %id(xcell.n1 m1) %id(xcell.n2 m2)] seemod1 +aseegen1 NULL mon [%id(xcell.n1 m1) %id(xcell.n2 m2) %id(xcell.n1 m1) %id(xcell.n2 m2)] seemod1 .model seemod1 seegen (tdelay = 11n tperiod=25n let='let' cdepth='d') to the netlist. -Each sensitive node from the (flattend) netlist may be added to assegen1, together with its -reference node, for example GND for NMOS, nwell potential for PMOS. This procedure is -currently to be done manually, an automated setup is in preparation. +Each sensitive node from the (flattend) netlist may be added to the output vector of assegen1 +(in brackets [...]), together with its reference node, for example GND for NMOS, nwell potential +for PMOS. This procedure is currently to be done manually, a semi-automated setup using +a GUI is in preparation. + +Instead of NULL, one may give a control signal to aseegen1, to start the pulse sequence. +'mon' is a monitoring output, showing each pulse as a voltage equivalent to the current. After a transient simulation, plotting the data output versus a non-radiated device may reveal the SEE influence. @@ -45,14 +49,26 @@ Description: "single event effect generator" PORT_TABLE: -Port_Name: ctrl out -Description: "control input" "output" +Port_Name: ctrl mon +Description: "control input" "monitor" Direction: in out -Default_Type: v i -Allowed_Types: [v,vd,i,id] [i,id] -Vector: no yes -Vector_Bounds: - [1 -] -Null_Allowed: yes no +Default_Type: v v +Allowed_Types: [v,vd,i,id] [v] +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + + +PORT_TABLE: + +Port_Name: out +Description: "output" +Direction: out +Default_Type: i +Allowed_Types: [i,id] +Vector: yes +Vector_Bounds: [1 -] +Null_Allowed: no PARAMETER_TABLE: @@ -158,16 +174,19 @@ again the output starts pulsing at port (node pair) number 1. The control input ctrl (voltage or current) may be used to start or repeat the whole sequence, depending on the circuit status. A rising voltage at ctrl, when crossing the threshold given by ctrlthres, will initiate the sequence (including -tdelay and tperiod). +tdelay and tperiod). If set to NULL, the pulse (sequence) will start immediately after tdelay. + +'mon' is a monitoring output, showing each pulse as a voltage equivalent to the current. It +may be used just for plotting, or for re-triggering an action. This model will work in transient analysis. Example ngspice usage (with control) -aseegen1 ctrl [%id(n1 m1) %id(n2 m2) %id(n1 m1) %id(n2 m2)] seemod1 +aseegen1 ctrl mon [%id(n1 m1) %id(n2 m2) %id(n1 m1) %id(n2 m2)] seemod1 .model seemod1 seegen (tdelay = 8n tperiod=25n) Example ngspice usage (without control, ctrl replaced by NULL, parameters as offered by default) -aseegen2 NULL [%id(n1 m1) %id(n5 n6) %id(n6 n7) %i(isingle) ] seemod2 +aseegen2 NULL mon [%id(n1 m1) %id(n5 n6) %id(n6 n7) %i(isingle) ] seemod2 .model seemod2 seegen (tdelay = 0 tperiod=0 ctrlthres=0.5 inull=0 tfall=500p trise=20p perlim=FALSE) From 6c8f7f94082cc3c03fd1e3a2ea3e6d91b7b20eb4 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 8 Jun 2025 12:00:33 +0200 Subject: [PATCH 20/38] New example for seegen: CMOS comparator --- .../xspice/see/CMOSComparator/Fig27_12_see.sp | 78 ++++++++++ .../see/CMOSComparator/cmosedu_models.txt | 147 ++++++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 examples/xspice/see/CMOSComparator/Fig27_12_see.sp create mode 100644 examples/xspice/see/CMOSComparator/cmosedu_models.txt diff --git a/examples/xspice/see/CMOSComparator/Fig27_12_see.sp b/examples/xspice/see/CMOSComparator/Fig27_12_see.sp new file mode 100644 index 000000000..e5880078b --- /dev/null +++ b/examples/xspice/see/CMOSComparator/Fig27_12_see.sp @@ -0,0 +1,78 @@ +** CMOS comparator *** +* Figure 27.12 +* Baker: "CMOS: Circuit Design, Layout, and Simulation", Wiley, 2005 + +.param VCC = 5 +.option scale=1u +.tran 9.5p 1600n + +VDD VDD 0 DC {VCC} +Vp vp 0 DC 0 PULSE {VCC/2-0.1} {VCC/2+0.1} 30n 1n 1n 350n 700n +Vctrl ct 0 PULSE {VCC/2-0.2} {VCC/2+0.2} 270n 1n 1n 5n 350n +vm vm 0 DC {VCC/2} + +X1 vbiasn vbiasp vdd bias +M1 n1 vp vss 0 N_1u L=1 W=10 +M2 n2 vm vss 0 N_1u L=1 W=10 +M3a vss vbiasn 0 0 N_1u L=2 W=20 +M31 n1 n1 vdd vdd P_1u L=1 W=20 +M41 n2 n2 vdd vdd P_1u L=1 W=20 +M3 vop n1 vdd vdd P_1u L=1 W=20 +M4 vom n2 vdd vdd P_1u L=1 W=20 +M5 vop vop vc 0 N_1u L=1 W=10 +M6 vop vom vc 0 N_1u L=1 W=10 +M7 vom vop vc 0 N_1u L=1 W=10 +M8 vom vom vc 0 N_1u L=1 W=10 +Mc vc vc 0 0 N_1u L=10 W=10 + +M1P vopb vp vpp vdd P_1u L=1 W=20 +M2P vomb vm vpp vdd P_1u L=1 W=20 +M3p vpp vbiasp vdd vdd P_1u L=2 W=20 +M4n vopb vopb 0 0 N_1u L=1 W=10 +M5n n2 vopb 0 0 N_1u L=1 W=10 +M6n vomb vomb 0 0 N_1u L=1 W=10 +M7n n1 vomb 0 0 N_1u L=1 W=10 + +M1D vdp vbiasp vdd vdd P_1u L=1 W=20 +M2D nd1 vom vdp vdd P_1u L=1 W=20 +M3D vdo vop vdp vdd P_1u L=1 W=20 +M4D nd1 nd1 0 0 N_1u L=1 W=10 +M5D vdo nd1 0 0 N_1u L=1 W=10 + +MIN out vdo 0 0 N_1u L=1 W=10 +MIP out vdo vdd vdd P_1u L=1 W=20 + +.subckt bias vbiasn vbiasp VDD +M1 Vbiasn Vbiasn 0 0 N_1u L=2 W=10 +M2 Vbiasp Vbiasn Vr 0 N_1u L=2 W=40 +M3 Vbiasn Vbiasp VDD VDD P_1u L=2 W=30 +M4 Vbiasp Vbiasp VDD VDD P_1u L=2 W=30 + +Rbias Vr 0 6.5k + +MSU1 Vsur Vbiasn 0 0 N_1u L=2 W=10 +MSU2 Vsur Vsur VDD VDD P_1u L=100 W=10 +MSU3 Vbiasp Vsur Vbiasn 0 N_1u L=1 W=10 +.ends + +.include cmosedu_models.txt + + +.param d = 1 +.param let = 20 +.param tfall = 500p trise = 100p ; tau in exponent for pulse + +aseegen2 ct mon [ %id(vdd vbiasp) %id(vdd vop) %id(vdd vom) %id(vdd vopb) %id(vdd vpp) %id(vdd vomb) %id(vdd vdp) %id(vdd nd1) ++ %i(vbiasn) %i(x1.vr) %i(x1.vsur) %i(n1) %i(vss) %i(n2) %i(vc) %i(vdo) %i(out) ] seemod2 +.model seemod2 seegen (tdelay = 25n tperiod=19n tfall='tfall' trise='trise' let='let' cdepth='d' perlim=TRUE ctrlthres= {VCC/2}) + +.control +run +set xbrushwidth=2 +plot mon +plot out vp ct mon*5000+6 + +.endc + +.end + \ No newline at end of file diff --git a/examples/xspice/see/CMOSComparator/cmosedu_models.txt b/examples/xspice/see/CMOSComparator/cmosedu_models.txt new file mode 100644 index 000000000..f4afa35f3 --- /dev/null +++ b/examples/xspice/see/CMOSComparator/cmosedu_models.txt @@ -0,0 +1,147 @@ +* +* Long channel models from CMOS Circuit Design, Layout, and Simulation, +* Level=3 models VDD=5V, see CMOSedu.com +* +.MODEL N_1u NMOS LEVEL = 3 ++ TOX = 200E-10 NSUB = 1E17 GAMMA = 0.5 ++ PHI = 0.7 VTO = 0.8 DELTA = 3.0 ++ UO = 650 ETA = 3.0E-6 THETA = 0.1 ++ KP = 120E-6 VMAX = 1E5 KAPPA = 0.3 ++ RSH = 0 NFS = 1E12 TPG = 1 ++ XJ = 500E-9 LD = 100E-9 ++ CGDO = 200E-12 CGSO = 200E-12 CGBO = 1E-10 ++ CJ = 400E-6 PB = 1 MJ = 0.5 ++ CJSW = 300E-12 MJSW = 0.5 +* +.MODEL P_1u PMOS LEVEL = 3 ++ TOX = 200E-10 NSUB = 1E17 GAMMA = 0.6 ++ PHI = 0.7 VTO = -0.9 DELTA = 0.1 ++ UO = 250 ETA = 0 THETA = 0.1 ++ KP = 40E-6 VMAX = 5E4 KAPPA = 1 ++ RSH = 0 NFS = 1E12 TPG = -1 ++ XJ = 500E-9 LD = 100E-9 ++ CGDO = 200E-12 CGSO = 200E-12 CGBO = 1E-10 ++ CJ = 400E-6 PB = 1 MJ = 0.5 ++ CJSW = 300E-12 MJSW = 0.5 +* +* +* Short channel models from CMOS Circuit Design, Layout, and Simulation, +* 50nm BSIM4 models VDD=1V, see CMOSedu.com +* +.model N_50n nmos level = 54 ++binunit = 1 paramchk= 1 mobmod = 0 ++capmod = 2 igcmod = 1 igbmod = 1 geomod = 0 ++diomod = 1 rdsmod = 0 rbodymod= 1 rgatemod= 1 ++permod = 1 acnqsmod= 0 trnqsmod= 0 ++tnom = 27 toxe = 1.4e-009 toxp = 7e-010 toxm = 1.4e-009 ++epsrox = 3.9 wint = 5e-009 lint = 1.2e-008 ++ll = 0 wl = 0 lln = 1 wln = 1 ++lw = 0 ww = 0 lwn = 1 wwn = 1 ++lwl = 0 wwl = 0 xpart = 0 toxref = 1.4e-009 ++vth0 = 0.22 k1 = 0.35 k2 = 0.05 k3 = 0 ++k3b = 0 w0 = 2.5e-006 dvt0 = 2.8 dvt1 = 0.52 ++dvt2 = -0.032 dvt0w = 0 dvt1w = 0 dvt2w = 0 ++dsub = 2 minv = 0.05 voffl = 0 dvtp0 = 1e-007 ++dvtp1 = 0.05 lpe0 = 5.75e-008 lpeb = 2.3e-010 xj = 2e-008 ++ngate = 5e+020 ndep = 2.8e+018 nsd = 1e+020 phin = 0 ++cdsc = 0.0002 cdscb = 0 cdscd = 0 cit = 0 ++voff = -0.15 nfactor = 1.2 eta0 = 0.15 etab = 0 ++vfb = -0.55 u0 = 0.032 ua = 1.6e-010 ub = 1.1e-017 ++uc = -3e-011 vsat = 1.1e+005 a0 = 2 ags = 1e-020 ++a1 = 0 a2 = 1 b0 = -1e-020 b1 = 0 ++keta = 0.04 dwg = 0 dwb = 0 pclm = 0.18 ++pdiblc1 = 0.028 pdiblc2 = 0.022 pdiblcb = -0.005 drout = 0.45 ++pvag = 1e-020 delta = 0.01 pscbe1 = 8.14e+008 pscbe2 = 1e-007 ++fprout = 0.2 pdits = 0.2 pditsd = 0.23 pditsl = 2.3e+006 ++rsh = 3 rdsw = 150 rsw = 150 rdw = 150 ++rdswmin = 0 rdwmin = 0 rswmin = 0 prwg = 0 ++prwb = 6.8e-011 wr = 1 alpha0 = 0.074 alpha1 = 0.005 ++beta0 = 30 agidl = 0.0002 bgidl = 2.1e+009 cgidl = 0.0002 ++egidl = 0.8 ++aigbacc = 0.012 bigbacc = 0.0028 cigbacc = 0.002 ++nigbacc = 1 aigbinv = 0.014 bigbinv = 0.004 cigbinv = 0.004 ++eigbinv = 1.1 nigbinv = 3 aigc = 0.017 bigc = 0.0028 ++cigc = 0.002 aigsd = 0.017 bigsd = 0.0028 cigsd = 0.002 ++nigc = 1 poxedge = 1 pigcd = 1 ntox = 1 ++xrcrg1 = 12 xrcrg2 = 5 ++cgso = 6.238e-010 cgdo = 6.238e-010 cgbo = 2.56e-011 cgdl = 2.495e-10 ++cgsl = 2.495e-10 ckappas = 0.02 ckappad = 0.02 acde = 1 ++moin = 15 noff = 0.9 voffcv = 0.02 ++kt1 = -0.21 kt1l = 0.0 kt2 = -0.042 ute = -1.5 ++ua1 = 1e-009 ub1 = -3.5e-019 uc1 = 0 prt = 0 ++at = 53000 ++fnoimod = 1 tnoimod = 0 ++jss = 0.0001 jsws = 1e-011 jswgs = 1e-010 njs = 1 ++ijthsfwd= 0.01 ijthsrev= 0.001 bvs = 10 xjbvs = 1 ++jsd = 0.0001 jswd = 1e-011 jswgd = 1e-010 njd = 1 ++ijthdfwd= 0.01 ijthdrev= 0.001 bvd = 10 xjbvd = 1 ++pbs = 1 cjs = 0.0005 mjs = 0.5 pbsws = 1 ++cjsws = 5e-010 mjsws = 0.33 pbswgs = 1 cjswgs = 5e-010 ++mjswgs = 0.33 pbd = 1 cjd = 0.0005 mjd = 0.5 ++pbswd = 1 cjswd = 5e-010 mjswd = 0.33 pbswgd = 1 ++cjswgd = 5e-010 mjswgd = 0.33 tpb = 0.005 tcj = 0.001 ++tpbsw = 0.005 tcjsw = 0.001 tpbswg = 0.005 tcjswg = 0.001 ++xtis = 3 xtid = 3 ++dmcg = 0e-006 dmci = 0e-006 dmdg = 0e-006 dmcgt = 0e-007 ++dwj = 0e-008 xgw = 0e-007 xgl = 0e-008 ++rshg = 0.4 gbmin = 1e-010 rbpb = 5 rbpd = 15 ++rbps = 15 rbdb = 15 rbsb = 15 ngcon = 1 +* +.model P_50n pmos level = 54 ++binunit = 1 paramchk= 1 mobmod = 0 ++capmod = 2 igcmod = 1 igbmod = 1 geomod = 0 ++diomod = 1 rdsmod = 0 rbodymod= 1 rgatemod= 1 ++permod = 1 acnqsmod= 0 trnqsmod= 0 ++tnom = 27 toxe = 1.4e-009 toxp = 7e-010 toxm = 1.4e-009 ++epsrox = 3.9 wint = 5e-009 lint = 1.2e-008 ++ll = 0 wl = 0 lln = 1 wln = 1 ++lw = 0 ww = 0 lwn = 1 wwn = 1 ++lwl = 0 wwl = 0 xpart = 0 toxref = 1.4e-009 ++vth0 = -0.22 k1 = 0.39 k2 = 0.05 k3 = 0 ++k3b = 0 w0 = 2.5e-006 dvt0 = 3.9 dvt1 = 0.635 ++dvt2 = -0.032 dvt0w = 0 dvt1w = 0 dvt2w = 0 ++dsub = 0.7 minv = 0.05 voffl = 0 dvtp0 = 0.5e-008 ++dvtp1 = 0.05 lpe0 = 5.75e-008 lpeb = 2.3e-010 xj = 2e-008 ++ngate = 5e+020 ndep = 2.8e+018 nsd = 1e+020 phin = 0 ++cdsc = 0.000258 cdscb = 0 cdscd = 6.1e-008 cit = 0 ++voff = -0.15 nfactor = 2 eta0 = 0.15 etab = 0 ++vfb = 0.55 u0 = 0.0095 ua = 1.6e-009 ub = 8e-018 ++uc = 4.6e-013 vsat = 90000 a0 = 1.2 ags = 1e-020 ++a1 = 0 a2 = 1 b0 = -1e-020 b1 = 0 ++keta = -0.047 dwg = 0 dwb = 0 pclm = 0.55 ++pdiblc1 = 0.03 pdiblc2 = 0.0055 pdiblcb = 3.4e-008 drout = 0.56 ++pvag = 1e-020 delta = 0.014 pscbe1 = 8.14e+008 pscbe2 = 9.58e-007 ++fprout = 0.2 pdits = 0.2 pditsd = 0.23 pditsl = 2.3e+006 ++rsh = 3 rdsw = 250 rsw = 160 rdw = 160 ++rdswmin = 0 rdwmin = 0 rswmin = 0 prwg = 3.22e-008 ++prwb = 6.8e-011 wr = 1 alpha0 = 0.074 alpha1 = 0.005 ++beta0 = 30 agidl = 0.0002 bgidl = 2.1e+009 cgidl = 0.0002 ++egidl = 0.8 ++aigbacc = 0.012 bigbacc = 0.0028 cigbacc = 0.002 ++nigbacc = 1 aigbinv = 0.014 bigbinv = 0.004 cigbinv = 0.004 ++eigbinv = 1.1 nigbinv = 3 aigc = 0.69 bigc = 0.0012 ++cigc = 0.0008 aigsd = 0.0087 bigsd = 0.0012 cigsd = 0.0008 ++nigc = 1 poxedge = 1 pigcd = 1 ntox = 1 ++xrcrg1 = 12 xrcrg2 = 5 ++cgso = 7.43e-010 cgdo = 7.43e-010 cgbo = 2.56e-011 cgdl = 1e-014 ++cgsl = 1e-014 ckappas = 0.5 ckappad = 0.5 acde = 1 ++moin = 15 noff = 0.9 voffcv = 0.02 ++kt1 = -0.19 kt1l = 0 kt2 = -0.052 ute = -1.5 ++ua1 = -1e-009 ub1 = 2e-018 uc1 = 0 prt = 0 ++at = 33000 ++fnoimod = 1 tnoimod = 0 ++jss = 0.0001 jsws = 1e-011 jswgs = 1e-010 njs = 1 ++ijthsfwd= 0.01 ijthsrev= 0.001 bvs = 10 xjbvs = 1 ++jsd = 0.0001 jswd = 1e-011 jswgd = 1e-010 njd = 1 ++ijthdfwd= 0.01 ijthdrev= 0.001 bvd = 10 xjbvd = 1 ++pbs = 1 cjs = 0.0005 mjs = 0.5 pbsws = 1 ++cjsws = 5e-010 mjsws = 0.33 pbswgs = 1 cjswgs = 5e-010 ++mjswgs = 0.33 pbd = 1 cjd = 0.0005 mjd = 0.5 ++pbswd = 1 cjswd = 5e-010 mjswd = 0.33 pbswgd = 1 ++cjswgd = 5e-010 mjswgd = 0.33 tpb = 0.005 tcj = 0.001 ++tpbsw = 0.005 tcjsw = 0.001 tpbswg = 0.005 tcjswg = 0.001 ++xtis = 3 xtid = 3 ++dmcg = 0e-006 dmci = 0e-006 dmdg = 0e-006 dmcgt = 0e-007 ++dwj = 0e-008 xgw = 0e-007 xgl = 0e-008 ++rshg = 0.4 gbmin = 1e-010 rbpb = 5 rbpd = 15 ++rbps = 15 rbdb = 15 rbsb = 15 ngcon = 1 From 3680a8c24d6290b29a00791d6734283782cd2e06 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 9 Jun 2025 11:02:15 +0200 Subject: [PATCH 21/38] Unix line endings rusage added --- .../xspice/see/CMOSComparator/Fig27_12_see.sp | 155 +++++++++--------- 1 file changed, 77 insertions(+), 78 deletions(-) diff --git a/examples/xspice/see/CMOSComparator/Fig27_12_see.sp b/examples/xspice/see/CMOSComparator/Fig27_12_see.sp index e5880078b..0744b9dc0 100644 --- a/examples/xspice/see/CMOSComparator/Fig27_12_see.sp +++ b/examples/xspice/see/CMOSComparator/Fig27_12_see.sp @@ -1,78 +1,77 @@ -** CMOS comparator *** -* Figure 27.12 -* Baker: "CMOS: Circuit Design, Layout, and Simulation", Wiley, 2005 - -.param VCC = 5 -.option scale=1u -.tran 9.5p 1600n - -VDD VDD 0 DC {VCC} -Vp vp 0 DC 0 PULSE {VCC/2-0.1} {VCC/2+0.1} 30n 1n 1n 350n 700n -Vctrl ct 0 PULSE {VCC/2-0.2} {VCC/2+0.2} 270n 1n 1n 5n 350n -vm vm 0 DC {VCC/2} - -X1 vbiasn vbiasp vdd bias -M1 n1 vp vss 0 N_1u L=1 W=10 -M2 n2 vm vss 0 N_1u L=1 W=10 -M3a vss vbiasn 0 0 N_1u L=2 W=20 -M31 n1 n1 vdd vdd P_1u L=1 W=20 -M41 n2 n2 vdd vdd P_1u L=1 W=20 -M3 vop n1 vdd vdd P_1u L=1 W=20 -M4 vom n2 vdd vdd P_1u L=1 W=20 -M5 vop vop vc 0 N_1u L=1 W=10 -M6 vop vom vc 0 N_1u L=1 W=10 -M7 vom vop vc 0 N_1u L=1 W=10 -M8 vom vom vc 0 N_1u L=1 W=10 -Mc vc vc 0 0 N_1u L=10 W=10 - -M1P vopb vp vpp vdd P_1u L=1 W=20 -M2P vomb vm vpp vdd P_1u L=1 W=20 -M3p vpp vbiasp vdd vdd P_1u L=2 W=20 -M4n vopb vopb 0 0 N_1u L=1 W=10 -M5n n2 vopb 0 0 N_1u L=1 W=10 -M6n vomb vomb 0 0 N_1u L=1 W=10 -M7n n1 vomb 0 0 N_1u L=1 W=10 - -M1D vdp vbiasp vdd vdd P_1u L=1 W=20 -M2D nd1 vom vdp vdd P_1u L=1 W=20 -M3D vdo vop vdp vdd P_1u L=1 W=20 -M4D nd1 nd1 0 0 N_1u L=1 W=10 -M5D vdo nd1 0 0 N_1u L=1 W=10 - -MIN out vdo 0 0 N_1u L=1 W=10 -MIP out vdo vdd vdd P_1u L=1 W=20 - -.subckt bias vbiasn vbiasp VDD -M1 Vbiasn Vbiasn 0 0 N_1u L=2 W=10 -M2 Vbiasp Vbiasn Vr 0 N_1u L=2 W=40 -M3 Vbiasn Vbiasp VDD VDD P_1u L=2 W=30 -M4 Vbiasp Vbiasp VDD VDD P_1u L=2 W=30 - -Rbias Vr 0 6.5k - -MSU1 Vsur Vbiasn 0 0 N_1u L=2 W=10 -MSU2 Vsur Vsur VDD VDD P_1u L=100 W=10 -MSU3 Vbiasp Vsur Vbiasn 0 N_1u L=1 W=10 -.ends - -.include cmosedu_models.txt - - -.param d = 1 -.param let = 20 -.param tfall = 500p trise = 100p ; tau in exponent for pulse - -aseegen2 ct mon [ %id(vdd vbiasp) %id(vdd vop) %id(vdd vom) %id(vdd vopb) %id(vdd vpp) %id(vdd vomb) %id(vdd vdp) %id(vdd nd1) -+ %i(vbiasn) %i(x1.vr) %i(x1.vsur) %i(n1) %i(vss) %i(n2) %i(vc) %i(vdo) %i(out) ] seemod2 -.model seemod2 seegen (tdelay = 25n tperiod=19n tfall='tfall' trise='trise' let='let' cdepth='d' perlim=TRUE ctrlthres= {VCC/2}) - -.control -run -set xbrushwidth=2 -plot mon -plot out vp ct mon*5000+6 - -.endc - -.end - \ No newline at end of file +** CMOS comparator *** +* Figure 27.12 +* Baker: "CMOS: Circuit Design, Layout, and Simulation", Wiley, 2005 + +.param VCC = 5 +.option scale=1u +.tran 9.5p 1600n + +VDD VDD 0 DC {VCC} +Vp vp 0 DC 0 PULSE {VCC/2-0.1} {VCC/2+0.1} 30n 1n 1n 350n 700n +Vctrl ct 0 PULSE {VCC/2-0.2} {VCC/2+0.2} 270n 1n 1n 5n 350n +vm vm 0 DC {VCC/2} + +X1 vbiasn vbiasp vdd bias +M1 n1 vp vss 0 N_1u L=1 W=10 +M2 n2 vm vss 0 N_1u L=1 W=10 +M3a vss vbiasn 0 0 N_1u L=2 W=20 +M31 n1 n1 vdd vdd P_1u L=1 W=20 +M41 n2 n2 vdd vdd P_1u L=1 W=20 +M3 vop n1 vdd vdd P_1u L=1 W=20 +M4 vom n2 vdd vdd P_1u L=1 W=20 +M5 vop vop vc 0 N_1u L=1 W=10 +M6 vop vom vc 0 N_1u L=1 W=10 +M7 vom vop vc 0 N_1u L=1 W=10 +M8 vom vom vc 0 N_1u L=1 W=10 +Mc vc vc 0 0 N_1u L=10 W=10 + +M1P vopb vp vpp vdd P_1u L=1 W=20 +M2P vomb vm vpp vdd P_1u L=1 W=20 +M3p vpp vbiasp vdd vdd P_1u L=2 W=20 +M4n vopb vopb 0 0 N_1u L=1 W=10 +M5n n2 vopb 0 0 N_1u L=1 W=10 +M6n vomb vomb 0 0 N_1u L=1 W=10 +M7n n1 vomb 0 0 N_1u L=1 W=10 + +M1D vdp vbiasp vdd vdd P_1u L=1 W=20 +M2D nd1 vom vdp vdd P_1u L=1 W=20 +M3D vdo vop vdp vdd P_1u L=1 W=20 +M4D nd1 nd1 0 0 N_1u L=1 W=10 +M5D vdo nd1 0 0 N_1u L=1 W=10 + +MIN out vdo 0 0 N_1u L=1 W=10 +MIP out vdo vdd vdd P_1u L=1 W=20 + +.subckt bias vbiasn vbiasp VDD +M1 Vbiasn Vbiasn 0 0 N_1u L=2 W=10 +M2 Vbiasp Vbiasn Vr 0 N_1u L=2 W=40 +M3 Vbiasn Vbiasp VDD VDD P_1u L=2 W=30 +M4 Vbiasp Vbiasp VDD VDD P_1u L=2 W=30 + +Rbias Vr 0 6.5k + +MSU1 Vsur Vbiasn 0 0 N_1u L=2 W=10 +MSU2 Vsur Vsur VDD VDD P_1u L=100 W=10 +MSU3 Vbiasp Vsur Vbiasn 0 N_1u L=1 W=10 +.ends + +.include cmosedu_models.txt + + +.param d = 1 +.param let = 20 +.param tfall = 500p trise = 100p ; tau in exponent for pulse + +aseegen2 ct mon [ %id(vdd vbiasp) %id(vdd vop) %id(vdd vom) %id(vdd vopb) %id(vdd vpp) %id(vdd vomb) %id(vdd vdp) %id(vdd nd1) ++ %i(vbiasn) %i(x1.vr) %i(x1.vsur) %i(n1) %i(vss) %i(n2) %i(vc) %i(vdo) %i(out) ] seemod2 +.model seemod2 seegen (tdelay = 25n tperiod=19n tfall='tfall' trise='trise' let='let' cdepth='d' perlim=TRUE ctrlthres= {VCC/2}) + +.control +run +rusage time +set xbrushwidth=2 +plot mon +plot out vp ct mon*5000+6 +.endc + +.end From 64284d0fda88b31c93a8abbd5da7282aa1f478fb Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Thu, 1 May 2025 21:09:19 +0200 Subject: [PATCH 22/38] New cppduals from https://gitlab.com/tesch1/cppduals downloaded may 1st, 2025 --- src/include/cppduals/.appveyor.yml | 7 +- src/include/cppduals/.gitlab-ci.yml | 113 +- src/include/cppduals/CMakeLists.txt | 52 +- src/include/cppduals/README.md | 65 +- src/include/cppduals/duals/Makefile.am | 6 - src/include/cppduals/duals/arch/SSE/Dual.h | 9 +- src/include/cppduals/duals/dual | 1394 +++++++++++------ src/include/cppduals/duals/dual_eigen | 63 +- src/include/cppduals/tests/CMakeLists.txt | 286 ++-- src/include/cppduals/tests/bench_eigen.cpp | 152 +- src/include/cppduals/tests/bench_gemm.cpp | 90 +- src/include/cppduals/tests/sandbox.cpp | 36 +- src/include/cppduals/tests/test_1.cpp | 2 - src/include/cppduals/tests/test_dual.cpp | 45 +- src/include/cppduals/tests/test_eigen.cpp | 118 +- src/include/cppduals/tests/test_expm.cpp | 6 +- src/include/cppduals/tests/test_fmt.cpp | 148 +- src/include/cppduals/tests/test_funcs.cpp | 302 +++- src/include/cppduals/tests/test_packets.cpp | 42 +- src/include/cppduals/tests/test_solve.cpp | 7 +- src/include/cppduals/tests/test_vectorize.cpp | 35 +- .../cppduals/thirdparty/CMakeLists.txt | 160 +- 22 files changed, 2056 insertions(+), 1082 deletions(-) delete mode 100644 src/include/cppduals/duals/Makefile.am diff --git a/src/include/cppduals/.appveyor.yml b/src/include/cppduals/.appveyor.yml index 1bc8991f3..54587d2fd 100644 --- a/src/include/cppduals/.appveyor.yml +++ b/src/include/cppduals/.appveyor.yml @@ -3,9 +3,8 @@ clone_folder: c:\projects\cppduals clone_depth: 3 image: -#- Visual Studio 2013 -#- Visual Studio 2015 - Visual Studio 2017 +#- Visual Studio 2022 configuration: - Release @@ -14,12 +13,10 @@ configuration: # Do not build feature branch with open Pull Requests skip_branch_with_pr: true -# skip unsupported combinations init: - echo %APPVEYOR_BUILD_WORKER_IMAGE% -- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2013" ( set generator="Visual Studio 12 2013" ) -- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" ( set generator="Visual Studio 14 2015" ) - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" ( set generator="Visual Studio 15 2017" ) +- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2022" ( set generator="Visual Studio 17 2022" ) - echo %generator% before_build: diff --git a/src/include/cppduals/.gitlab-ci.yml b/src/include/cppduals/.gitlab-ci.yml index 9296366be..8dac950f8 100644 --- a/src/include/cppduals/.gitlab-ci.yml +++ b/src/include/cppduals/.gitlab-ci.yml @@ -1,5 +1,4 @@ -#image: ubuntu:19.04 -image: fedora:30 +image: fedora:41 variables: GIT_DEPTH: 3 @@ -9,79 +8,105 @@ stages: - build - test - cover -- publish - -before_script: -#- apt-get update --yes -#- apt-get install --yes cmake g++ git doxygen lcov graphviz -- dnf install -y gcc-c++ make cmake git doxygen lcov graphviz +- pages +- upload +- release build: stage: build -# variables: -# CC: clang -# CXX: clang++ script: + - dnf install -y gcc-c++ make cmake git doxygen lcov graphviz - echo $CXX - - cmake -Bbuild -H. -DCPPDUALS_TESTING=ON + - gcc -march=native -dM -E - // SSE3 namespace Eigen { @@ -150,17 +151,9 @@ template<> EIGEN_STRONG_INLINE void prefetch >(const duals::d template<> EIGEN_STRONG_INLINE duals::dual pfirst(const Packet2df& a) { - #if EIGEN_GNUC_AT_MOST(4,3) - // Workaround gcc 4.2 ICE - this is not performance wise ideal, but who cares... - // This workaround also fix invalid code generation with gcc 4.3 - EIGEN_ALIGN16 duals::dual res[2]; - _mm_store_ps((float*)res, a.v); - return res[0]; - #else duals::dual res; _mm_storel_pi((__m64*)&res, a.v); return res; - #endif } template<> EIGEN_STRONG_INLINE Packet2df preverse(const Packet2df& a) diff --git a/src/include/cppduals/duals/dual b/src/include/cppduals/duals/dual index 4f5bf8acc..94688d185 100644 --- a/src/include/cppduals/duals/dual +++ b/src/include/cppduals/duals/dual @@ -16,14 +16,24 @@ #define CPPDUALS_DUAL #ifndef PARSED_BY_DOXYGEN -#include -#include +#define _DUALS_CONSTEXPR constexpr + +///// FOR LIBCPP ///// +#include +#if !defined(_LIBCPP_BEGIN_NAMESPACE_STD) +namespace std { +template class complex; +} +#else // LIBCPP +_LIBCPP_BEGIN_NAMESPACE_STD +template class complex; +_LIBCPP_END_NAMESPACE_STD +#endif // LIBCPP + #include #include -#include -#include -#include -#endif + +#endif // PARSED_BY_DOXYGEN #if !defined(CPPDUALS_IGNORE_COMPILER_VERSION) && !defined(_WIN32) #if __cplusplus < 201103L @@ -34,11 +44,9 @@ /// Configure whether system has POSIX extern int signgam; #ifndef CPPDUALS_HAVE_SIGNGAM #ifndef _WIN32 -#ifndef __CYGWIN__ #define CPPDUALS_HAVE_SIGNGAM 1 #endif #endif -#endif namespace duals { /** @@ -180,11 +188,12 @@ T rpart(dual) // Real part T dpart(dual) // Dual part dual dconj(dual) // Dual-conjugate -dual random(dual low = {0,0}, dual high = {1,0}) - +// Transcendental functions dual exp(dual) dual log(dual) dual log10(dual) +dual log2(dual) +dual logb(dual x) dual pow(dual, U) dual pow(U, dual) dual pow(dual, dual) @@ -196,7 +205,9 @@ dual tan(dual) dual asin(dual) dual acos(dual) dual atan(dual) - +dual atan2(dual, dual) +dual hypot(dual, dual) +dual scalbn(dual arg, int ex) // TODO: dual sinh(dual) dual cosh(dual) @@ -205,18 +216,35 @@ dual asinh(dual) dual acosh(dual) dual atanh(dual) +dual erf(dual) +dual erfc(dual) +dual tgamma(dual) +dual lgamma(dual) + // Non-differentiable operations on the real part. -T frexp(duals::dual arg, int* exp ); -duals::dual ldexp(duals::dual arg, int exp ); -T trunc(duals::dual d); -T floor(duals::dual d); -T ceil(duals::dual d); -T round(duals::dual d); -int fpclassify(duals::dual d); -bool isfinite(duals::dual d); -bool isnormal(duals::dual d); -bool isinf(duals::dual d); -bool isnan(duals::dual d); +dual abs(dual d) +dual fabs(dual d) +dual fmax(dual x, dual y) +dual fmin(dual x, dual y) +dual frexp(dual arg, int* exp ) +dual ldexp(dual arg, int exp ) +dual trunc(dual d) +dual floor(dual d) +dual ceil(dual d) +dual round(dual d) + +// floating point functions +int fpclassify(dual d) +bool isfinite(dual d) +bool isnormal(dual d) +bool isinf(dual d) +bool isnan(dual d) +bool signbit(dual d) +dual copysign(dual x, dual y) + +// Utility functions +dual random(dual low = {0,0}, dual high = {1,0}) +dual random2(dual low = {0,0}, dual high = {1,0}) // Stream IO template operator>>(basic_istream &, dual &); @@ -256,7 +284,7 @@ are disabled by default, but can be enabled by `#define CPPDUALS_LIBFMT` for the `dual<>` formatter, and/or `#define CPPDUALS_LIBFMT_COMPLEX` for the std::complex<> formatter. There are three custom formatting flags that control how the dual numbers are -printed, these must come before the normal `{fmt}` formatting spec: +printed, these must come before the normal `{fmt}` formatting spec '$', '*', ','. For me these are about 3x faster than iostreams. ``` @@ -333,7 +361,7 @@ template struct dual_traits> template struct dual_traits>> { /// complex> have the same 'depth' as their dual. - enum { depth = dual_traits::depth }; + enum { depth = dual_traits >::depth }; /// The real storage type. typedef typename dual_traits::real_type real_type; @@ -361,6 +389,8 @@ template struct promote : std::common_type using can_promote = detail::has_member_type>; +// dual dual +// T == U template struct promote, dual, typename std::enable_if<(can_promote::value @@ -368,6 +398,9 @@ struct promote, dual, { typedef dual::type> type; }; +// dual U +// T >= U +// U is not complex template struct promote, U, typename std::enable_if<(can_promote::value @@ -376,6 +409,9 @@ struct promote, U, { typedef dual::type> type; }; +// U dual +// T >= U +// U is not complex template struct promote, typename std::enable_if<(can_promote::value @@ -385,6 +421,8 @@ struct promote, typedef dual::type> type; }; // ///////////////////////////////////////////////// +// complex complex +// T == U template struct promote, std::complex, typename std::enable_if<(can_promote::value @@ -392,6 +430,9 @@ struct promote, std::complex, { typedef std::complex::type> type; }; +// complex U +// T >= U +// U is not complex template struct promote, U, typename std::enable_if<(can_promote::value @@ -400,6 +441,9 @@ struct promote, U, { typedef std::complex::type> type; }; +// U complex +// T >= U +// U is not complex template struct promote, typename std::enable_if<(can_promote::value @@ -446,7 +490,7 @@ 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. template -struct numeric_limits> : numeric_limits { +struct numeric_limits > : public numeric_limits { static constexpr bool is_specialized = true; static constexpr duals::dual min NOMACRO () { return numeric_limits::min NOMACRO (); } static constexpr duals::dual lowest() { return numeric_limits::lowest(); } @@ -477,24 +521,24 @@ namespace duals { // Both T and U are wrapped in a dual<> #define CPPDUALS_ENABLE_SAME_DEPTH_AND_COMMON_T(T,U) \ - typename std::enable_if<(int)duals::dual_traits::depth == \ - (int)duals::dual_traits::depth, int>::type = 0, \ - typename std::enable_if::value,int>::type = 0, \ - typename common_t = dual::type> + typename common_t = dual::type>, \ + typename std::enable_if<(int)duals::dual_traits::depth == \ + (int)duals::dual_traits::depth, int>::type = 0, \ + typename std::enable_if::value,int>::type = 0 // T is wrapped in a dual<>, U may or may not be. #define CPPDUALS_ENABLE_LEQ_DEPTH_AND_COMMON_T(T,U) \ + typename common_t = typename duals::promote, U>::type, \ typename std::enable_if<((int)duals::dual_traits::depth >= \ (int)duals::dual_traits::depth), int>::type = 0, \ - typename std::enable_if,U>::value,int>::type = 0, \ - typename common_t = typename duals::promote, U>::type + typename std::enable_if,U>::value,int>::type = 0 // T is wrapped in complex> #define CPPDUALS_ENABLE_LEQ_DEPTH_AND_CX_COMMON_T(T,U) \ + typename common_t = typename duals::promote >,U>::type, \ typename std::enable_if<((int)duals::dual_traits::depth >= \ (int)duals::dual_traits::depth), int>::type = 0, \ - typename std::enable_if>,U>::value,int>::type = 0, \ - typename common_t = typename duals::promote >,U>::type + typename std::enable_if>,U>::value,int>::type = 0 #define CPPDUALS_ENABLE_IF(...) typename std::enable_if< (__VA_ARGS__) , int>::type = 0 @@ -528,16 +572,13 @@ public: : _real(re), _dual(du) {} /// Copy construct from a dual of equal depth. -#if defined (_MSC_VER) -#pragma warning (disable : 4244) /* floats are not used in HICUM */ -#endif template::value)> dual(const dual & x) : _real(x.rpart()), _dual(x.dpart()) {} /// Cast to a complex> with real part equal to *this. - operator std::complex>() { return std::complex>(*this); } + operator std::complex>() { return std::complex>(*this, (T)0); } /// Explicit cast to an arithmetic type retains the rpart() template dual & operator-=(const dual & x) { _real -= x.rpart(); _dual -= x.dpart(); return *this; } - /// Multiply this dual with a dual of same of lower depth. + /// Multiply this dual with a dual of same depth. template dual & operator*=(const dual & x) { _dual = _real * x.dpart() + _dual * x.rpart(); @@ -733,6 +774,768 @@ CPPDUALS_LHS_COMPARISON(!=) #endif // PARSED_BY_DOXYGEN +/// Complex Conjugate of a dual is just the dual. +template dual conj(const dual & x) { return x; } + +/// Conjugate a thing that's not dual and not complex -- it has no +/// complex value so just return it. This is different from +/// std::conj() which promotes the T to a std::complex. +template::value && + !is_complex::value && + std::is_arithmetic::value)> +T conj(const T & x) { return x; } + +/// Dual Conjugate, such that x*dconj(x) = rpart(x)^2. Different +/// function name from complex conjugate conj(). +template dual dconj(const dual & x) { + return dual(x.rpart(), - x.dpart()); +} + +/// Dual Conjugate of a complex, such that x*dconj(x) = rpart(x)^2. +/// Different function name from complex conjugate conj(). +template std::complex dconj(const std::complex & x) { + return std::complex(dconj(x.real()), dconj(x.imag())); +} + +/// Conjugate a thing that's not dual and not complex. +template::value && + !is_complex::value && + std::is_arithmetic::value)> +T dconj(const T & x) { return x; } + +namespace detail { + template dual exp_impl(const dual & x); + template dual log_impl(const dual & x); + template dual log10_impl(const dual & x); + template dual log2_impl(const dual & x); + template dual logb_impl(const dual & x); + template + common_t pow_dual_scalar(const dual& x, const U& y); + template + common_t pow_scalar_dual(const U& x, const dual& y); + template + std::complex> pow_complex_dual(const std::complex>& x, const dual& y); + template + std::complex> pow_dual_complex(const dual& x, const std::complex>& y); + template + common_t pow_dual_dual(const dual& x, const dual& y); + template dual sqrt_impl(const dual & x); + template dual cbrt_impl(const dual & x); + template dual sin_impl(const dual & x); + template dual cos_impl(const dual & x); + template dual tan_impl(const dual & x); + template dual asin_impl(const dual & x); + template dual acos_impl(const dual & x); + template dual atan_impl(const dual & x); + template + common_t atan2_dual_scalar(const dual & y, const U & x); + template + common_t atan2_scalar_dual(const U & y, const dual & x); + template dual atan2_dual_dual(const dual & y, const dual & x); + template dual hypot_impl(const dual & x, const dual & y); + template dual scalbn_impl(const dual & arg, int ex); + template dual sinh_impl(const dual & x); + template dual cosh_impl(const dual & x); + template dual tanh_impl(const dual & x); + template dual asinh_impl(const dual & x); + template dual acosh_impl(const dual & x); + template dual atanh_impl(const dual & x); + template dual erf_impl(const dual & x); + template dual erfc_impl(const dual & x); + template dual tgamma_impl(const dual & x); + template dual lgamma_impl(const dual & x); + template dual abs_impl(const dual & x); + template dual fabs_impl(const dual & x); + template dual fmax_impl(const dual & x, const dual & y); + template dual fmin_impl(const dual & x, const dual & y); + template dual frexp_impl(const dual & x, int* exp); + template dual ldexp_impl(const dual & x, int exp); + template dual trunc_impl(const dual & x); + template dual floor_impl(const dual & x); + template dual ceil_impl(const dual & x); + template dual round_impl(const dual & x); + template int fpclassify_impl(const dual & x); + template bool isfinite_impl(const dual & x); + template bool isnormal_impl(const dual & x); + template bool isinf_impl(const dual & x); + template bool isnan_impl(const dual & x); + template bool signbit_impl(const dual & x); + template dual copysign_impl(const dual & x, const dual & y); + template dual log1p_impl(const dual & x); + template dual expm1_impl(const dual & x); + template dual random_impl(const dual & low, const dual & high); + template dual random2_impl(const dual & low, const dual & high); +} + +/// /// /// /// /// /// /// /// +/// Prototypes +/// + +// Public interfaces that forward to implementations +template dual exp(const dual & x) { return detail::exp_impl(x); } +template dual log(const dual & x) { return detail::log_impl(x); } +template dual log10(const dual & x) { return detail::log10_impl(x); } +template dual log2(const dual & x) { return detail::log2_impl(x); } +template dual logb(const dual & x) { return detail::logb_impl(x); } +template::value)> +common_t pow(const dual& x, const U& y) { return detail::pow_dual_scalar(x, y); } +template::value)> +common_t pow(const U& x, const dual& y) { return detail::pow_scalar_dual(x, y); } +template +std::complex> pow(const dual & x, const std::complex> & y) { return detail::pow_dual_complex(x, y); } +template +std::complex> pow(const std::complex> & x, const dual& y) { return detail::pow_complex_dual(x, y); } +template +common_t pow(const dual& x, const dual& y) { return detail::pow_dual_dual(x, y); } +template dual sqrt(const dual & x) { return detail::sqrt_impl(x); } +template dual cbrt(const dual & x) { return detail::cbrt_impl(x); } +template dual sin(const dual & x) { return detail::sin_impl(x); } +template dual cos(const dual & x) { return detail::cos_impl(x); } +template dual tan(const dual & x) { return detail::tan_impl(x); } +template dual asin(const dual & x) { return detail::asin_impl(x); } +template dual acos(const dual & x) { return detail::acos_impl(x); } +template dual atan(const dual & x) { return detail::atan_impl(x); } +template +common_t atan2(const dual & y, const U & x) { return detail::atan2_dual_scalar(y, x); } +template +common_t atan2(const U & y, const dual & x) { return detail::atan2_scalar_dual(y, x); } +template dual atan2(const dual & y, const dual & x) { return detail::atan2_dual_dual(y, x); } +template dual hypot(const dual & x, const dual & y) { return detail::hypot_impl(x, y); } +template dual scalbn(const dual & arg, int ex) { return detail::scalbn_impl(arg, ex); } +template dual sinh(const dual & x) { return detail::sinh_impl(x); } +template dual cosh(const dual & x) { return detail::cosh_impl(x); } +template dual tanh(const dual & x) { return detail::tanh_impl(x); } +template dual asinh(const dual & x) { return detail::asinh_impl(x); } +template dual acosh(const dual & x) { return detail::acosh_impl(x); } +template dual atanh(const dual & x) { return detail::atanh_impl(x); } +/// The error function. Make sure to `#include ` before +/// `#include ` to use this function. +template dual erf(const dual & x) { return detail::erf_impl(x); } +template dual erfc(const dual & x) { return detail::erfc_impl(x); } +template dual tgamma(const dual & x) { return detail::tgamma_impl(x); } +template dual lgamma(const dual & x) { return detail::lgamma_impl(x); } +template dual abs(const dual & x) { return detail::abs_impl(x); } +template dual fabs(const dual & x) { return detail::fabs_impl(x); } +template dual fmax(const dual & x, const dual & y) { return detail::fmax_impl(x, y); } +template dual fmin(const dual & x, const dual & y) { return detail::fmin_impl(x, y); } + +template dual frexp(const dual & x, int* exp) { return detail::frexp_impl(x, exp); } +template dual ldexp(const dual & x, int exp) { return detail::ldexp_impl(x, exp); } +//template dual trunc(const dual & x) { return detail::trunc_impl(x); } +template dual trunc(const dual & x) { return detail::trunc_impl(x); } +template dual floor(const dual & x) { return detail::floor_impl(x); } +template dual ceil(const dual & x) { return detail::ceil_impl(x); } +template dual round(const dual & x) { return detail::round_impl(x); } + +template int fpclassify(const dual & x) { return detail::fpclassify_impl(x); } +template bool isfinite(const dual & x) { return detail::isfinite_impl(x); } +template bool isnormal(const dual & x) { return detail::isnormal_impl(x); } +template bool isinf(const dual & x) { return detail::isinf_impl(x); } +template bool isnan(const dual & x) { return detail::isnan_impl(x); } +template bool signbit(const dual & x) { return detail::signbit_impl(x); } +template dual copysign(const dual & x, const dual & y) { return detail::copysign_impl(x, y); } + +//template dual random(const dual & low, const dual & high) { return detail::random_impl(low, high); } +//template dual random2(const dual & low, const dual & high) { return detail::random2_impl(low, high); } + +namespace utils { +template int sgn(T val) { + return (T(0) < val) - (val < T(0)); +} +} + +template dual log1p(const dual & x) {return detail::log1p_impl(x);} +template dual expm1(const dual & x) {return detail::expm1_impl(x);} + +#if __cpp_user_defined_literals >= 200809 +/// Dual number literals in namespace duals::literals +inline namespace literals +{ +using duals::dual; +constexpr dual operator""_ef(long double du) +{ + return { 0.0f, static_cast(du) }; +} +constexpr dual operator""_ef(unsigned long long du) +{ + return { 0.0f, static_cast(du) }; +} +constexpr dual operator""_e(long double du) +{ + return { 0.0, static_cast(du) }; +} +constexpr dual operator""_e(unsigned long long du) +{ + return { 0.0, static_cast(du) }; +} +constexpr dual operator""_el(long double du) +{ + return { 0.0l, du }; +} +constexpr dual operator""_el(unsigned long long du) +{ + return { 0.0l, static_cast(du) }; +} +} // namespace literals +#endif + +// shortcut type names +typedef dual dualf; +typedef dual duald; +typedef dual dualld; +typedef dual hyperdualf; +typedef dual hyperduald; +typedef dual hyperdualld; + +} // namespace duals + +/// /// /// /// /// /// /// /// /// /// /// /// /// /// /// +/// Insert some stuff into std:: +/// /// /// /// /// /// /// /// /// /// /// /// /// /// /// + +#ifdef _LIBCPP_BEGIN_NAMESPACE_STD +_LIBCPP_BEGIN_NAMESPACE_STD +#else +namespace std { +#endif + +// special needs LIBCPP +#if defined(_LIBCPP_BEGIN_NAMESPACE_STD) +template _LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI duals::dual
__constexpr_copysign(duals::dual
a, duals::dual
b); +template _LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI duals::dual
__constexpr_fabs(duals::dual
a); +template _LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI bool __constexpr_isfinite(duals::dual
a); +template _LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI bool __constexpr_isinf(duals::dual
a); +template _LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI duals::dual
__constexpr_fmax(duals::dual
a, duals::dual
b); +template _LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI duals::dual
__constexpr_scalbn(duals::dual
a, int exp); +template _LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI duals::dual
__constexpr_logb(duals::dual
a); +#endif + +// export functions to the std namespace +using duals::exp; +using duals::log; +using duals::log10; +using duals::log2; +using duals::logb; +using duals::pow; +using duals::sqrt; +using duals::cbrt; +using duals::sin; +using duals::cos; +using duals::tan; +using duals::asin; +using duals::acos; +using duals::atan; +using duals::atan2; +using duals::hypot; +using duals::scalbn; +using duals::sinh; +using duals::cosh; +using duals::tanh; +using duals::asinh; +using duals::acosh; +using duals::atanh; +using duals::erf; +using duals::erfc; +using duals::tgamma; +using duals::lgamma; +using duals::abs; +using duals::fabs; +using duals::fmax; +using duals::fmin; +using duals::frexp; +using duals::ldexp; +using duals::trunc; +using duals::floor; +using duals::ceil; +using duals::round; +using duals::fpclassify; +using duals::isfinite; +using duals::isnormal; +using duals::isinf; +using duals::isnan; +using duals::signbit; +using duals::copysign; +//using duals::random; +//using duals::random2; + +// TODO: figure out if still needed +namespace __math { + using duals::isinf; +} + +#ifdef _LIBCPP_END_NAMESPACE_STD +_LIBCPP_END_NAMESPACE_STD +#else +} // namespace std +#endif + +/// /// /// /// /// /// /// /// /// /// /// /// /// /// /// +/// Implementations +/// /// /// /// /// /// /// /// /// /// /// /// /// /// /// + +#include +#include + +#ifdef _LIBCPP_BEGIN_NAMESPACE_STD +_LIBCPP_BEGIN_NAMESPACE_STD +#else +namespace std { +#endif + +#if defined(_LIBCPP_BEGIN_NAMESPACE_STD) +// special needs LIBCPP +template _LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI duals::dual
__constexpr_copysign(duals::dual
a, duals::dual
b) { return duals::copysign(a, b); } +template _LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI duals::dual
__constexpr_fabs(duals::dual
a) { return duals::fabs(a); } +template _LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI bool __constexpr_isfinite(duals::dual
a) { return duals::isfinite(a); } +template _LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI bool __constexpr_isinf(duals::dual
a) { return duals::isinf(a); } +template _LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI duals::dual
__constexpr_fmax(duals::dual
a, duals::dual
b) { return duals::fmax(a, b); } +template _LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI duals::dual
__constexpr_scalbn(duals::dual
a, int exp) { return duals::scalbn(a, exp); } +template _LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI duals::dual
__constexpr_logb(duals::dual
a) { return duals::logb(a); } +#endif + +#ifdef _LIBCPP_END_NAMESPACE_STD +_LIBCPP_END_NAMESPACE_STD +#else +} // namespace std +#endif + +namespace duals { +namespace detail { + +/// Exponential e^x +template dual exp_impl(const dual & x) { + using std::exp; + T v = exp(x.rpart()); + return dual(v, + v * x.dpart()); +} + +/// Natural log ln(x) +template dual log_impl(const dual & x) { + using std::log; + T v = log(x.rpart()); + if (x.dpart() == T(0)) + return v; + else + return dual(v, x.dpart() / x.rpart()); +} + +template dual log10_impl(const dual & x) { + using std::log; + return log(x) / log(static_cast(10)); +} + +template dual log2_impl(const dual & x) { + using std::log; + return log(x) / log(static_cast(2)); +} + +template duals::dual logb_impl(const duals::dual & x) { + using std::log; + using std::pow; + using std::abs; + using std::floor; + T v = floor(log(abs(x.rpart())) / log(std::numeric_limits::radix)); + return duals::dual(v, + x.rpart() - pow(2,v) ? (T)0 : std::numeric_limits::infinity()); +} + +// dual ^ U implementation +template +common_t pow_dual_scalar(const dual& x, const U& y) +{ + using std::pow; + typedef typename common_t::value_type V; + return common_t( + pow(x.rpart(), y), + x.dpart() == V(0) ? V(0) : x.dpart() * y * pow(x.rpart(), y - U(1))); +} + +// U ^ dual implementation +template +common_t pow_scalar_dual(const U& x, const dual& y) +{ + return pow(common_t(x), y); +} + +// U ^ dual implementation +template +std::complex> pow_complex_dual(const std::complex>& x, const dual& y) +{ + using dual_t = duals::dual; + + // 1. Compute the magnitude (r = |x|). + // r = sqrt( (Re x)^2 + (Im x)^2 ), where Re x and Im x are dual. + dual_t rr = x.real() * x.real() + x.imag() * x.imag(); + dual_t r = sqrt(rr); // Must have sqrt(dual_t) defined in your dual library + + // 2. Compute the argument (theta = arg(x)). + // theta = atan2( Im x, Re x ) + dual_t theta = atan2(x.imag(), x.real()); // dual-friendly atan2 + + // 3. Compute ln(x) = ln(r) + i * theta + // Then multiply by y: y * ln(x) + // realPart = y * ln(r) + // imagPart = y * theta + dual_t realPart = y * log(r); + dual_t imagPart = y * theta; + + // 4. exponent = exp(realPart) + // Then real/imag of x^y = exponent * cos(imagPart), exponent * + // sin(imagPart) + dual_t exponent = exp(realPart); + + dual_t realOut = exponent * cos(imagPart); + dual_t imagOut = exponent * sin(imagPart); + + // 5. Return the result as a complex>. + return std::complex(realOut, imagOut); +} + +template +std::complex> pow_dual_complex( + const dual& x, const std::complex>& y) +{ + // For clarity, define short aliases: + using dual_t = duals::dual; + + // Extract the real and imaginary parts of y: both are dual. + const dual_t& a = y.real(); // exponent's real part + const dual_t& b = y.imag(); // exponent's imaginary part + + // 1. Compute ln(x). We assume x > 0 in the "real" sense. + // (In forward-mode dual, x can carry derivatives, but rpart(x) should be > + // 0 + // or else you'd need branch handling for negative bases.) + dual_t ln_x = log(x); + + // 2. Compute the real exponent = a * ln_x + // and the imaginary exponent = b * ln_x + dual_t realExp = a * ln_x; // a ln(x) + dual_t imagExp = b * ln_x; // b ln(x) + + // 3. The magnitude is exp(a ln(x)): + dual_t magnitude = exp(realExp); + + // 4. Then the final real and imaginary parts come from: + // Re(x^y) = magnitude * cos(b ln(x)) + // Im(x^y) = magnitude * sin(b ln(x)) + dual_t realPart = magnitude * cos(imagExp); + dual_t imagPart = magnitude * sin(imagExp); + + // 5. Return the complex result. + return std::complex(realPart, imagPart); +} + +// dual ^ dual implementation +template +common_t pow_dual_dual(const dual& f, const dual& g) +{ + using std::log; + using std::pow; +#if 1 + using std::floor; + typedef typename common_t::value_type V; + common_t result; + + if (f.rpart() == T(0) && g.rpart() >= U(1)) { + if (g.rpart() > U(1)) { + result = common_t(0); + } + else { + result = f; + } + } + else { + if (f.rpart() < T(0) && g.rpart() == floor(g.rpart())) { + V const tmp = g.rpart() * pow(f.rpart(), g.rpart() - U(1.0)); + result = common_t(pow(f.rpart(), g.rpart()), + f.dpart() == T(0) ? T(0) : f.dpart() * tmp); + if (g.dpart() != U(0.0)) { + // Return a NaN when g.dpart() != 0. + result.dpart(std::numeric_limits::quiet_NaN()); + } + } + else { + // Handle the remaining cases. For cases 4,5,6,9 we allow the log() + // function to generate -HUGE_VAL or NaN, since those cases result in + // a nonfinite derivative. + V const tmp1 = pow(f.rpart(), g.rpart()); + V const tmp2 = g.rpart() * pow(f.rpart(), g.rpart() - T(1.0)); + V const tmp3 = tmp1 * log(f.rpart()); + result = common_t(tmp1, f.dpart() == T(0) && g.dpart() == U(0) + ? V(0) + : tmp2 * f.dpart() + tmp3 * g.dpart()); + } + } + return result; +#else + T v = pow(f.rpart(), g.rpart()); + return common_t( + v, pow(f.rpart(), g.rpart() - T(1)) * + (g.rpart() * f.dpart() + f.rpart() * log(f.rpart()) * g.dpart())); +#endif +} + +template dual sqrt_impl(const dual & x) { + using std::sqrt; + T v = sqrt(x.rpart()); + if (x.dpart() == T(0)) + return v; + else + return dual(v, x.dpart() / (T(2) * v) ); +} + +template dual cbrt_impl(const dual & x) { + using std::cbrt; + T v = cbrt(x.rpart()); + if (x.dpart() == T(0)) + return v; + else + return dual(v, x.dpart() / (T(3) * v * v) ); +} + +template dual sin_impl(const dual & x) { + using std::sin; + using std::cos; + return dual(sin(x.rpart()), + x.dpart() * cos(x.rpart())); +} + +template dual cos_impl(const dual & x) { + using std::cos; + using std::sin; + return dual(cos(x.rpart()), + -sin(x.rpart()) * x.dpart()); +} + +template dual tan_impl(const dual & x) { + using std::tan; + T v = tan(x.rpart()); + return dual(v, x.dpart() * (v*v + 1)); +} + +template dual asin_impl(const dual & x) { + using std::asin; + using std::sqrt; + T v = asin(x.rpart()); + if (x.dpart() == T(0)) + return v; + else + return dual(v, x.dpart() / sqrt(1 - x.rpart()*x.rpart())); +} + +template dual acos_impl(const dual & x) { + using std::acos; + using std::sqrt; + T v = acos(x.rpart()); + if (x.dpart() == T(0)) + return v; + else + return dual(v, -x.dpart() / sqrt(1 - x.rpart()*x.rpart())); +} + +template dual atan_impl(const dual & x) { + using std::atan; + T v = atan(x.rpart()); + if (x.dpart() == T(0)) + return v; + else + return dual(v, x.dpart() / (1 + x.rpart() * x.rpart())); +} + +template dual atan2_dual_dual(const dual & y, const dual & x) { + using std::atan2; + T v = atan2(y.rpart(), x.rpart()); + return dual(v, + (x.rpart() * y.dpart() - y.rpart() * x.dpart()) / + (y.rpart() * y.rpart() + x.rpart() * x.rpart())); +} + +template +common_t +atan2_dual_scalar(const dual & y, const U & x) { + using std::atan2; + T v = atan2(y.rpart(), x); + return dual(v, + (x * y.dpart()) / + (y.rpart() * y.rpart() + x * x)); +} + +template +common_t +atan2_scalar_dual(const U & y, const dual & x) { + using std::atan2; + T v = atan2(y, x.rpart()); + return dual(v, + (-y * x.dpart()) / + (y * y + x.rpart() * x.rpart())); +} + +template duals::dual hypot_impl(const duals::dual & x, const duals::dual & y) { + using std::hypot; + return dual(hypot(x.rpart(), y.rpart()), + (x.rpart() * y.dpart() + y.rpart() * x.dpart()) / hypot(x.rpart(), y.rpart())); +} + +template duals::dual scalbn_impl(const duals::dual & arg, int ex) { + return arg * std::pow((T)2, ex); +} + +template dual sinh_impl(const dual & x) { + using std::sinh; + using std::cosh; + return dual(sinh(x.rpart()), + x.dpart() * cosh(x.rpart())); +} + +template dual cosh_impl(const dual & x) { + using std::cosh; + using std::sinh; + return dual(cosh(x.rpart()), + x.dpart() * sinh(x.rpart())); +} + +template dual tanh_impl(const dual & x) { + using std::tanh; + return dual(tanh(x.rpart()), + x.dpart() * (1 - tanh(x.rpart()) * tanh(x.rpart()))); +} + +template dual asinh_impl(const dual & x) { + using std::asinh; + using std::sqrt; + return dual(asinh(x.rpart()), + x.dpart() / sqrt(1 + x.rpart() * x.rpart())); +} + +template dual acosh_impl(const dual & x) { + using std::acosh; + using std::sqrt; + return dual(acosh(x.rpart()), + x.dpart() / sqrt(x.rpart() * x.rpart() - 1)); +} + +template dual atanh_impl(const dual & x) { + using std::atanh; + return dual(atanh(x.rpart()), + x.dpart() / (1 - x.rpart() * x.rpart())); +} + +template dual log1p_impl(const dual & x) { + using std::log1p; + return dual(log1p(x.rpart()), + x.dpart() / (1 + x.rpart())); +} + +template dual expm1_impl(const dual & x) { + using std::expm1; + using std::exp; + return dual(expm1(x.rpart()), + x.dpart() * exp(x.rpart())); +} + +/// The error function. Make sure to `#include ` before +/// `#include ` to use this function. +template dual erf_impl(const dual & x) { + using std::erf; + using std::sqrt; + using std::pow; + using std::exp; + return dual(erf(x.rpart()), + x.dpart() * T(2)/sqrt(T(MY_PI)) * exp(-pow(x.rpart(),T(2)))); +} + +/// Error function complement (1 - erf()). +template dual erfc_impl(const dual & x) { + using std::erfc; + using std::sqrt; + using std::pow; + using std::exp; + return dual(erfc(x.rpart()), + x.dpart() * -T(2)/sqrt(T(MY_PI)) * exp(-pow(x.rpart(),T(2)))); +} + +/// Gamma function. Approximation of the dual part. +// TODO specialize for integers +template dual tgamma_impl(const dual & x) { + using std::tgamma; + T v = tgamma(x.rpart()); + if (x.dpart() == T(0)) + return v; + else { + + int errno_saved = errno; + T h(T(1) / (1ull << (std::numeric_limits::digits / 3))); + T w((tgamma(x.rpart()+h) - tgamma(x.rpart()-h))/(2*h)); + errno = errno_saved; + return dual(v, x.dpart() * w); + } +} + +/// Log of absolute value of gamma function. Approximation of the dual part. +template dual lgamma_impl(const dual & x) { + using std::lgamma; + T v = lgamma(x.rpart()); + if (x.dpart() == T(0)) + return v; + else { +#if CPPDUALS_HAVE_SIGNGAM + int signgam_saved = signgam; +#endif + int errno_saved = errno; + T h(T(1) / (1ull << (std::numeric_limits::digits / 3))); + T w((lgamma(x.rpart()+h) - lgamma(x.rpart()-h))/(2*h)); +#if CPPDUALS_HAVE_SIGNGAM + signgam = signgam_saved; +#endif + errno = errno_saved; + return dual(v, x.dpart() * w); + } +} +template dual abs_impl(const dual & x) { + using std::abs; + return dual(abs(x.rpart()), + x.dpart() * utils::sgn(x.rpart())); +} +template dual fabs_impl(const dual & x) { + using std::fabs; + return dual(fabs(x.rpart()), + x.dpart() * utils::sgn(x.rpart())); +} +template duals::dual fmax_impl(const duals::dual & x, const duals::dual & y) { + return x.rpart() > y.rpart() ? x : y; +} +template duals::dual fmin_impl(const duals::dual & x, const duals::dual & y) { + return x.rpart() <= y.rpart() ? x : y; +} +template duals::dual frexp_impl(const duals::dual & arg, int* exp ) { using std::frexp; return frexp(arg.rpart(), exp); } +template duals::dual ldexp_impl(const duals::dual & arg, int exp ) { return arg * std::pow((T)2,exp); } +template duals::dual trunc_impl(const duals::dual & d) { using std::trunc; return trunc(d.rpart()); } +template dual floor_impl(const dual & x) { + using std::floor; + return dual(floor(x.rpart()), + x.dpart() * utils::sgn(x.rpart()-floor(x.rpart()))); +} +template duals::dual ceil_impl(const duals::dual & d) { using std::ceil; return ceil(d.rpart()); } +template duals::dual round_impl(const duals::dual & d) { using std::round; return round(d.rpart()); } +template int fpclassify_impl(const duals::dual & d) { using std::fpclassify; return fpclassify(d.rpart()); } +template bool isfinite_impl(const duals::dual & d) { using std::isfinite; return isfinite(d.rpart()); } +template bool isnormal_impl(const duals::dual & d) { using std::isnormal; return isnormal(d.rpart()); } +template bool isinf_impl(const duals::dual & d) { using std::isinf; return isinf(d.rpart()); } +template bool isnan_impl(const duals::dual & d) { using std::isnan; return isnan(d.rpart()); } +template bool signbit_impl(const duals::dual & d) { using std::signbit; return signbit(d.rpart()); } +template duals::dual copysign_impl(const duals::dual & x, const duals::dual & y) { + using std::copysign; + T r = copysign(x.rpart(), y.rpart()); + return duals::dual(r, r == x.rpart() ? x.dpart() : -x.dpart()); +} + +} // namespace detail +} // namespace duals + +#include +namespace duals { namespace randos { // Random real value between a and b. @@ -781,290 +1584,18 @@ DT random(DT a = DT(0,0), DT b = DT(1,0)) { random(a.dpart(),b.dpart())); } -/// Complex Conjugate of a dual is just the dual. -template dual conj(const dual & x) { return x; } +} // namespace duals + +#include -/// Conjugate a thing that's not dual and not complex -- it has no -/// complex value so just return it. This is different from -/// std::conj() which promotes the T to a std::complex. -template::value && - !is_complex::value && - std::is_arithmetic::value)> -T conj(const T & x) { return x; } - -/// Dual Conjugate, such that x*dconj(x) = rpart(x)^2. Different -/// function name from complex conjugate conj(). -template dual dconj(const dual & x) { - return dual(x.rpart(), - x.dpart()); +namespace duals { +typedef std::complex cdualf; +typedef std::complex cduald; +typedef std::complex cdualld; } -/// Dual Conjugate of a complex, such that x*dconj(x) = rpart(x)^2. -/// Different function name from complex conjugate conj(). -template std::complex dconj(const std::complex & x) { - return std::complex(dconj(x.real()), dconj(x.imag())); -} - -/// Conjugate a thing that's not dual and not complex. -template::value && - !is_complex::value && - std::is_arithmetic::value)> -T dconj(const T & x) { return x; } - -/// Exponential e^x -template dual exp(const dual & x) { - using std::exp; - T v = exp(x.rpart()); - return dual(v, - v * x.dpart()); -} - -/// Natural log ln(x) -template dual log(const dual & x) { - using std::log; - T v = log(x.rpart()); - if (x.dpart() == T(0)) - return v; - else - return dual(v, x.dpart() / x.rpart()); -} - -template dual log10(const dual & x) { - using std::log; - return log(x) / log(static_cast(10)); -} - -template dual log2(const dual & x) { - using std::log; - return log(x) / log(static_cast(2)); -} - -template -common_t -pow(const dual & x, const dual & y) { - using std::pow; - using std::log; - T v = pow(x.rpart(), y.rpart()); - return common_t(v, - x.dpart() * y.rpart() * pow(x.rpart(), y.rpart() - T(1)) + - y.dpart() * log(x.rpart()) * v); -} - -template -common_t -pow(const dual & x, const U & y) { - using std::pow; - return common_t(pow(x.rpart(), y), - x.dpart() * y * pow(x.rpart(), y - U(1))); -} - -template -common_t -pow(const U & x, const dual & y) { - return pow(common_t(x), y); -} - -namespace utils { -template int sgn(T val) { - return (T(0) < val) - (val < T(0)); -} -} - -template dual abs(const dual & x) { - using std::abs; - return dual(abs(x.rpart()), - x.dpart() * utils::sgn(x.rpart())); -} - -template dual fabs(const dual & x) { - using std::fabs; - return dual(fabs(x.rpart()), - x.dpart() * utils::sgn(x.rpart())); -} - -#if 0 -template dual abs2(const dual & x) { - using std::abs; - return dual(x.rpart() * x.rpart(), - xxx x.dpart() * utils::sgn(x.rpart())); -} -#endif - -template duals::dual copysign(const duals::dual & x, const duals::dual & y) { - using std::copysign; - T r = copysign(x.rpart(), y.rpart()); - return duals::dual(r, r == x.rpart() ? x.dpart() : -x.dpart()); -} - -template duals::dual hypot(const duals::dual & x, const duals::dual & y) { - return sqrt(x*x + y*y); -} - -template duals::dual scalbn(const duals::dual & arg, int ex) { - return arg * std::pow((T)2, ex); -} - -template duals::dual (fmax)(const duals::dual & x, const duals::dual & y) { - return x.rpart() > y.rpart() ? x : y; -} - -template duals::dual (fmin)(const duals::dual & x, const duals::dual & y) { - return x.rpart() <= y.rpart() ? x : y; -} - -template duals::dual logb(const duals::dual & x) { - return duals::log2(x); -} - -template int (fpclassify)(const duals::dual & d) { using std::fpclassify; return (fpclassify)(d.rpart()); } -template bool (isfinite)(const duals::dual & d) { using std::isfinite; return (isfinite)(d.rpart()); } -template bool (isnormal)(const duals::dual & d) { using std::isnormal; return (isnormal)(d.rpart()); } -template bool (isinf)(const duals::dual & d) { using std::isinf; return (isinf)(d.rpart()); } -template bool (isnan)(const duals::dual & d) { using std::isnan; return (isnan)(d.rpart()); } -template bool (signbit)(const duals::dual & d) { using std::signbit; return (signbit)(d.rpart()); } - -template dual sqrt(const dual & x) { - using std::sqrt; - T v = sqrt(x.rpart()); - if (x.dpart() == T(0)) - return v; - else - return dual(v, x.dpart() / (T(2) * v) ); -} - -template dual cbrt(const dual & x) { - using std::cbrt; - T v = cbrt(x.rpart()); - if (x.dpart() == T(0)) - return v; - else - return dual(v, x.dpart() / (T(3) * v * v) ); -} - -template dual sin(const dual & x) { - using std::sin; - using std::cos; - return dual(sin(x.rpart()), - x.dpart() * cos(x.rpart())); -} - -template dual cos(const dual & x) { - using std::cos; - using std::sin; - return dual(cos(x.rpart()), - -sin(x.rpart()) * x.dpart()); -} - -template dual tan(const dual & x) { - using std::tan; - T v = tan(x.rpart()); - return dual(v, x.dpart() * (v*v + 1)); -} - -template dual asin(const dual & x) { - using std::asin; - using std::sqrt; - T v = asin(x.rpart()); - if (x.dpart() == T(0)) - return v; - else - return dual(v, x.dpart() / sqrt(1 - x.rpart()*x.rpart())); -} - -template dual acos(const dual & x) { - using std::acos; - using std::sqrt; - T v = acos(x.rpart()); - if (x.dpart() == T(0)) - return v; - else - return dual(v, -x.dpart() / sqrt(1 - x.rpart()*x.rpart())); -} - -template dual atan(const dual & x) { - using std::atan; - T v = atan(x.rpart()); - if (x.dpart() == T(0)) - return v; - else - return dual(v, x.dpart() / (1 + x.rpart()*x.rpart())); -} - -template dual atan2(const dual & x, const dual & y) { - using std::atan2; - T v = atan2(x.rpart(), y.rpart()); - if (x.dpart() == T(0)) - return v; - else - return dual(v, x.dpart() / (1 + x.rpart()*x.rpart())); -} - -// TODO -template dual sinh(const dual & x); -template dual cosh(const dual & x); -template dual tanh(const dual & x); -template dual asinh(const dual & x); -template dual acosh(const dual & x); -template dual atanh(const dual & x); -template dual log1p(const dual & x); -template dual expm1(const dual & x); - -/// The error function. Make sure to `#include ` before -/// `#include ` to use this function. -template dual erf(const dual & x) { - using std::erf; - using std::sqrt; - using std::pow; - using std::exp; - return dual(erf(x.rpart()), - x.dpart() * T(2)/sqrt(T(MY_PI)) * exp(-pow(x.rpart(),T(2)))); -} - -/// Error function complement (1 - erf()). -template dual erfc(const dual & x) { - using std::erfc; - using std::sqrt; - using std::pow; - using std::exp; - return dual(erfc(x.rpart()), - x.dpart() * -T(2)/sqrt(T(MY_PI)) * exp(-pow(x.rpart(),T(2)))); -} - -/// Gamma function. Approximation of the dual part. -// TODO specialize for integers -template dual tgamma(const dual & x) { - using std::tgamma; - T v = tgamma(x.rpart()); - if (x.dpart() == T(0)) - return v; - else { - int errno_saved = errno; - T h(T(1) / (1ull << (std::numeric_limits::digits / 3))); - T w((tgamma(x.rpart()+h) - tgamma(x.rpart()-h))/(2*h)); - errno = errno_saved; - return dual(v, x.dpart() * w); - } -} - -/// Log of absolute value of gamma function. Approximation of the dual part. -template dual lgamma(const dual & x) { - using std::lgamma; - T v = lgamma(x.rpart()); - if (x.dpart() == T(0)) - return v; - else { -#if CPPDUALS_HAVE_SIGNGAM - int signgam_saved = signgam; -#endif - int errno_saved = errno; - T h(T(1) / (1ull << (std::numeric_limits::digits / 3))); - T w((lgamma(x.rpart()+h) - lgamma(x.rpart()-h))/(2*h)); -#if CPPDUALS_HAVE_SIGNGAM - signgam = signgam_saved; -#endif - errno = errno_saved; - return dual(v, x.dpart() * w); - } -} +#include +namespace duals { /// Putto operator template @@ -1170,48 +1701,6 @@ operator>>(std::basic_istream & is, dual & x) return is; } -#if __cpp_user_defined_literals >= 200809 -/// Dual number literals in namespace duals::literals -inline namespace literals -{ -using duals::dual; -constexpr dual operator""_ef(long double du) -{ - return { 0.0f, static_cast(du) }; -} -constexpr dual operator""_ef(unsigned long long du) -{ - return { 0.0f, static_cast(du) }; -} -constexpr dual operator""_e(long double du) -{ - return { 0.0, static_cast(du) }; -} -constexpr dual operator""_e(unsigned long long du) -{ - return { 0.0, static_cast(du) }; -} -constexpr dual operator""_el(long double du) -{ - return { 0.0l, du }; -} -constexpr dual operator""_el(unsigned long long du) -{ - return { 0.0l, static_cast(du) }; -} -} -#endif - -typedef dual dualf; -typedef dual duald; -typedef dual dualld; -typedef dual hyperdualf; -typedef dual hyperduald; -typedef dual hyperdualld; -typedef std::complex cdualf; -typedef std::complex cduald; -typedef std::complex cdualld; - } // namespace duals #ifdef CPPDUALS_LIBFMT @@ -1221,7 +1710,7 @@ typedef std::complex cdualld; /// Formats a dual number (r,d) as (r+d_e), offering the same /// formatting options as the underlying type - with the addition of /// three optional format options, only one of which may appear -/// directly after the ':' in the format spec: '$', '*', and ',". The +/// directly after the ':' in the format spec: '$', '*', and ','. The /// '*' flag changes the separating _ to a *, producing (r+d*e), where /// r and d are the formatted value_type values. The ',' flag simply /// prints the real and dual parts separated by a comma. As a @@ -1236,47 +1725,61 @@ struct fmt::formatter,Char> : public fmt::formatter { typedef fmt::formatter base; enum style { expr, star, pair } style_ = expr; - internal::dynamic_format_specs specs_; - FMT_CONSTEXPR auto parse(format_parse_context & ctx) -> decltype(ctx.begin()) { - using handler_type = internal::dynamic_specs_handler; - auto type = internal::type_constant::value; - internal::specs_checker handler(handler_type(specs_, ctx), type); + detail::dynamic_format_specs specs_; + + FMT_CONSTEXPR auto parse(parse_context& ctx) -> decltype(ctx.begin()) { auto it = ctx.begin(); - switch (*it) { - case '$': style_ = style::expr; ctx.advance_to(++it); break; - case '*': style_ = style::star; ctx.advance_to(++it); break; - case ',': style_ = style::pair; ctx.advance_to(++it); break; - default: break; + if (it != ctx.end()) { + switch (*it) { + case '$': style_ = style::expr; ctx.advance_to(++it); break; + case '*': style_ = style::star; ctx.advance_to(++it); break; + case ',': style_ = style::pair; ctx.advance_to(++it); break; + default: break; + } } - parse_format_specs(ctx.begin(), ctx.end(), handler); - return base::parse(ctx); + return parse_format_specs(it, ctx.end(), specs_, ctx, + detail::type_constant::value); } + template - auto format(const duals::dual & x, FormatCtx & ctx) -> decltype(ctx.out()) { - format_to(ctx.out(), "("); + auto format(const duals::dual & x, FormatCtx & ctx) const -> decltype(ctx.out()) { + auto specs = specs_; + if (specs.dynamic()) { + detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, + specs.width_ref, ctx); + detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision, + specs.precision_ref, ctx); + } + + auto out = ctx.out(); + *out++ = '('; if (style_ == style::pair) { - base::format(x.rpart(), ctx); - format_to(ctx.out(), ","); - base::format(x.dpart(), ctx); - return format_to(ctx.out(), ")"); + out = detail::write(out, x.rpart(), specs, ctx.locale()); + *out++ = ','; + out = detail::write(out, x.dpart(), specs, ctx.locale()); + } else { + if (x.rpart() || !x.dpart()) + out = detail::write(out, x.rpart(), specs, ctx.locale()); + if (x.dpart()) { + if (x.rpart() && x.dpart() >= 0) + specs.set_sign(sign::plus); + out = detail::write(out, x.dpart(), specs, ctx.locale()); + if (style_ == style::star) { + *out++ = '*'; + *out++ = 'e'; + } else { + *out++ = '_'; + *out++ = 'e'; + } + if (std::is_same::type,float>::value) *out++ = 'f'; + if (std::is_same::type,long double>::value) *out++ = 'l'; + } } - if (x.rpart() || !x.dpart()) - base::format(x.rpart(), ctx); - if (x.dpart()) { - if (x.rpart() && x.dpart() >= 0 && specs_.sign != sign::plus) - format_to(ctx.out(), "+"); - base::format(x.dpart(), ctx); - if (style_ == style::star) - format_to(ctx.out(), "*e"); - else - format_to(ctx.out(), "_e"); - if (std::is_same::type,float>::value) format_to(ctx.out(), "f"); - if (std::is_same::type,long double>::value) format_to(ctx.out(), "l"); - } - return format_to(ctx.out(), ")"); + *out++ = ')'; + return out; } }; -#endif +#endif // CPPDUALS_LIBFMT #ifdef CPPDUALS_LIBFMT_COMPLEX #ifndef CPPDUALS_LIBFMT @@ -1294,7 +1797,7 @@ struct fmt::formatter,Char> : public fmt::formatter /// options as the underlying type - with the addition of three /// optional format options, only one of which may appear directly /// after the ':' in the format spec (before any fill or align): '$' -/// (the default if no flag is specified), '*', and ',". The '*' flag +/// (the default if no flag is specified), '*', and ','. The '*' flag /// adds a * before the 'i', producing (a+b*i), where a and b are the /// formatted value_type values. The ',' flag simply prints the real /// and complex parts separated by a comma (same as iostreams' format). @@ -1308,82 +1811,53 @@ struct fmt::formatter,Char> : public fmt::formatter { typedef fmt::formatter base; enum style { expr, star, pair } style_ = expr; - internal::dynamic_format_specs specs_; - FMT_CONSTEXPR auto parse(format_parse_context & ctx) -> decltype(ctx.begin()) { - using handler_type = internal::dynamic_specs_handler; - auto type = internal::type_constant::value; - internal::specs_checker handler(handler_type(specs_, ctx), type); + detail::dynamic_format_specs specs_; + + FMT_CONSTEXPR auto parse(parse_context& ctx) -> decltype(ctx.begin()) { auto it = ctx.begin(); - switch (*it) { - case '$': style_ = style::expr; ctx.advance_to(++it); break; - case '*': style_ = style::star; ctx.advance_to(++it); break; - case ',': style_ = style::pair; ctx.advance_to(++it); break; - default: break; + if (it != ctx.end()) { + switch (*it) { + case '$': style_ = style::expr; ctx.advance_to(++it); break; + case '*': style_ = style::star; ctx.advance_to(++it); break; + case ',': style_ = style::pair; ctx.advance_to(++it); break; + default: break; + } } - parse_format_specs(ctx.begin(), ctx.end(), handler); - //todo: fixup alignment - return base::parse(ctx); + // Let base parser handle any nested format chars first + auto end = base::parse(ctx); + // Now parse the format specs for this formatter + parse_format_specs(end, ctx.end(), specs_, ctx, + detail::type_constant::value); + return end; } + template - auto format(const std::complex & x, FormatCtx & ctx) -> decltype(ctx.out()) { + auto format(const std::complex & x, FormatCtx & ctx) const -> decltype(ctx.out()) { format_to(ctx.out(), "("); if (style_ == style::pair) { base::format(x.real(), ctx); format_to(ctx.out(), ","); base::format(x.imag(), ctx); - return format_to(ctx.out(), ")"); - } - if (x.real() || !x.imag()) - base::format(x.real(), ctx); - if (x.imag()) { - if (x.real() && x.imag() >= 0 && specs_.sign != sign::plus) - format_to(ctx.out(), "+"); - base::format(x.imag(), ctx); - if (style_ == style::star) - format_to(ctx.out(), "*i"); - else - format_to(ctx.out(), "i"); - if (std::is_same::type,float>::value) format_to(ctx.out(), "f"); - if (std::is_same::type,long double>::value) format_to(ctx.out(), "l"); + } else { + if (x.real() || !x.imag()) + base::format(x.real(), ctx); + if (x.imag()) { + // The base formatter will handle the negative sign + if (x.real() && x.imag() >= 0 && sign::plus != specs_.sign()) { + format_to(ctx.out(), "+"); + } + base::format(x.imag(), ctx); + if (style_ == style::star) + format_to(ctx.out(), "*i"); + else + format_to(ctx.out(), "i"); + if (std::is_same::type,float>::value) format_to(ctx.out(), "f"); + if (std::is_same::type,long double>::value) format_to(ctx.out(), "l"); + } } return format_to(ctx.out(), ")"); } }; -#endif - -#ifdef _LIBCPP_BEGIN_NAMESPACE_STD -_LIBCPP_BEGIN_NAMESPACE_STD -#else -namespace std { -#endif - -#ifndef PARSED_BY_DOXYGEN - -#define make_math(T) \ - inline T (frexp)(const duals::dual & arg, int* exp ) { return (frexp)(arg.rpart(), exp); } \ - inline duals::dual (ldexp)(const duals::dual & arg, int exp ) { return arg * std::pow((T)2,exp); } \ - inline T (trunc)(const duals::dual & d) { return (trunc)(d.rpart()); } \ - inline T (floor)(const duals::dual & d) { return (floor)(d.rpart()); } \ - inline T (ceil)(const duals::dual & d) { return (ceil)(d.rpart()); } \ - inline T (round)(const duals::dual & d) { return (round)(d.rpart()); } \ - inline int (fpclassify)(const duals::dual & d) { return (fpclassify)(d.rpart()); } \ - inline bool (isfinite)(const duals::dual & d) { return (isfinite)(d.rpart()); } \ - inline bool (isnormal)(const duals::dual & d) { return (isnormal)(d.rpart()); } \ - inline bool (isinf)(const duals::dual & d) { return (isinf)(d.rpart()); } \ - inline bool (isnan)(const duals::dual & d) { return (isnan)(d.rpart()); } \ - -make_math(float) -make_math(double) -make_math(long double) - -#undef make_math - -#endif // PARSED_BY_DOXYGEN - -#ifdef _LIBCPP_BEGIN_NAMESPACE_STD -_LIBCPP_END_NAMESPACE_STD -#else -} // namespace std -#endif +#endif // CPPDUALS_LIBFMT_COMPLEX #endif // CPPDUALS_DUAL diff --git a/src/include/cppduals/duals/dual_eigen b/src/include/cppduals/duals/dual_eigen index 818c8e7f7..cab406aa4 100644 --- a/src/include/cppduals/duals/dual_eigen +++ b/src/include/cppduals/duals/dual_eigen @@ -141,7 +141,6 @@ namespace Eigen { template struct NumTraits > : GenericNumTraits { - typedef typename NumTraits::Real ReallyReal; typedef duals::dual Real; typedef duals::dual Literal; typedef duals::dual Nested; @@ -159,13 +158,13 @@ struct NumTraits > : GenericNumTraits EIGEN_DEVICE_FUNC static inline Real epsilon() { return Real(NumTraits::epsilon()); } EIGEN_DEVICE_FUNC - static inline ReallyReal dummy_precision() { return NumTraits::dummy_precision(); } + static inline Real dummy_precision() { return NumTraits::dummy_precision(); } EIGEN_DEVICE_FUNC - static inline ReallyReal highest() { return NumTraits::highest(); } + static inline Real highest() { return NumTraits::highest(); } EIGEN_DEVICE_FUNC - static inline ReallyReal lowest() { return NumTraits::lowest(); } + static inline Real lowest() { return NumTraits::lowest(); } EIGEN_DEVICE_FUNC - static inline ReallyReal digits10() { return NumTraits::digits10(); } + static inline int digits10() { return NumTraits::digits10(); } }; #if !defined(CPPDUALS_NO_EIGEN_PROMOTION) @@ -218,6 +217,20 @@ using duals::dconj; namespace internal { +#if 0 +// For MatrixExponential.h to treat duals::dual as a known type and compile it +template struct is_exp_known_type; +template struct matrix_exp_computeUV; +template struct is_exp_known_type> : is_exp_known_type {}; +template +struct matrix_exp_computeUV > : matrix_exp_computeUV +{ + typedef typename NumTraits::Scalar>::Real RealScalar; +}; +#endif + +#if 1 +// this is used by the packet math for SSE to copy raw duals around. template struct real_impl > { @@ -250,7 +263,44 @@ struct real_ref_retval> { typedef typename NumTraits::Real & type; }; + +#else //// +template +struct real_impl > +{ + typedef duals::dual RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const duals::dual& x) + { + return x; + } +}; + +template +struct real_ref_impl> +{ + typedef typename NumTraits >::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar & run(duals::dual & x) + { + return reinterpret_cast(&x)[0]; + } + EIGEN_DEVICE_FUNC + static inline const RealScalar & run(const duals::dual & x) + { + return reinterpret_cast(&x)[0]; + } +}; + +template +struct real_ref_retval> +{ + typedef typename NumTraits>::Real & type; +}; + +#endif /// 0 + template struct scalar_random_op> { EIGEN_EMPTY_STRUCT_CTOR(scalar_random_op) @@ -384,7 +434,8 @@ template struct dconj_helper\\n\", \"\", \"\", \"[\", \"]\")") -add_definitions (-DEIGEN_DEFAULT_IO_FORMAT=${IOFORMAT}) -#add_definitions (-DEIGEN_DEFAULT_IO_FORMAT=EIGEN_IO_FORMAT_OCTAVE) # # Correctness & Coverage # -if (NOT MSVC) - set (OPT_FLAGS "-O2") - set (OPT_FLAGS "-O3;-msse3") - set (OPT_FLAGS "-O3;-mavx2;-mfma") - set (OPT_FLAGS "-O3;-march=native") +message ("OSX_ARCHITECTURES: ${CMAKE_SYSTEM_PROCESSOR}") +set (OSX_ARCHITECTURES "arm64;x86_64") +if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") + set (X86 TRUE) else () - set (OPT_FLAGS "/arch:IA32") - set (OPT_FLAGS "/arch:SSE") - set (OPT_FLAGS "/arch:SSE2") - set (OPT_FLAGS "/arch:AVX2") + set (X86 FALSE) +endif () + +# Set optimization flags only if coverage is not enabled +if (NOT CPPDUALS_CODE_COVERAGE) + if (X86) + if (NOT MSVC) + set (OPT_FLAGS "-O3;-march=native") + else () + set (OPT_FLAGS "/arch:AVX2") + endif () + else () + set (OPT_FLAGS "-O3") + endif () +else() + if (X86) + if (NOT MSVC) + set (OPT_FLAGS "-mavx2") + else () + set (OPT_FLAGS "/arch:AVX2") + endif () + else () + set (OPT_FLAGS "") + endif () endif () -#set (OPT_FLAGS "${OPT_FLAGS};-fsanitize=address;-fno-omit-frame-pointer") set (OPT_FLAGS "${OPT_FLAGS};-DCPPDUALS_VECTORIZE_CDUAL") -#set (OPT_FLAGS "${OPT_FLAGS};-DCPPDUALS_DONT_VECTORIZE") -#set (OPT_FLAGS "${OPT_FLAGS};-DEIGEN_DONT_VECTORIZE") set (ALL_TESTS - test_dual test_funcs test_eigen test_packets + test_dual test_cdual test_funcs test_eigen test_packets test_vectorize test_solve test_expm test_1 test_fmt example ) @@ -70,33 +76,30 @@ foreach (TEST_ ${ALL_TESTS}) add_executable (${TEST} ${TEST_}.cpp) set (PHASE_FLAGS ${OPT_FLAGS} -DPHASE_${PHASE}) - string (REPLACE ";" ", " L2 "${CMAKE_CXX_FLAGS}") + string (REPLACE ";" ", " L2 "${OPT_FLAGS};${CMAKE_CXX_FLAGS}") target_compile_options (${TEST} PUBLIC ${PHASE_FLAGS}) target_compile_definitions (${TEST} PRIVATE "OPT_FLAGS=${L2}") - target_link_libraries (${TEST} gtest_main cppduals_coverage_config) - #target_link_libraries (${TEST} -lasan) - add_dependencies (${TEST} eigenX expokitX) + + # Link with coverage config first to ensure flags are used + target_link_libraries (${TEST} + cppduals_coverage_config # Link coverage first + gtest_main + eigen + expokit + ) + gtest_discover_tests (${TEST} TEST_LIST ${TEST}_targets) set_tests_properties (${${TEST}_targets} PROPERTIES TIMEOUT 10) - # -ftest-coverage endforeach (PHASE) endforeach (TEST_) # special for fmt -target_compile_features (test_fmt_1 PUBLIC cxx_std_14) target_link_libraries (test_fmt_1 fmt::fmt) if (CPPDUALS_BENCHMARK) # # Benchmarks # - - message ("searching: ${DEPS_ROOT} for google benchmark libs") - find_library (BENCHMARK_LIBRARY benchmark PATHS ${DEPS_ROOT}/lib) - find_library (BENCHMARKM_LIBRARY benchmark_main PATHS ${DEPS_ROOT}/lib) - #find_library (PTHREAD_LIBRARY pthread) - message ("BENCHMARK_LIBRARY: ${BENCHMARK_LIBRARY}") - include_directories ("${BENCHMARK_INC_DIR}") if (Boost_FOUND AND NO) add_definitions (-DHAVE_BOOST=1) include_directories ("${Boost_INCLUDE_DIRS}") @@ -110,11 +113,14 @@ if (CPPDUALS_BENCHMARK) set (BLA_STATIC OFF) endif (NOT BLA_STATIC) set (BLA_VENDOR OpenBLAS) - endif (NOT APPLE AND NOT BLA_VENDOR) + endif () find_package (BLAS REQUIRED) #find_package (LAPACK REQUIRED) add_definitions (-DHAVE_BLAS) #add_definitions (-DEIGEN_USE_BLAS) + if (APPLE) + add_definitions (-DACCELERATE_NEW_LAPACK -DACCELERATE_LAPACK_ILP64) + endif () # find lapacke.h cblas.h set (CBLAS_HINTS ${BLAS_DIR} ${LAPACK_DIR} /usr /usr/local /opt /opt/local) @@ -124,18 +130,21 @@ if (CPPDUALS_BENCHMARK) /opt /opt/local /usr/local/opt - /System/Library/Frameworks) + /System/Library/Frameworks + ${BLAS_LIBRARIES} + ) # Finds the include directories for lapacke.h find_path (LAPACKE_INCLUDE_DIRS - NAMES lapacke.h + REQUIRED + NAMES lapacke.h clapack.h HINTS ${CBLAS_HINTS} PATH_SUFFIXES include inc include/x86_64 include/x64 - openblas/include -# Accelerate.framework/Versions/Current/Frameworks/vecLib.framework/Versions/Current/Headers + openblas/include openblas + Frameworks/vecLib.framework/Headers PATHS ${CBLAS_PATHS} - DOC "LAPACK(E) include header lapacke.h") + DOC "LAPACK(E) include header lapacke.h/clapack.h") mark_as_advanced (LAPACKE_INCLUDE_DIRS) if (LAPACKE_INCLUDE_DIRS) include_directories (${LAPACKE_INCLUDE_DIRS}) @@ -145,12 +154,13 @@ if (CPPDUALS_BENCHMARK) # Finds the include directories for cblas*.h find_path (CBLAS_INCLUDE_DIRS + REQUIRED NAMES cblas.h cblas_openblas.h cblas-openblas.h HINTS ${CBLAS_HINTS} PATH_SUFFIXES include inc include/x86_64 include/x64 - openblas/include -# Accelerate.framework/Versions/Current/Frameworks/vecLib.framework/Versions/Current/Headers + openblas/include openblas + Frameworks/vecLib.framework/Headers PATHS ${CBLAS_PATHS} DOC "BLAS include header cblas.h") mark_as_advanced (CBLAS_INCLUDE_DIRS) @@ -161,80 +171,168 @@ if (CPPDUALS_BENCHMARK) break() endif (EXISTS "${CBLAS_INCLUDE_DIRS}/${cblas}") endforeach (cblas) - message ("Found BLAS : ${BLAS_LIBRARIES}") message ("Found cBLAS : ${CBLAS_INCLUDE_DIRS}") message ("Found lapacke : ${LAPACKE_INCLUDE_DIRS}") - set (OPT_FLAGS "") + set (BMK_FLAGS "") if (NOT MSVC) - #set (OPT_FLAGS "-O3;-mavx") - #set (OPT_FLAGS "-O3;-march=native;-fopenmp") - set (OPT_FLAGS "-O3;-msse3;-fopenmp") - set (OPT_FLAGS "-O3") - set (OPT_FLAGS "-O3;-msse3") - set (OPT_FLAGS "-O3;-march=native;-funroll-loops") - set (OPT_FLAGS "-O3;-msse3;-mavx2;-mfma") - set (OPT_FLAGS "-O3;-march=native") - #set (OPT_FLAGS "${OPT_FLAGS};-save-temps;-fverbose-asm") + #set (BMK_FLAGS "-O3;-mavx") + #set (BMK_FLAGS "-O3;-march=native;-fopenmp") + if (X86) + set (BMK_FLAGS "-msse3;-fopenmp") + set (BMK_FLAGS "-msse3") + set (BMK_FLAGS "-march=native;-funroll-loops") + set (BMK_FLAGS "-msse3;-mavx2;-mfma") + else () + set (BMK_FLAGS "-march=native") + endif () + #set (BMK_FLAGS "-O3;${BMK_FLAGS}") + #set (BMK_FLAGS "${BMK_FLAGS};-save-temps;-fverbose-asm") else () - set (OPT_FLAGS "/arch:IA32") - set (OPT_FLAGS "/arch:SSE") - set (OPT_FLAGS "/arch:SSE2") - set (OPT_FLAGS "/arch:AVX2") + set (BMK_FLAGS "/arch:IA32") + set (BMK_FLAGS "/arch:SSE") + set (BMK_FLAGS "/arch:SSE2") + set (BMK_FLAGS "/arch:AVX2") endif () - #set (OPT_FLAGS "${OPT_FLAGS};-DEIGEN_DONT_VECTORIZE") - #set (OPT_FLAGS "${OPT_FLAGS};-DCPPDUALS_DONT_VECTORIZE") - #set (OPT_FLAGS "${OPT_FLAGS};-DCPPDUALS_DONT_VECTORIZE_CDUAL") + #set (BMK_FLAGS "${BMK_FLAGS};-DEIGEN_DONT_VECTORIZE") + #set (BMK_FLAGS "${BMK_FLAGS};-DCPPDUALS_DONT_VECTORIZE") + #set (BMK_FLAGS "${BMK_FLAGS};-DCPPDUALS_DONT_VECTORIZE_CDUAL") - foreach (BENCH bench_dual bench_eigen bench_gemm bench_example bench_fmt) - add_executable (${BENCH} ${BENCH}.cpp) - target_compile_options (${BENCH} PUBLIC ${OPT_FLAGS}) - #set_target_properties (${BENCH} PROPERTIES LINK_FLAGS -fopenmp) - #target_link_options (${BENCH} PUBLIC ${OPT_FLAGS}) - string (REPLACE ";" ", " L2 "${OPT_FLAGS} ${CMAKE_CXX_FLAGS}") - target_compile_definitions (${BENCH} PRIVATE "OPT_FLAGS=${L2}") - add_dependencies (${BENCH} benchmarkX eigenX expokitX) - target_link_libraries (${BENCH} ${BENCHMARK_LIBRARY} -lpthread ${BLAS_LIBRARIES}) - endforeach (BENCH) + foreach (VECTORIZE YES NO) + foreach (BENCH bench_dual bench_eigen bench_exp bench_gemm bench_example bench_fmt) + if (NOT VECTORIZE) + set (BENCHE ${BENCH}) + else () + set (BENCHE ${BENCH}_novec) + endif () + add_executable (${BENCHE} ${BENCH}.cpp) + target_compile_options (${BENCHE} PUBLIC ${BMK_FLAGS}) + if (NOT VECTORIZE) + target_compile_options (${BENCHE} PUBLIC "-DEIGEN_DONT_VECTORIZE") + endif() + #set_target_properties (${BENCH} PROPERTIES LINK_FLAGS -fopenmp) + #target_link_options (${BENCH} PUBLIC ${BMK_FLAGS}) + string (REPLACE ";" ", " L2 "${BMK_FLAGS} ${CMAKE_CXX_FLAGS}") + target_compile_definitions (${BENCHE} PRIVATE "BMK_FLAGS=${L2}") + target_link_libraries (${BENCHE} benchmark::benchmark ${BLAS_LIBRARIES} eigen expokit) + endforeach () + endforeach () target_link_libraries (bench_fmt fmt::fmt) + target_link_libraries (bench_fmt_novec fmt::fmt) endif (CPPDUALS_BENCHMARK) add_executable (sandbox sandbox.cpp) -add_dependencies (sandbox eigenX expokitX ) # mpfrX mprealX -#target_compile_options (sandbox PUBLIC ${OPT_FLAGS}) +#target_compile_options (sandbox PUBLIC ${BMK_FLAGS}) target_compile_options (sandbox PUBLIC -DCPPDUALS_VECTORIZE_CDUAL) if (MSVC) - target_compile_options (sandbox PUBLIC /arch:AVX2) + if (X86) + target_compile_options (sandbox PUBLIC /arch:AVX2) + endif () else () - target_compile_options (sandbox PUBLIC -O1 -msse3 -mavx2 -mfma) + if (X86) + target_compile_options (sandbox PUBLIC -O1 -msse3 -mavx2 -mfma) + else () + target_compile_options (sandbox PUBLIC -O1 ) # -mfpu=neon + endif () endif () set_target_properties (sandbox PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -target_link_libraries (sandbox PUBLIC cppduals_coverage_config) +target_link_libraries (sandbox PUBLIC cppduals_coverage_config eigen expokit) # # Generate coverage reports # -if (CODE_COVERAGE) - add_custom_target (cov - DEPENDS ${ALL_TEST_BINS} - COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target test - COMMAND $ - COMMAND lcov --capture --directory . --output-file coverage.info - COMMAND lcov --remove coverage.info '/usr/*' --output-file coverage.info - COMMAND lcov --remove coverage.info '*/thirdparty/*' --output-file coverage.info - COMMAND lcov --remove coverage.info '*/googletest/*' --output-file coverage.info - COMMAND lcov --list coverage.info +if (CPPDUALS_CODE_COVERAGE) + # Find required tools + get_filename_component(CMAKE_CXX_COMPILER_DIR "${CMAKE_CXX_COMPILER}" DIRECTORY) + set(GENHTML_PATH ${CMAKE_CXX_COMPILER_DIR}/genhtml) + if(NOT EXISTS ${GENHTML_PATH}) + find_program(GENHTML_PATH genhtml REQUIRED) + endif() + + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # Clang + # often in the same directory as clang - search there too + get_filename_component(CMAKE_CXX_COMPILER_DIR "${CMAKE_CXX_COMPILER}" DIRECTORY) + set(LLVM_COV_PATH ${CMAKE_CXX_COMPILER_DIR}/llvm-cov) + set(LLVM_PROFDATA_PATH ${CMAKE_CXX_COMPILER_DIR}/llvm-profdata) + if(NOT EXISTS ${LLVM_COV_PATH}) + find_program(LLVM_COV_PATH llvm-cov REQUIRED) + endif() + if(NOT EXISTS ${LLVM_PROFDATA_PATH}) + find_program(LLVM_PROFDATA_PATH llvm-profdata REQUIRED) + endif() + + add_custom_target(cov + DEPENDS ${ALL_TEST_BINS} + COMMAND ${CMAKE_COMMAND} -E remove_directory coverage/profraw + COMMAND ${CMAKE_COMMAND} -E make_directory coverage/profraw + COMMAND ${CMAKE_COMMAND} --build . --target test "LLVM_PROFILE_FILE=coverage/profraw/%p.profraw" + COMMAND ${LLVM_PROFDATA_PATH} merge -sparse coverage/profraw/*.profraw -o coverage/coverage.profdata + COMMAND ${LLVM_COV_PATH} show + -instr-profile=coverage/coverage.profdata + -format=html -output-dir=coverage/html + -show-line-counts-or-regions + -show-instantiation-summary + ${ALL_TEST_BINS} + COMMAND ${LLVM_COV_PATH} report + -instr-profile=coverage/coverage.profdata + ${ALL_TEST_BINS} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) - add_custom_target (cov-html + elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + # GCC + set(LCOV_PATH ${CMAKE_CXX_COMPILER_DIR}/lcov) + if(NOT EXISTS ${LCOV_PATH}) + find_program(LCOV_PATH lcov REQUIRED) + endif() + # Extract GCC version number and use matching gcov version + execute_process( + COMMAND ${CMAKE_CXX_COMPILER} -dumpversion + OUTPUT_VARIABLE GCC_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + set(GCOV_PATH ${CMAKE_CXX_COMPILER_DIR}/gcov-${GCC_VERSION}) + if(NOT EXISTS ${GCOV_PATH}) + find_program(GCOV_PATH gcov-${GCC_VERSION} REQUIRED) + endif() + + add_custom_target(cov + DEPENDS ${ALL_TEST_BINS} + COMMAND ${CMAKE_COMMAND} -E make_directory coverage + COMMAND ${LCOV_PATH} --directory . --zerocounters + # Add initial capture before running tests + COMMAND ${LCOV_PATH} --directory . --capture --initial --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.base --ignore-errors inconsistent + # Run tests and capture coverage data + COMMAND ctest --output-on-failure + COMMAND ${LCOV_PATH} --directory . --capture --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.info --ignore-errors inconsistent + # Combine baseline and test coverage data + COMMAND ${LCOV_PATH} --add-tracefile coverage/coverage.base --add-tracefile coverage/coverage.info --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.total + # Only look at the coverage of the tests and duals library + COMMAND ${LCOV_PATH} --extract coverage/coverage.total '*/tests/*' '*/duals/*' --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.info + # Remove unwanted paths + #COMMAND ${LCOV_PATH} --remove coverage/coverage.total '/usr/*' --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.info + #COMMAND ${LCOV_PATH} --remove coverage/coverage.info '*/thirdparty/*' --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.info + #COMMAND ${LCOV_PATH} --remove coverage/coverage.info '*/googletest/*' --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.info + # Add --ignore-errors empty to prevent failure on empty coverage data + COMMAND ${LCOV_PATH} --list coverage/coverage.info --ignore-errors empty --gcov-tool ${GCOV_PATH} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) + else() + message(FATAL_ERROR "No coverage tool found for ${CMAKE_CXX_COMPILER_ID}") + endif() + + add_custom_target(cov-html DEPENDS cov - COMMAND rm -rf ../coverage - COMMAND genhtml --ignore-errors source coverage.info --legend --title "make cov" - --output-directory=../coverage - COMMAND echo "output in coverage/index.html" - ) + COMMAND ${CMAKE_COMMAND} -E remove_directory coverage/html + COMMAND ${GENHTML_PATH} --ignore-errors source coverage/coverage.info --legend --title "cppduals coverage" + --output-directory=coverage/html + COMMAND ${CMAKE_COMMAND} -E echo "Coverage report generated at coverage/html/index.html" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) + endif () diff --git a/src/include/cppduals/tests/bench_eigen.cpp b/src/include/cppduals/tests/bench_eigen.cpp index adde638d8..f32304276 100644 --- a/src/include/cppduals/tests/bench_eigen.cpp +++ b/src/include/cppduals/tests/bench_eigen.cpp @@ -11,13 +11,13 @@ // (c)2019 Michael Tesch. tesch1@gmail.com // +#include #include #include #include #include #include "type_name.hpp" -#include #include #include @@ -31,67 +31,6 @@ using namespace duals; template< class T > struct type_identity { typedef T type; }; -namespace Eigen { -namespace internal { -template struct is_exp_known_type; -template struct is_exp_known_type> : is_exp_known_type {}; -#if 0 -template struct MatrixExponentialScalingOp; -template -struct MatrixExponentialScalingOp> -{ - MatrixExponentialScalingOp(int squarings) : m_squarings(squarings) { } - inline const duals::dual operator() (const duals::dual & x) const - { - using std::ldexp; - return ldexp(x, -m_squarings); - } - typedef std::complex> ComplexScalar; - inline const ComplexScalar operator() (const ComplexScalar& x) const - { - using std::ldexp; - return ComplexScalar(ldexp(x.real(), -m_squarings), ldexp(x.imag(), -m_squarings)); - } - - private: - int m_squarings; -}; -#endif -}} -#include - -namespace Eigen { -namespace internal { -template -struct matrix_exp_computeUV > -{ - typedef typename NumTraits::Scalar>::Real RealScalar; - template - static void run(const ArgType& arg, MatrixType& U, MatrixType& V, int& squarings) - { - using std::frexp; - using std::pow; - const RealScalar l1norm = arg.cwiseAbs().colwise().sum().maxCoeff(); - squarings = 0; - if (l1norm < 1.495585217958292e-002) { - matrix_exp_pade3(arg, U, V); - } else if (l1norm < 2.539398330063230e-001) { - matrix_exp_pade5(arg, U, V); - } else if (l1norm < 9.504178996162932e-001) { - matrix_exp_pade7(arg, U, V); - } else if (l1norm < 2.097847961257068e+000) { - matrix_exp_pade9(arg, U, V); - } else { - const RealScalar maxnorm = 5.371920351148152; - frexp(l1norm / maxnorm, &squarings); - if (squarings < 0) squarings = 0; - MatrixType A = arg.unaryExpr(MatrixExponentialScalingOp(squarings)); - matrix_exp_pade13(A, U, V); - } - } -}; -}} - /* encode the type into an integer for benchmark output */ template struct type_num { /* should fail */ }; template<> struct type_num { static constexpr int id = 1; }; @@ -271,87 +210,6 @@ template void B_MatVec(benchmark::State& state) { state.SetComplexityN(state.range(0)); } -template void B_Expm(benchmark::State& state) -{ - int N = state.range(0); - //Rt S(1); - MatrixX A = MatrixX::Random(N, N); - MatrixX B = MatrixX::Zero(N, N); - //A = S * A / A.norm(); - - for (auto _ : state) { - B = A.exp(); - benchmark::ClobberMemory(); - } - - state.counters["type"] = type_num::id; - state.SetComplexityN(state.range(0)); -} - -template void B_ExpPadm(benchmark::State& state) -{ - int N = state.range(0); - //Rt S(1); - MatrixX A = MatrixX::Random(N, N); - MatrixX B = MatrixX::Zero(N, N); - //A = S * A / A.norm(); - - for (auto _ : state) { - B = eexpokit::padm(A); - benchmark::ClobberMemory(); - } - - state.counters["type"] = type_num::id; - state.SetComplexityN(state.range(0)); -} - -template void B_ExpExpv(benchmark::State& state) -{ - int N = state.range(0); - //Rt S(1); - MatrixX A = MatrixX::Zero(N, N); - MatrixX b = MatrixX::Ones(N, 1); - MatrixX c = MatrixX::Zero(N, 1); - //A = S * A / A.norm(); - - // sparse random fill - for (int i = 0; i < 4*N; i++) - A((int)duals::randos::random(0.,N-1.), - (int)duals::randos::random(0.,N-1.)) = duals::randos::random2(); - - for (auto _ : state) { - auto ret = eexpokit::expv(1,A,b); - if (ret.err > 1) { - std::ofstream f("fail.m"); - f << "A=" << A.format(eexpokit::OctaveFmt) << "\n"; - break; - } - // c = ret.w - benchmark::ClobberMemory(); - } - - state.counters["type"] = type_num::id; - state.SetComplexityN(state.range(0)); -} - -template void B_ExpChbv(benchmark::State& state) -{ - int N = state.range(0); - //Rt S(1); - MatrixX A = MatrixX::Random(N, N); - MatrixX b = MatrixX::Zero(N, 1); - MatrixX c = MatrixX::Zero(N, 1); - //A = S * A / A.norm(); - - for (auto _ : state) { - c = eexpokit::chbv(A,b); - benchmark::ClobberMemory(); - } - - state.counters["type"] = type_num::id; - state.SetComplexityN(state.range(0)); -} - #define MAKE_BM_SIMPLE(TYPE1,TYPE2,NF) \ BENCHMARK_TEMPLATE(B_VecVecAdd, TYPE1,TYPE2) V_RANGE(4,NF); \ BENCHMARK_TEMPLATE(B_VecVecSub, TYPE1,TYPE2) V_RANGE(4,NF); \ @@ -359,11 +217,7 @@ template void B_ExpChbv(benchmark::State& state) BENCHMARK_TEMPLATE(B_VecVecDiv, TYPE1,TYPE2) V_RANGE(4,NF); \ BENCHMARK_TEMPLATE(B_MatVec, TYPE1,TYPE2) V_RANGE(4,NF); \ BENCHMARK_TEMPLATE(B_MatMat, TYPE1,TYPE2) V_RANGE(1,NF); \ - BENCHMARK_TEMPLATE(B_MatDiv, TYPE1,TYPE2) V_RANGE(1,NF); \ - BENCHMARK_TEMPLATE(B_Expm, TYPE1) V_RANGE(1,NF); \ - BENCHMARK_TEMPLATE(B_ExpPadm, TYPE1) V_RANGE(1,NF); \ - BENCHMARK_TEMPLATE(B_ExpChbv, TYPE1) V_RANGE(1,NF); \ - BENCHMARK_TEMPLATE(B_ExpExpv, TYPE1) V_RANGE(1,NF) + BENCHMARK_TEMPLATE(B_MatDiv, TYPE1,TYPE2) V_RANGE(1,NF) #define MAKE_BENCHMARKS(TYPE1,TYPE2,NF) \ MAKE_BM_SIMPLE(TYPE1,TYPE2,NF) @@ -389,7 +243,7 @@ MAKE_BM_SIMPLE(cduald, cduald,4); int main(int argc, char** argv) { #ifndef EIGEN_VECTORIZE - static_assert(false, "no vectorization?"); + //static_assert(false, "no vectorization?"); #endif std::cout << "OPT_FLAGS=" << QUOTE(OPT_FLAGS) << "\n"; std::cout << "INSTRUCTIONSET=" << Eigen::SimdInstructionSetsInUse() << "\n"; diff --git a/src/include/cppduals/tests/bench_gemm.cpp b/src/include/cppduals/tests/bench_gemm.cpp index 3426ccecc..53ed76b11 100644 --- a/src/include/cppduals/tests/bench_gemm.cpp +++ b/src/include/cppduals/tests/bench_gemm.cpp @@ -6,12 +6,14 @@ // // (c)2019 Michael Tesch. tesch1@gmail.com // +#include + #if defined(__APPLE__) && defined(__clang__) #include #else -#ifdef EIGEN_LAPACKE +#if defined(EIGEN_LAPACKE) || defined(__APPLE__) #include #else #include @@ -24,13 +26,13 @@ extern "C" { } #endif // defined(__APPLE__) && defined(__clang__) +#include #include #include #include #include #include "type_name.hpp" -#include #include #include @@ -80,6 +82,59 @@ template void B_MatMat(benchmark::State& state) { state.SetComplexityN(state.range(0)); } +// Helper templates to select correct BLAS routine +template +struct blas_gemm; + +#define TRANSPOSE(X) ((X) ? CblasTrans : CblasNoTrans) + +template <> +struct blas_gemm { + static void call(bool tA, bool tB, int m, int n, int k, float alpha, float *A, + int lda, float *B, int ldb, float beta, float *C, int ldc) + { + cblas_sgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB), m, n, k, alpha, A, + lda, B, ldb, beta, C, ldc); + } +}; + +template <> +struct blas_gemm { + static void call(bool tA, bool tB, int m, int n, int k, double alpha, + double *A, int lda, double *B, int ldb, double beta, + double *C, int ldc) + { + cblas_dgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB), m, n, k, alpha, A, + lda, B, ldb, beta, C, ldc); + } +}; + +template <> +struct blas_gemm> { + static void call(bool tA, bool tB, int m, int n, int k, + std::complex alpha, std::complex *A, int lda, + std::complex *B, int ldb, std::complex beta, + std::complex *C, int ldc) + { + cblas_cgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB), m, n, k, &alpha, A, + lda, B, ldb, &beta, C, ldc); + } +}; + +template <> +struct blas_gemm> { + static void call(bool tA, bool tB, int m, int n, int k, + std::complex alpha, std::complex *A, int lda, + std::complex *B, int ldb, std::complex beta, + std::complex *C, int ldc) + { + cblas_zgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB), m, n, k, &alpha, A, + lda, B, ldb, &beta, C, ldc); + } +}; + +#undef TRANSPOSE + template ::value>::type* = nullptr> void matrix_multiplcation(T *A, int Awidth, int Aheight, T *B, int Bwidth, int Bheight, @@ -99,31 +154,12 @@ void matrix_multiplcation(T *A, int Awidth, int Aheight, assert(A_width == B_height); int lda = tA ? m : k; int ldb = tB ? k : n; -#define TRANSPOSE(X) ((X) ? CblasTrans : CblasNoTrans) - // http://www.netlib.org/lapack/explore-html/d7/d2b/dgemm_8f.html - if (!is_complex::value) { - if (sizeof(T) == sizeof(float)) - cblas_sgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB), - m, n, k, 1.0, (float *)A, lda, (float *)B, ldb, - std::real(beta), (float *)AB, n); - else - cblas_dgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB), - m, n, k, 1.0, (double *)A, lda, (double *)B, ldb, - std::real(beta), (double *)AB, n); - } - else { - std::complex alphaf(1,0); - std::complex alpha(1,0); - if (Eigen::NumTraits::digits10() < 10) - cblas_cgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB), - m, n, k, &alphaf, A, lda, B, ldb, &beta, AB, n); - else - cblas_zgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB), - m, n, k, &alpha, A, lda, B, ldb, &beta, AB, n); - } -#undef TRANSPOSE + + // Call the appropriate BLAS routine based on type T + blas_gemm::call(tA, tB, m, n, k, T(1), A, lda, B, ldb, beta, AB, n); } + template ::value>::type* = nullptr> void matrix_multiplcation(T *A, int Awidth, int Aheight, T *B, int Bwidth, int Bheight, @@ -232,10 +268,10 @@ MAKE_BM_SIMPLE(cduald, cduald,4); int main(int argc, char** argv) { #ifndef EIGEN_VECTORIZE - static_assert(false, "no vectorization?"); + //static_assert(false, "no vectorization?"); #endif #ifndef NDEBUG - static_assert(false, "NDEBUG to benchmark?"); + //static_assert(false, "NDEBUG to benchmark?"); #endif std::cout << "OPT_FLAGS=" << QUOTE(OPT_FLAGS) << "\n"; std::cout << "INSTRUCTIONSET=" << Eigen::SimdInstructionSetsInUse() << "\n"; diff --git a/src/include/cppduals/tests/sandbox.cpp b/src/include/cppduals/tests/sandbox.cpp index e6b49b0e1..abae1e8d8 100644 --- a/src/include/cppduals/tests/sandbox.cpp +++ b/src/include/cppduals/tests/sandbox.cpp @@ -12,12 +12,12 @@ * (c)2019 Michael Tesch. tesch1@gmail.com */ +#include #include #include #include #include "type_name.hpp" -#include #include #include #include @@ -60,13 +60,45 @@ template struct common_type,T> { typedef Rando type; }; } -#if 0 +#if EIGEN_ARCH_ARM64 int main(int argc, char * argv[]) { emtx A,B,C; //emtx A,B,C; C = A * B; + + // + using namespace Eigen::internal; + float32x4_t a, b, v3; + float32x2_t f2; + float32x4x2_t yy; + float ff[] = {1., 2., 3., 4.}; + duals::dual x; + const uint64x2_t maskq = {0, (uint64_t)-1}; + const uint64x2_t imaskq = {(uint64_t)-1, 0}; + + std::cout << "a:" << std::hex << maskq[0] << "\n"; + std::cout << "b:" << maskq[1] << "\n"; + + std::cout << "v3=" << v3[0] << ", " << v3[1] << ", " << v3[2] << ", " << v3[3] << "\n"; + std::cout << "f2=" << f2[0] << ", " << f2[1] << "\n"; + + std::cout << ff[0] << ", " << ff[1] << ", " << ff[2] << ", " << ff[3] << "\n"; +#ifdef __ARM_NEON + std::cout << "__ARM_NEON:" << __ARM_NEON << "\n"; +#endif +#ifdef __ARM_NEON_FP + std::cout << "__ARM_NEON_FP:" << __ARM_NEON_FP << "\n"; +#endif +#ifdef __ARM_ARCH + std::cout << "__ARM_ARCH:" << __ARM_ARCH << "\n"; +#endif +#ifdef __ARM_BIG_ENDIAN + std::cout << "__ARM_BIG_ENDIAN:" << __ARM_BIG_ENDIAN << "\n"; +#endif + + return 0; } #elif 0 diff --git a/src/include/cppduals/tests/test_1.cpp b/src/include/cppduals/tests/test_1.cpp index 1203a2721..3f4bd1ce2 100644 --- a/src/include/cppduals/tests/test_1.cpp +++ b/src/include/cppduals/tests/test_1.cpp @@ -81,9 +81,7 @@ expm4(const Eigen::EigenBase & A_, R.setIdentity(); R += B; ReturnT S = B; - int ni = 0; for (int ii = 2; ii < maxt; ii++) { - ni++; S = Real(1.0/ii) * S * B; R += S; auto Sn = S.norm(); diff --git a/src/include/cppduals/tests/test_dual.cpp b/src/include/cppduals/tests/test_dual.cpp index 8c550b7d8..dbcc6c246 100644 --- a/src/include/cppduals/tests/test_dual.cpp +++ b/src/include/cppduals/tests/test_dual.cpp @@ -18,6 +18,7 @@ #include #include +#include #include "gtest/gtest.h" using duals::dualf; @@ -58,7 +59,7 @@ TEST(template_, dual_traits) { // depth EXPECT_EQ(dual_traits::depth, 0); EXPECT_EQ(dual_traits::depth, 0); - EXPECT_EQ(dual_traits::depth, 0); + EXPECT_EQ(dual_traits::depth, 1); EXPECT_EQ(dual_traits::depth, 1); EXPECT_EQ(dual_traits::depth, 2); } @@ -186,6 +187,8 @@ TEST(template_, common_type) { _EXPECT_TRUE(std::is_same); _EXPECT_TRUE(std::is_same); _EXPECT_TRUE(std::is_same); + _EXPECT_TRUE(std::is_same); + _EXPECT_TRUE(std::is_same); _EXPECT_TRUE(std::is_same); _EXPECT_TRUE(std::is_same); @@ -328,6 +331,7 @@ TEST(members, rpart) { EXPECT_EQ(z.rpart(), 4); EXPECT_EQ(z.dpart(), 3); } + TEST(members, dpart) { EXPECT_EQ(dpart(3), 0); dualf z(2,3); @@ -555,6 +559,15 @@ TEST(comparison, ge) { EXPECT_FALSE(1 >= a); } +#if 0 +TEST(simple_ops, add) { + // https://gitlab.com/tesch1/cppduals/-/issues/11 + duals::dual> x; + x = x+std::complex(1., 2.); + duals::dual> y = sqrt(x+std::complex(1., 2.)); +} +#endif + TEST(compound_assign, same_type) { // OP= dualf x = 2 + 4_e; @@ -977,25 +990,6 @@ TEST(non_class, random2) { EXPECT_NE(c2.dpart(), 0); EXPECT_NE(c1.rpart(), c2.rpart()); EXPECT_NE(c1.dpart(), c2.dpart()); - - // cdualf - cdualf d1 = duals::randos::random2(); - cdualf d2 = duals::randos::random2(); - EXPECT_NE(d1.real().rpart(), 0); - EXPECT_NE(d1.real().dpart(), 0); - EXPECT_NE(d1.imag().rpart(), 0); - EXPECT_NE(d1.imag().dpart(), 0); - - EXPECT_NE(d2.real().rpart(), 0); - EXPECT_NE(d2.real().dpart(), 0); - EXPECT_NE(d2.imag().rpart(), 0); - EXPECT_NE(d2.imag().dpart(), 0); - - EXPECT_NE(d1.real().rpart(), d2.real().rpart()); - EXPECT_NE(d1.real().dpart(), d2.real().dpart()); - - EXPECT_NE(d1.imag().rpart(), d2.imag().rpart()); - EXPECT_NE(d1.imag().dpart(), d2.imag().dpart()); } TEST(smoke, funcs) { @@ -1097,6 +1091,17 @@ TEST(complex, mixing) { // complex * real -> complex // complex * dual -> complex ? + // pow_dual_complex + B = pow(1_ef, C); + // pow_complex_dual + B = pow(C, 1_ef); + + // pow_dual_dual + B = pow(1_ef, 2_ef); + // pow_dual_scalar + B = pow(1_ef, 2); + // pow_scalar_dual + B = pow(2, 1_ef); } int main(int argc, char **argv) diff --git a/src/include/cppduals/tests/test_eigen.cpp b/src/include/cppduals/tests/test_eigen.cpp index 61dbaccd8..fa6cc5701 100644 --- a/src/include/cppduals/tests/test_eigen.cpp +++ b/src/include/cppduals/tests/test_eigen.cpp @@ -16,11 +16,12 @@ * (c)2019 Michael Tesch. tesch1@gmail.com */ -#include "type_name.hpp" #include +#include "type_name.hpp" #include #include #include + #include //#include #include "eexpokit/padm.hpp" @@ -39,10 +40,13 @@ using duals::is_complex; using duals::dual_traits; using namespace duals::literals; -typedef std::complex complexd; +typedef long double ldouble; typedef std::complex complexf; -typedef std::complex cduald; +typedef std::complex complexd; +typedef std::complex complexld; typedef std::complex cdualf; +typedef std::complex cduald; +typedef std::complex cdualld; template using emtx = Eigen::Matrix; template using smtx = Eigen::SparseMatrix; @@ -60,49 +64,6 @@ template using ecdf = Eigen::Matrix ; EXPECT_NEAR(rpart(A), rpart(B),tol); \ EXPECT_NEAR(dpart(A), dpart(B),tol) -/// Simple taylor series, truncated when |S| is "small enough" -template -ReturnT -expm4(const Eigen::EigenBase & A_, - typename DerivedA::RealScalar mn = std::numeric_limits::epsilon() * 1000) -{ - //std::cerr << "do PO:" << type_name() << "\n"; - typedef typename DerivedA::RealScalar Real; - using std::isfinite; - const DerivedA & A = A_.derived(); - int maxt = std::numeric_limits::digits; - int s = log2(rpart(A.derived().norm())) + 1; - s = std::max(0, s); - - auto B = A * pow(Real(2), -s); - ReturnT R(A.rows(), A.cols()); - R.setIdentity(); - R += B; - ReturnT S = B; - for (int ii = 2; ii < maxt; ii++) { - S = S * B * Real(1.0/ii); - R += S; - auto Sn = S.norm(); - if (!isfinite(Sn)) { - std::cout << "expm() non-finite norm:" << Sn << " at " << ii << "\n"; - std::cout << " |R| = " << R.norm() << " s=" << s << "\n" - << " |A| = " << rpart(A.real().norm()) << "\n" - << " |A/2^s|=" << rpart(A.real().norm()/pow(2,s)) << "\n"; - break; - } - // converged yet? - if (Sn < mn) - break; - if (ii == maxt - 1) { - std::cout << "expm() didn't converge in " << maxt << " |S| = " << Sn << "\n"; - throw std::invalid_argument("no converge"); - } - } - - for (; s; s--) - R = R * R; - return R; -} TEST(Eigen, NumTraits) { //::testing::StaticAssertTypeEq>::Real, float>(); @@ -448,11 +409,12 @@ TEST(measure, norm) { b = 3; Rt d(1); MatrixD x; - x << d; + x.array() = d; MatrixD a = (MatrixD() << 1,2,3, 4,5+5_ef,6, 7,8,9).finished(); //typename MatrixD::Index index; EXPECT_EQ(a.sum(), 45 + 5_ef); + EXPECT_EQ(x.sum(), 9); EXPECT_NEAR(rpart(a.norm()), 16.8819430161341337282, 1e-5); EXPECT_NEAR(rpart(a.mean()), 5, 1e-5); EXPECT_NEAR(dpart(a.mean()), 0.555555555555555, 1e-5); @@ -510,31 +472,49 @@ TEST(dpart, matrix) { EXPECT_EQ((dpart(AA) - CC).norm(),0); } -TEST(func, expm) { - typedef float T; - typedef dual dualt; - typedef std::complex> cdualt; -#define NN 3 -#define N2 6 - emtx a,b; - a = emtx::Random(); - a.array() += 1.1 + 2.2_ef; - a.setZero(); - a = eexpokit::padm(a); - EXPECT_LT((a - emtx::Identity()).norm(), 1e-6) << "a=" << a << "\n"; - a *= 1+2_e; - EXPECT_LT((a - emtx::Identity()).norm(), 1e-6) << "a=" << a << "\n"; +TEST(eigen, exp_typechecks) { + typedef emtx Mat; + typedef emtx Matd; + EXPECT_FALSE(Eigen::internal::is_exp_known_type::value); + EXPECT_FALSE(Eigen::internal::is_exp_known_type::value); - emtx c; - //b = a + 1_e * emtx::Random(); - c.setZero(); - c = c.exp(); - //c = expm4(c); - EXPECT_LT((c - emtx::Identity()).norm(), 1e-6) << "b=" << b << "\n"; - #undef NN - #undef N2 + typedef emtx Matc; + typedef emtx Matcd; + EXPECT_FALSE(Eigen::internal::is_exp_known_type::value); + EXPECT_FALSE(Eigen::internal::is_exp_known_type::value); } +const bool _exp = true; +const bool _padm = false; + +#define TEST_EXP(SCALAR_T, SIDE, EXP_OR_PADM) \ + TEST(func, exp_##SCALAR_T##_##SIDE##EXP_OR_PADM) { \ + emtx a,b; \ + a = emtx::Random(); \ + a.setZero(); \ + if (EXP_OR_PADM == _exp) a = a.exp(); \ + else a = eexpokit::padm(a); \ + EXPECT_LT((a - emtx::Identity()).norm(), 1e-6) << "a=" << a << "\n"; \ +} + +#define TEST_EXP_SIZES(SCALAR_T, EXP_OR_PADM) \ + TEST_EXP(SCALAR_T, 3, EXP_OR_PADM) \ + TEST_EXP(SCALAR_T, 4, EXP_OR_PADM) \ + TEST_EXP(SCALAR_T, 17, EXP_OR_PADM) + +#define TEST_EXP_SIZES_EOP(SCALAR_T) \ + TEST_EXP_SIZES(SCALAR_T, _padm) \ + TEST_EXP_SIZES(SCALAR_T, _exp) + +// just make sure padm is working +TEST_EXP_SIZES_EOP(float) +TEST_EXP_SIZES_EOP(double) +TEST_EXP_SIZES_EOP(ldouble) +TEST_EXP_SIZES_EOP(complexf) +TEST_EXP_SIZES_EOP(complexd) +TEST_EXP_SIZES_EOP(complexld) + +/* testing engine */ #define QUOTE(...) STRFY(__VA_ARGS__) #define STRFY(...) #__VA_ARGS__ diff --git a/src/include/cppduals/tests/test_expm.cpp b/src/include/cppduals/tests/test_expm.cpp index b42461d45..3e8e21e9b 100644 --- a/src/include/cppduals/tests/test_expm.cpp +++ b/src/include/cppduals/tests/test_expm.cpp @@ -16,8 +16,8 @@ * (c)2019 Michael Tesch. tesch1@gmail.com */ -#include "type_name.hpp" #include +#include "type_name.hpp" #include #include #include @@ -104,7 +104,7 @@ expm4(const Eigen::EigenBase & A_, return R; } -template > +template , int N2 = 2*NN> void dexpm() { //typedef std::complex T; //typedef std::complex> dualt; @@ -167,8 +167,6 @@ void dexpm() { << "eA2=" << eA2.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n"; EXPECT_LT((dA1 - dA2).norm(), tol) << "dA1=" << dA1.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n" << "dA2=" << dA2.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n"; -#undef NN -#undef N2 } #if defined(PHASE_1) diff --git a/src/include/cppduals/tests/test_fmt.cpp b/src/include/cppduals/tests/test_fmt.cpp index 42111318d..376845e44 100644 --- a/src/include/cppduals/tests/test_fmt.cpp +++ b/src/include/cppduals/tests/test_fmt.cpp @@ -14,6 +14,7 @@ * (c)2019 Michael Tesch. tesch1@gmail.com */ #include +//#include #define CPPDUALS_LIBFMT #define CPPDUALS_LIBFMT_COMPLEX #include @@ -29,79 +30,131 @@ typedef std::complex cdualf; using namespace duals::literals; using namespace std::complex_literals; +TEST(libfmt, float_) { + std::string s = fmt::format("{:.1f}", 2.f); + EXPECT_EQ(s, "2.0"); +} +TEST(libfmt, double_) { + std::string s = fmt::format("{:.1f}", 2.); + EXPECT_EQ(s, "2.0"); +} TEST(libfmt, complex_) { - std::string s = fmt::format("{}", 2.f + 3if); + std::string s = fmt::format("{:.1f}", 2.f + 3if); EXPECT_EQ(s, "(2.0+3.0if)"); + s = fmt::format("{:.2f}", 2.f + 3if); + EXPECT_EQ(s, "(2.00+3.00if)"); } TEST(libfmt, complex_el) { std::string s = fmt::format("{}", 2.l + 3il); - EXPECT_EQ(s, "(2.0+3.0il)"); + EXPECT_EQ(s, "(2+3il)"); } TEST(libfmt, complex_flags) { std::string s; s = fmt::format("{}", 2. + 3i); - EXPECT_EQ(s, "(2.0+3.0i)"); - + EXPECT_EQ(s, "(2+3i)"); +} +TEST(libfmt, complex_flags_dollar) { + std::string s; s = fmt::format("{:$}", 2. + 3i); - EXPECT_EQ(s, "(2.0+3.0i)"); - + EXPECT_EQ(s, "(2+3i)"); +} +TEST(libfmt, complex_flags_star) { + std::string s; s = fmt::format("{:*}", 2. + 3i); + EXPECT_EQ(s, "(2+3*i)"); +} +TEST(libfmt, complex_flags_star_f) { + std::string s; + s = fmt::format("{:*.1f}", 2. + 3i); EXPECT_EQ(s, "(2.0+3.0*i)"); +} +TEST(libfmt, complex_flags_comma) { + std::string s; + s = fmt::format("{:,.1f}", 2. + 3i); + EXPECT_EQ(s, "(2.0,3.0)"); s = fmt::format("{:,}", 2. + 3i); - EXPECT_EQ(s, "(2.0,3.0)"); + EXPECT_EQ(s, "(2,3)"); +} + +TEST(libfmt, complex_flags_a) { + std::string s; // + + s = fmt::format("{:$+}", 2. + 3i); + EXPECT_EQ(s, "(+2+3i)"); + + s = fmt::format("{:$+.1f}", 2. + 3i); EXPECT_EQ(s, "(+2.0+3.0i)"); s = fmt::format("{:*+}", 2. + 3i); - EXPECT_EQ(s, "(+2.0+3.0*i)"); + EXPECT_EQ(s, "(+2+3*i)"); s = fmt::format("{:,+}", 2. + 3i); - EXPECT_EQ(s, "(+2.0,+3.0)"); + EXPECT_EQ(s, "(+2,+3)"); +} + +TEST(libfmt, complex_flags_b) { + std::string s; // + - s = fmt::format("{:$+}", 2. - 3i); - EXPECT_EQ(s, "(+2.0-3.0i)"); + EXPECT_EQ(s, "(+2-3i)"); s = fmt::format("{:*+}", 2. - 3i); - EXPECT_EQ(s, "(+2.0-3.0*i)"); + EXPECT_EQ(s, "(+2-3*i)"); s = fmt::format("{:,+}", 2. - 3i); + EXPECT_EQ(s, "(+2,-3)"); + + s = fmt::format("{:,+.1f}", 2. - 3i); EXPECT_EQ(s, "(+2.0,-3.0)"); } + TEST(libfmt, complex_all_real) { std::string s; s = fmt::format("{}", 2. + 0i); + EXPECT_EQ(s, "(2)"); + + s = fmt::format("{:.1f}", 2. + 0i); EXPECT_EQ(s, "(2.0)"); s = fmt::format("{:*}", 2. + 0i); - EXPECT_EQ(s, "(2.0)"); + EXPECT_EQ(s, "(2)"); s = fmt::format("{:,}", 2. + 0i); + EXPECT_EQ(s, "(2,0)"); + + s = fmt::format("{:,.1f}", 2. + 0i); EXPECT_EQ(s, "(2.0,0.0)"); } + TEST(libfmt, complex_all_imag) { std::string s; s = fmt::format("{}", 0. + 3i); + EXPECT_EQ(s, "(3i)"); + + s = fmt::format("{:.1f}", 0. + 3i); EXPECT_EQ(s, "(3.0i)"); s = fmt::format("{:*}", 0. + 3i); - EXPECT_EQ(s, "(3.0*i)"); + EXPECT_EQ(s, "(3*i)"); s = fmt::format("{:,}", 0. + 3i); - EXPECT_EQ(s, "(0.0,3.0)"); + EXPECT_EQ(s, "(0,3)"); } TEST(libfmt, complex_plus) { std::string s = fmt::format("{:+}", 1. + 3i); + EXPECT_EQ(s, "(+1+3i)"); + + s = fmt::format("{:+.1f}", 1. + 3i); EXPECT_EQ(s, "(+1.0+3.0i)"); s = fmt::format("{:+}", 1. - 3i); - EXPECT_EQ(s, "(+1.0-3.0i)"); + EXPECT_EQ(s, "(+1-3i)"); } TEST(libfmt, complex_g) { std::string s = fmt::format("{:g}", 2.f + 3if); @@ -118,67 +171,102 @@ TEST(libfmt, complex_gel) { TEST(libfmt, dual_) { std::string s = fmt::format("{}", 2 + 3_ef); + EXPECT_EQ(s, "(2+3_ef)"); + + s = fmt::format("{:.1f}", 2 + 3_ef); EXPECT_EQ(s, "(2.0+3.0_ef)"); } TEST(libfmt, dual_el) { std::string s = fmt::format("{}", 2 + 3_el); + EXPECT_EQ(s, "(2+3_el)"); + + s = fmt::format("{:.1f}", 2 + 3_el); EXPECT_EQ(s, "(2.0+3.0_el)"); } TEST(libfmt, dual_flags) { std::string s; s = fmt::format("{}", 2. + 3_e); - EXPECT_EQ(s, "(2.0+3.0_e)"); + EXPECT_EQ(s, "(2+3_e)"); s = fmt::format("{:$}", 2. + 3_e); + EXPECT_EQ(s, "(2+3_e)"); + + s = fmt::format("{:$.1f}", 2. + 3_e); EXPECT_EQ(s, "(2.0+3.0_e)"); s = fmt::format("{:*}", 2. + 3_e); - EXPECT_EQ(s, "(2.0+3.0*e)"); + EXPECT_EQ(s, "(2+3*e)"); s = fmt::format("{:,}", 2. + 3_e); + EXPECT_EQ(s, "(2,3)"); + + s = fmt::format("{:,.1f}", 2. + 3_e); EXPECT_EQ(s, "(2.0,3.0)"); // + + s = fmt::format("{:$+}", 2. + 3_e); - EXPECT_EQ(s, "(+2.0+3.0_e)"); + EXPECT_EQ(s, "(+2+3_e)"); s = fmt::format("{:*+}", 2. + 3_e); + EXPECT_EQ(s, "(+2+3*e)"); + + s = fmt::format("{:*+.1f}", 2. + 3_e); EXPECT_EQ(s, "(+2.0+3.0*e)"); s = fmt::format("{:,+}", 2. + 3_e); - EXPECT_EQ(s, "(+2.0,+3.0)"); + EXPECT_EQ(s, "(+2,+3)"); // + - s = fmt::format("{:$+}", 2. - 3_e); - EXPECT_EQ(s, "(+2.0-3.0_e)"); + EXPECT_EQ(s, "(+2-3_e)"); s = fmt::format("{:*+}", 2. - 3_e); + EXPECT_EQ(s, "(+2-3*e)"); + + s = fmt::format("{:*+.1f}", 2. - 3_e); EXPECT_EQ(s, "(+2.0-3.0*e)"); s = fmt::format("{:,+}", 2. - 3_e); - EXPECT_EQ(s, "(+2.0,-3.0)"); + EXPECT_EQ(s, "(+2,-3)"); + s = fmt::format("{:,+}", 2. + 3_e); + EXPECT_EQ(s, "(+2,+3)"); } TEST(libfmt, dual_all_real) { std::string s; s = fmt::format("{}", 2 + 0_e); - EXPECT_EQ(s, "(2.0)"); + EXPECT_EQ(s, "(2)"); s = fmt::format("{:*}", 2 + 0_e); - EXPECT_EQ(s, "(2.0)"); + EXPECT_EQ(s, "(2)"); s = fmt::format("{:,}", 2 + 0_e); - EXPECT_EQ(s, "(2.0,0.0)"); + EXPECT_EQ(s, "(2,0)"); } TEST(libfmt, dual_all_dual) { std::string s; s = fmt::format("a{}b", 0 + 3_e); + EXPECT_EQ(s, "a(3_e)b"); + s = fmt::format("a{:.1f}b", 0 + 3_e); EXPECT_EQ(s, "a(3.0_e)b"); s = fmt::format("a{:*}b", 0 + 3_e); - EXPECT_EQ(s, "a(3.0*e)b"); + EXPECT_EQ(s, "a(3*e)b"); s = fmt::format("a{:,}b", 0 + 3_e); + EXPECT_EQ(s, "a(0,3)b"); + s = fmt::format("a{:,.1f}b", 0 + 3_e); EXPECT_EQ(s, "a(0.0,3.0)b"); } + +TEST(libfmt, dual_plus) { + std::string s = fmt::format("{:+}", 1. + 3_e); + EXPECT_EQ(s, "(+1+3_e)"); + + s = fmt::format("{:+.1f}", 1. + 3_e); + EXPECT_EQ(s, "(+1.0+3.0_e)"); + + s = fmt::format("{:+}", 1. - 3_e); + EXPECT_EQ(s, "(+1-3_e)"); +} TEST(libfmt, dual_g) { std::string s = fmt::format("{:g}", 2 + 3_ef); EXPECT_EQ(s, "(2+3_ef)"); @@ -194,6 +282,12 @@ TEST(libfmt, dual_gel) { std::string s = fmt::format("{:g}", 2 + 3_el); EXPECT_EQ(s, "(2+3_el)"); } + +TEST(libfmt, dual_cd) { + std::string s = fmt::format("{}", cdualf(2 + 3_ef, 4 + 5_ef)); + EXPECT_EQ(s, "((2+3_ef)+(4+5_ef)i)"); +} + TEST(libfmt, dual_cgt) { std::string s = fmt::format("{:g}", cdualf(2 + 3_ef, 4 + 5_ef)); EXPECT_EQ(s, "((2+3_ef)+(4+5_ef)i)"); @@ -208,6 +302,10 @@ TEST(libfmt, dual_cgts) { s = fmt::format("{:,*g}", cdualf(2 + 3_ef, 4 + 5_ef)); EXPECT_EQ(s, "((2+3*ef),(4+5*ef))"); + // nonsense but should still work + s = fmt::format("{:*,g}", cdualf(2 + 3_ef, 4 + 5_ef)); + EXPECT_EQ(s, "((2,3)+(4,5)*i)"); + s = fmt::format("{:,,g}", cdualf(2 + 3_ef, 4 + 5_ef)); EXPECT_EQ(s, "((2,3),(4,5))"); } diff --git a/src/include/cppduals/tests/test_funcs.cpp b/src/include/cppduals/tests/test_funcs.cpp index c897cad45..ae9947214 100644 --- a/src/include/cppduals/tests/test_funcs.cpp +++ b/src/include/cppduals/tests/test_funcs.cpp @@ -32,25 +32,38 @@ typedef std::complex complexd; // not verify precision. #define FD_CHECK(T, F, ...) \ TEST(func##_##T, F) { \ + using std::isnan; \ for (T x : __VA_ARGS__) { \ T prec = 100 * std::sqrt(std::numeric_limits::epsilon()); \ - T dd = dpart(F(x + dual(0,1))); \ + T dd = duals::dpart(F(x + dual(0,1))); \ /*T dx = std::numeric_limits::epsilon() * (T)1000000; */ \ T dx = T(1)/ (1ull << (std::numeric_limits::digits / 3)); \ T fd = (F(x + dx) - F(x - dx)) / (2*dx); \ - EXPECT_CNEAR(dd, fd, prec * std::abs(std::max(std::max(dd,fd),T(1)))) \ - << "dd=" << dd << " fd=" << fd << " x=" << x << " dx=" << dx; \ + if (!isnan(dd) && !isnan(fd)) { \ + EXPECT_CNEAR(dd, fd, \ + prec * std::abs(std::max(std::max(dd,fd),T(1)))) \ + << "dd=" << dd << " fd=" << fd << " x=" << x << " dx=" << dx; \ + } \ } \ } +#define powL(x) pow(x,2) +#define powR(x) pow(2,x) +#define powLR(x) pow(x,x) + FD_CHECK(double, exp, {-1,0,1}) -FD_CHECK(double, log, {1}) -//FD_CHECK(complexd, log, {-1,1}) TODO -FD_CHECK(double, log10, {1}) -//FD_CHECK(complexd, log10, {-1,0,1}) TODO +FD_CHECK(double, log, {1, 3}) +// FD_CHECK(complexd, log, {-1,1}) TODO +FD_CHECK(double, log10, {1, 3}) + +FD_CHECK(double, powL, {-3.,-1.,-0.4,0.,0.6,1.,2.5}) +FD_CHECK(double, powR, {-3.,-1.,-0.4,0.,0.6,1.,2.5}) +FD_CHECK(double, powLR, {-3.,-1.,-0.4,0.,0.6,1.,2.5}) + +// FD_CHECK(complexd, log10, {-1,0,1}) TODO FD_CHECK(double, sqrt, {0.5,1.0}) FD_CHECK(double, cbrt, {-10.,-0.01,0.01,1.0,10.}) -//FD_CHECK(complexd, sqrt, {0,1}) TODO +// FD_CHECK(complexd, sqrt, {0,1}) TODO FD_CHECK(double, sin, {-1,0,1}) FD_CHECK(double, cos, {-1,0,1}) FD_CHECK(double, tan, {-1,0,1}) @@ -59,12 +72,27 @@ FD_CHECK(double, acos, {-.9,0.,.9}) FD_CHECK(double, atan, {-10,-1,0,1,10}) // TODO: -//FD_CHECK(double, sinh, {0}) -//FD_CHECK(double, cosh, {0}) -//FD_CHECK(double, tanh, {0}) -//FD_CHECK(double, asinh, {0}) -//FD_CHECK(double, acosh, {0}) -//FD_CHECK(double, atanh, {0}) +#define atan2L(x) atan2(x,2) +#define atan2R(x) atan2(2,x) +#define atan2LR(x) atan2(x,x) +FD_CHECK(double, atan2L, {-10.,-1.,0.,1.,10.}) +FD_CHECK(double, atan2R, {-10.,-1.,0.01,1.,10.}) +FD_CHECK(double, atan2LR, {-10.,-1.,0.01,1.,10.}) + +#define hypot2LR(x) hypot(x,x) +FD_CHECK(double, hypot2LR, {-10.,-1.,0.01,1.,10.}) + +#define scalbnL(x) scalbn(x,2) +FD_CHECK(double, scalbnL, {-10.,-1.,0.01,1.,10.}) + +FD_CHECK(double, sinh, {-0.1, 0.1}) +FD_CHECK(double, cosh, {-0.1, 0.1}) +FD_CHECK(double, tanh, {-0.1, 0.1}) +FD_CHECK(double, asinh, {-0.1, 0.1}) +FD_CHECK(double, acosh, {-1.1, 1.1}) +FD_CHECK(double, atanh, {-0.1, 0.1}) +FD_CHECK(double, log1p, {-0.1, 0.1}) +FD_CHECK(double, expm1, {-0.1, 0.1}) FD_CHECK(double, erf, {-1,0,1}) FD_CHECK(double, erfc, {-1,0,1}) @@ -97,6 +125,8 @@ TEST(func, tgamma) { //EXPECT_EQ(tgamma(x).rpart(), 362880); "interestingly", compiling without optimization (-O0) causes this to fail EXPECT_NEAR(tgamma(x).rpart(), 362880, 362880 * 100 * std::numeric_limits::epsilon()); } + +// part selection functions TEST(func, rpart) { dualf x = 10 + 4_e; EXPECT_EQ(rpart(x), 10); @@ -105,16 +135,258 @@ TEST(func, dpart) { dualf x = 2 + 4_e; EXPECT_EQ(dpart(x), 4); } + +// non-differentiable operations on the real part. TEST(func, abs) { + dualf x = -10 + 4_e; + EXPECT_EQ(abs(x), 10); } -TEST(func, arg) { +TEST(func, fabs) { + dualf x = -10 + 4_e; + EXPECT_EQ(fabs(x), 10); +} +TEST(func, fmax) { + dualf x = -10 + 4_e; + dualf y = 10 + 4_e; + EXPECT_EQ(fmax(x, y), 10); +} +TEST(func, fmin) { + dualf x = -10 + 4_e; + dualf y = 10 + 4_e; + EXPECT_EQ(fmin(x, y), -10); +} +TEST(func, frexp) { + dualf x = 6 + 4_e; + int exp = 0; + EXPECT_EQ(frexp(x, &exp), 0.75); + EXPECT_EQ(exp, 3); +} +TEST(func, ldexp) { + dualf x = 0.5 + 4_e; + int exp = 1; + EXPECT_EQ(ldexp(x, exp), 1); +} +TEST(func, trunc) { + dualf x = 1.5 + 4_e; + EXPECT_EQ(trunc(x), 1); +} +TEST(func, floor) { + dualf x = 1.5 + 4_e; + EXPECT_EQ(floor(x), 1); +} +TEST(func, ceil) { + dualf x = 1.5 + 4_e; + EXPECT_EQ(ceil(x), 2); +} +TEST(func, round) { + dualf x = 1.5 + 4_e; + EXPECT_EQ(round(x), 2); +} +// floating point functions +TEST(func, fpclassify) { + dualf x = 1.5 + 4_e; + EXPECT_EQ(fpclassify(x), FP_NORMAL); + EXPECT_EQ(fpclassify(std::numeric_limits::infinity()), FP_INFINITE); + EXPECT_EQ(fpclassify(std::numeric_limits::quiet_NaN()), FP_NAN); + if (std::numeric_limits::has_denorm != std::denorm_absent) { + EXPECT_EQ(fpclassify(std::numeric_limits::denorm_min()), FP_SUBNORMAL); + } + EXPECT_EQ(fpclassify(x+std::numeric_limits::min()), FP_NORMAL); + EXPECT_EQ(fpclassify(2*std::numeric_limits::max()), FP_INFINITE); + EXPECT_EQ(fpclassify(x+std::numeric_limits::epsilon()), FP_NORMAL); +} +TEST(func, isfinite) { + dualf x = 1.5 + 4_e; + EXPECT_EQ(isfinite(x), true); +} +TEST(func, isnormal) { + dualf x = 1.5 + 4_e; + EXPECT_EQ(isnormal(x), true); +} +TEST(func, isinf) { + dualf x = 1.5 + 4_e; + EXPECT_EQ(isinf(x), false); +} +TEST(func, isnan) { + dualf x = 1.5 + 4_e; + EXPECT_EQ(isnan(x), false); +} +TEST(func, signbit) { + dualf x = 1.5 + 4_e; + EXPECT_EQ(signbit(x), false); +} +TEST(func, copysign) { + dualf x = 1.5 + 4_e; + dualf y = -1.3 + 2_e; + EXPECT_EQ(copysign(x, y), -1.5); +} + +// Utility functions +TEST(func, random) { + dualf x = random(0.001 + 0.001_e, 1 + 1_e); + EXPECT_GE(rpart(x), 0.001); + EXPECT_LE(rpart(x), 1); + EXPECT_GE(dpart(x), 0.001); + EXPECT_LE(dpart(x), 1); +} + +TEST(func, random2) { + dualf x = duals::randos::random2(0.001 + 0.001_e, 1 + 1_e); + EXPECT_GE(rpart(x), 0.001); + EXPECT_LE(rpart(x), 1); + EXPECT_GE(dpart(x), 0.001); + EXPECT_LE(dpart(x), 1); +} + +// more tests +TEST(func, logb) { + dualf x = 4 + 1_e; + EXPECT_EQ(rpart(logb(.5 + 1_e)), -1.); + EXPECT_EQ(rpart(logb(1 + 1_e)), 0.); + EXPECT_EQ(rpart(logb(2 + 1_e)), 1.); + EXPECT_EQ(rpart(logb(3 + 1_e)), 1.); + EXPECT_EQ(rpart(logb(4 + 1_e)), 2.); + EXPECT_EQ(rpart(logb(x * x)), 4.); + + EXPECT_EQ(dpart(logb(4 + 8_e)), std::numeric_limits::infinity()); + EXPECT_EQ(dpart(logb(4.01 + 8_e)), 0.); + + EXPECT_EQ(dpart(logb(x * x)), std::numeric_limits::infinity()); + EXPECT_EQ(dpart(logb(3 * x)), 0.); + x += 0.01; + EXPECT_EQ(dpart(logb(3 * x)), 0.); + EXPECT_EQ(dpart(logb(x * x)), 0.); +} + +TEST(func, pow) { + dualf x = pow(0 + 0_e, 0.); + EXPECT_EQ(rpart(x), 1); + EXPECT_EQ(dpart(x), 0); + + dualf y = pow(0 + 0_e, 0. + 0_e); + EXPECT_EQ(rpart(y), 1); + EXPECT_EQ(dpart(y), 0); + + dualf z = pow(0, 0. + 0_e); + EXPECT_EQ(rpart(z), 1); + EXPECT_EQ(dpart(z), 0); +} +TEST(func, pow_complex) { + std::complex C(3+4_ef, 5+6_ef); + std::complex x = std::pow(C, 2+1_ef); + std::complex ref = std::complex(std::pow(std::complex(3,5), 2)); + EXPECT_NEAR(rpart(x.real()), ref.real(), 1e-5); + EXPECT_NEAR(rpart(x.imag()), ref.imag(), 1e-6); + //EXPECT_EQ(dpart(x), std::pow(std::complex(3, 5), 2) * (2+1_ef)); +} + +//---------------------------------------------------------------------- +// Test for pow_dual_complex(const dual& realBase, const std::complex>& complexExponent) +//---------------------------------------------------------------------- +TEST(func, PowDualComplexTest) +{ + // 1) Prepare inputs: + // realBase = 2.0 (with zero derivative for this example) + duald realBase(2.0f); + + // complexExponent = (1.5 + 0.7i), + // each part a dual with .rpart() = 1.5 or 0.7, derivative 0 + std::complex complexExponent(duald(1.5f), duald(0.7f)); + + // 2) Call the function we want to test: + // x^y => pow_dual_complex(realBase, complexExponent) + std::complex result = std::pow(realBase, complexExponent); + + // 3) Reference: use standard pow in double + double dblBase = 2.0; + std::complex dblExponent(1.5, 0.7); + std::complex reference = std::pow(dblBase, dblExponent); + + // 4) Compare the .rpart() of the dual’s real/imag with reference + EXPECT_NEAR(result.real().rpart(), reference.real(), 1e-6); + EXPECT_NEAR(result.imag().rpart(), reference.imag(), 1e-6); +} + +//---------------------------------------------------------------------- +// Test for pow_complex_dual(const std::complex>& complexBase, const dual& realExponent) +//---------------------------------------------------------------------- +TEST(func, PowComplexDualTest) +{ + // 1) Prepare inputs: + // complexBase = (3 + 5i), each part dual with zero derivative + std::complex complexBase(duald(3.0f), duald(5.0f)); + + // realExponent = 2.0 as a dual + duald realExponent(2.0f); + + // 2) Call the function we want to test: + // x^y => pow_complex_dual(complexBase, realExponent) + std::complex result = pow(complexBase, realExponent); + + // 3) Reference: again, standard pow in double + std::complex dblBase(3.0, 5.0); + double dblExponent = 2.0; + std::complex reference = std::pow(dblBase, dblExponent); + + // 4) Compare the .rpart() of the dual’s real/imag with reference + EXPECT_NEAR(result.real().rpart(), reference.real(), 1e-6); + EXPECT_NEAR(result.imag().rpart(), reference.imag(), 1e-6); } TEST(func, norm) { + // TODO } TEST(func, conj) { + // TODO } TEST(func, polar) { + // TODO } +TEST(func, atan) { + EXPECT_EQ(rpart(atan(0 + 1_e)), atan(0)); + EXPECT_EQ(dpart(atan(1_e)), 1); + EXPECT_EQ(dpart(atan(1 + 1_e)), 0.5); // = 1 / (1 + x^2) + EXPECT_EQ(dpart(atan(-2 + 1_e)), 1. / 5.); // = 1 / (1 + x^2) +} +TEST(func, atan2) { + // TODO + //EXPECT_EQ(dpart(atan2(1_e, 1)), 1); + //EXPECT_EQ(dpart(atan2(1 + 1_e, 1)), 0.5); + //EXPECT_EQ(dpart(atan2(-2 + 1_e, 1)), (1. / 5.)); + duald y = 1 + 1_e; + duald x = 1 + 0_e; + auto z = atan2(y, x); + z = atan2(y, x); + EXPECT_EQ(rpart(z), atan2(rpart(y), rpart(x))); + EXPECT_EQ(dpart(z), 0.5); + + y = -2 + 1_e; + x = 1 + 0_e; + z = atan2(y, x); + EXPECT_EQ(rpart(z), atan2(rpart(y), rpart(x))); + EXPECT_EQ(dpart(z), 1. / 5.); + + y = 1 + 0_e; + x = -2 + 1_e; + z = atan2(y, x); + EXPECT_EQ(rpart(z), atan2(rpart(y), rpart(x))); + EXPECT_EQ(dpart(z), -1. / 5.); +} +TEST(func, atan2a) { + // TODO + duald y = 1 + 1_e; + EXPECT_EQ(rpart(atan2(y, 1)), atan2(rpart(y), 1)); + EXPECT_EQ(rpart(atan2(y, 2)), atan2(rpart(y), 2)); + EXPECT_EQ(dpart(atan2(y, 1)), 0.5); + y = 2 + 1_e; + EXPECT_EQ(dpart(atan2(y, -2)), -0.25); +} +TEST(func, atan2b) { + // TODO + duald x = 10 + 1_e; + EXPECT_EQ(rpart(atan2(2, x)), atan2(2, rpart(x))); + EXPECT_EQ(dpart(atan2(2, x)), -1./52); +} + struct pike_f1 { // function diff --git a/src/include/cppduals/tests/test_packets.cpp b/src/include/cppduals/tests/test_packets.cpp index c6f925a12..6300095ae 100644 --- a/src/include/cppduals/tests/test_packets.cpp +++ b/src/include/cppduals/tests/test_packets.cpp @@ -16,8 +16,8 @@ * (c)2019 Michael Tesch. tesch1@gmail.com */ -#include "type_name.hpp" #include +#include "type_name.hpp" #include #include #include @@ -60,6 +60,7 @@ template using ecdf = Eigen::Matrix ; #if !defined(CPPDUALS_DONT_VECTORIZE) && !defined(EIGEN_DONT_VECTORIZE) +#ifdef EIGEN_VECTORIZE_SSE TEST(Packet1cdf, pload_pstore) { using namespace Eigen::internal; cdualf cd1 = cdualf(1+2_ef,3+4_ef); @@ -68,6 +69,7 @@ TEST(Packet1cdf, pload_pstore) { pstore(&cd2, p1); EXPECT_DEQ(cd1, cd2); } +#endif using duals::randos::random2; @@ -89,11 +91,11 @@ using duals::randos::random2; pstore(cd3.data(), p3); \ for (int i = 0; i < N; i++) { \ EXPECT_DNEAR(cd3[i], cd1[i] op cd2[i], tol) \ - << cd1[i] << ',' << cd2[i] << " fail at " << i; \ + << cd1[i] << #op << cd2[i] << "=" << cd3[i] << "!=" << (cd1[i] op cd2[i]) << " fail at " << i << "/" << N; \ } \ } -#define GEN_PACKET_TEST_UN(PTYPE,pop,op) TEST(PTYPE,pop) { \ +#define GEN_PACKET_TEST_UN(PTYPE,pop,op) TEST(PTYPE,pop) { \ using namespace Eigen::internal; \ typedef unpacket_traits::type DTYPE; \ const static int N = unpacket_traits::size; \ @@ -112,7 +114,7 @@ using duals::randos::random2; } \ } -#define GEN_PACKET_TEST_RD(PTYPE,pop,op) TEST(PTYPE,pop) { \ +#define GEN_PACKET_TEST_RD(PTYPE,pop,op) TEST(PTYPE,pop) { \ using namespace Eigen::internal; \ typedef unpacket_traits::type DTYPE; \ const static int N = unpacket_traits::size; \ @@ -131,7 +133,7 @@ using duals::randos::random2; << acc << " " << p2 << " fail."; \ } -#define GEN_PACKET_TEST_REVERSE(PTYPE) TEST(PTYPE,preverse) { \ +#define GEN_PACKET_TEST_REVERSE(PTYPE) TEST(PTYPE,preverse) { \ using namespace Eigen::internal; \ typedef unpacket_traits::type DTYPE; \ const static int N = unpacket_traits::size; \ @@ -149,7 +151,7 @@ using duals::randos::random2; } \ } -#define GEN_PACKET_TEST_FIRST(PTYPE) TEST(PTYPE,pfirst) { \ +#define GEN_PACKET_TEST_FIRST(PTYPE) TEST(PTYPE,pfirst) { \ using namespace Eigen::internal; \ typedef unpacket_traits::type DTYPE; \ const static int N = unpacket_traits::size; \ @@ -323,13 +325,11 @@ using duals::randos::random2; GEN_PACKET_TEST_UN(PTYPE,pconj,conj) // TODO: -//pcplxflip //preduxp //pand //por //pxor //andnot -//pbroadcast4 //ploadquad (for packets w/ size==8) //pgather //pscatter @@ -345,7 +345,7 @@ GEN_CPACKET_TESTS(Packet2cf) GEN_CPACKET_TESTS(Packet4cf) #endif -#ifdef EIGEN_VECTORIZE_SSE +#if defined(EIGEN_VECTORIZE_SSE) || defined(EIGEN_VECTORIZE_NEON) GEN_PACKET_TESTS(Packet2df) GEN_PACKET_TESTS(Packet1dd) GEN_CPACKET_TESTS(Packet1cdf) @@ -368,20 +368,28 @@ TEST(compile, VECTORIZE) { #endif } TEST(compile, SSE) { +#ifdef EIGEN_VECTORIZE_SSE EXPECT_TRUE(std::string(Eigen::SimdInstructionSetsInUse()).find("SSE") != std::string::npos) - << "Not using SSE instructions:" << Eigen::SimdInstructionSetsInUse(); -#ifndef EIGEN_VECTORIZE_SSE - EXPECT_TRUE(false) - << "Not using EIGEN_VECTORIZE_SSE:" << Eigen::SimdInstructionSetsInUse(); +#else + EXPECT_TRUE(true) #endif + << "Not using EIGEN_VECTORIZE_SSE:" << Eigen::SimdInstructionSetsInUse(); } TEST(compile, AVX) { +#ifdef EIGEN_VECTORIZE_AVX EXPECT_TRUE(std::string(Eigen::SimdInstructionSetsInUse()).find("AVX") != std::string::npos) - << "Not using AVX instructions:" << Eigen::SimdInstructionSetsInUse(); -#ifndef EIGEN_VECTORIZE_AVX - EXPECT_TRUE(false) - << "Not using EIGEN_VECTORIZE_AVX:" << Eigen::SimdInstructionSetsInUse(); +#else + EXPECT_TRUE(true) #endif + << "Not using EIGEN_VECTORIZE_AVX:" << Eigen::SimdInstructionSetsInUse(); +} +TEST(compile, NEON) { +#ifdef EIGEN_VECTORIZE_NEON + EXPECT_TRUE(std::string(Eigen::SimdInstructionSetsInUse()).find("NEON") != std::string::npos) +#else + EXPECT_TRUE(true) +#endif + << "Not using EIGEN_VECTORIZE_NEON:" << Eigen::SimdInstructionSetsInUse(); } #define QUOTE(...) STRFY(__VA_ARGS__) diff --git a/src/include/cppduals/tests/test_solve.cpp b/src/include/cppduals/tests/test_solve.cpp index a7c9c8008..326a273f9 100644 --- a/src/include/cppduals/tests/test_solve.cpp +++ b/src/include/cppduals/tests/test_solve.cpp @@ -16,8 +16,8 @@ * (c)2019 Michael Tesch. tesch1@gmail.com */ -#include "type_name.hpp" #include +#include "type_name.hpp" #include #include #include @@ -78,7 +78,10 @@ void solveLu() { emtx B = b + DT(0,1) * emtx::Random(); emtx C,D,E; C = A * B; - D = A.lu().solve(C); + // D = A.lu().solve(C); + // D = A.colPivHouseholderQr().solve(C); + // D = A.bdcSvd().solve(C); + D = A.fullPivLu().solve(C); EXPECT_LT(rpart(B - D).norm(), tol); EXPECT_LT(dpart(B - D).norm(), tol); } diff --git a/src/include/cppduals/tests/test_vectorize.cpp b/src/include/cppduals/tests/test_vectorize.cpp index 1299c7895..0e3560a37 100644 --- a/src/include/cppduals/tests/test_vectorize.cpp +++ b/src/include/cppduals/tests/test_vectorize.cpp @@ -16,8 +16,8 @@ * (c)2019 Michael Tesch. tesch1@gmail.com */ -#include "type_name.hpp" #include +#include "type_name.hpp" #include #include #include @@ -52,7 +52,7 @@ template using ecdf = Eigen::Matrix ; #define _EXPECT_FALSE(...) {typedef __VA_ARGS__ fal; EXPECT_FALSE(fal::value); static_assert(!fal::value, "sa"); } #define ASSERT_DEQ(A,B) ASSERT_EQ(rpart(A), rpart(B)); ASSERT_EQ(dpart(A), dpart(B)) #define ASSERT_DNEAR(A,B,tol) \ - ASSERT_NEAR(abs(rpart((A) - (B))),0,abs(rpart(A))*(tol)); \ + ASSERT_NEAR(abs(rpart((A) - (B))),0,abs(rpart(A))*(tol)) << "rpart " << A << " " << B << "\n"; \ ASSERT_NEAR(abs(dpart((A) - (B))),0,abs(dpart(A))*(tol)) #define EXPECT_DEQ(A,B) EXPECT_EQ(rpart(A), rpart(B)); EXPECT_EQ(dpart(A), dpart(B)) #define EXPECT_DNE(A,B) EXPECT_NE(rpart(A), rpart(B)); EXPECT_NE(dpart(A), dpart(B)) @@ -117,9 +117,9 @@ void elemwise(int N) { ASSERT_DEQ(cca[i], Cca(i)) << "ca mismatch at " << i << "\n"; ASSERT_DEQ(ccb[i], Ccb(i)) << "cb mismatch at " << i << "\n"; } - ASSERT_DNEAR(sum, A.sum(), N*tol); - ASSERT_DNEAR(sum, A.sum(), N*tol); + ASSERT_DNEAR(sum, A.sum(), N*tol) << "sum mismatch at " << sum << " " << A.sum() << "\n"; } +#if defined(PHASE_1) TEST(Vector, full_even_dualf) { elemwise(512); } TEST(Vector, full_even_duald) { elemwise(512); } @@ -136,6 +136,7 @@ TEST(Vector, single_elem_cdualf) { elemwise(1); } TEST(Vector, two_elem_dualf) { elemwise(2); } TEST(Vector, two_elem_duald) { elemwise(2); } TEST(Vector, two_elem_cdualf) { elemwise(2); } +#endif #define DBOUT(X) #define MAKE_MULT_TEST(TYPE1, TYPE2, FIX, SIZE) \ @@ -308,20 +309,30 @@ TEST(flags, VECTORIZE) { #endif } TEST(flags, SSE) { +#ifdef EIGEN_VECTORIZE_SSE EXPECT_TRUE(std::string(Eigen::SimdInstructionSetsInUse()).find("SSE") != std::string::npos) - << "Not using SSE instructions:" << Eigen::SimdInstructionSetsInUse(); -#ifndef EIGEN_VECTORIZE_SSE - EXPECT_TRUE(false) +#else + EXPECT_TRUE(true) +#endif << "Not using EIGEN_VECTORIZE_SSE:" << Eigen::SimdInstructionSetsInUse(); -#endif } + TEST(flags, AVX) { +#ifdef EIGEN_VECTORIZE_AVX EXPECT_TRUE(std::string(Eigen::SimdInstructionSetsInUse()).find("AVX") != std::string::npos) - << "Not using AVX instructions:" << Eigen::SimdInstructionSetsInUse(); -#ifndef EIGEN_VECTORIZE_AVX - EXPECT_TRUE(false) - << "Not using EIGEN_VECTORIZE_AVX:" << Eigen::SimdInstructionSetsInUse(); +#else + EXPECT_TRUE(true) #endif + << "Not using EIGEN_VECTORIZE_AVX:" << Eigen::SimdInstructionSetsInUse(); +} + +TEST(flags, NEON) { +#ifdef EIGEN_VECTORIZE_NEON + EXPECT_TRUE(std::string(Eigen::SimdInstructionSetsInUse()).find("NEON") != std::string::npos) +#else + EXPECT_TRUE(true) +#endif + << "Not using EIGEN_VECTORIZE_NEON:" << Eigen::SimdInstructionSetsInUse(); } #define QUOTE(...) STRFY(__VA_ARGS__) diff --git a/src/include/cppduals/thirdparty/CMakeLists.txt b/src/include/cppduals/thirdparty/CMakeLists.txt index 12b274152..45cd32bc3 100644 --- a/src/include/cppduals/thirdparty/CMakeLists.txt +++ b/src/include/cppduals/thirdparty/CMakeLists.txt @@ -4,12 +4,19 @@ # 3.10 adds support for "gtest_discover_tests" which enumerates the tests inside # of the code and adds them to ctest. # -cmake_minimum_required (VERSION 3.10) +cmake_minimum_required (VERSION 3.14) project (cppduals_thirdparty) include (ExternalProject) get_directory_property (hasParent PARENT_DIRECTORY) +if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.23) + cmake_policy (SET CMP0135 NEW) +endif () +if (CMAKE_XCODE_BUILD_SYSTEM VERSION_GREATER_EQUAL 12) + cmake_policy (SET CMP0114 NEW) +endif () + set (DEPS_ROOT "${CMAKE_BINARY_DIR}/root") if (hasParent) set (DEPS_ROOT "${CMAKE_BINARY_DIR}/thirdparty/root" PARENT_SCOPE) @@ -21,98 +28,109 @@ else (NOT WIN32) set (DOWNLOAD_DIR "C:/Downloads") endif (NOT WIN32) +include(FetchContent) + # -# Google test (https://github.com/google/googletest/blob/master/googletest/README.md) -# +# Google test +# https://google.github.io/googletest/quickstart-cmake.html -# Download and unpack googletest at configure time -configure_file (CMakeLists-gt.txt.in googletest-download/CMakeLists.txt) -execute_process (COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . - RESULT_VARIABLE result - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download) -if (result) - message (FATAL_ERROR "CMake step for googletest failed: ${result}") -endif () -execute_process (COMMAND ${CMAKE_COMMAND} --build . - RESULT_VARIABLE result - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download) -if (result) - message (FATAL_ERROR "Build step for googletest failed: ${result}") -endif () +# +# Configure google-test +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/refs/tags/v1.15.2.zip + URL_HASH MD5=eb1c5c237d13ed12bf492d3997ca6b0d + DOWNLOAD_NAME googletest-v1.15.2.zip + DOWNLOAD_DIR "$ENV{HOME}/Downloads" +) -# Prevent overriding the parent project's compiler/linker -# settings on Windows -set (gtest_force_shared_crt ON CACHE BOOL "" FORCE) +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) -# Add googletest directly to our build. This defines -# the gtest and gtest_main targets. -add_subdirectory ( - ${CMAKE_CURRENT_BINARY_DIR}/googletest-src - ${CMAKE_CURRENT_BINARY_DIR}/googletest-build - EXCLUDE_FROM_ALL) - -# The gtest/gtest_main targets carry header search path -# dependencies automatically when using CMake 2.8.11 or -# later. Otherwise we have to add them here ourselves. -if (CMAKE_VERSION VERSION_LESS 2.8.11) - include_directories ("${gtest_SOURCE_DIR}/include") -endif () - -# Can simply link against gtest or gtest_main as needed. Eg -#add_executable (example example.cpp) -#target_link_libraries (example gtest_main) -#add_test (NAME example_test COMMAND example) +# Enable testing +include(GoogleTest) # # Eigen # -if (CPPDUALS_EIGEN_LATEST) - set (EIGEN_URL http://bitbucket.org/eigen/eigen/get/default.tar.bz2) - #set (EIGEN_MD5 ffc83130dcd37b694c6cf7e905099af9) +if (TRUE) + set (EIGEN_URL https://gitlab.com/libeigen/eigen/-/archive/3.3.8/eigen-3.3.8.tar.bz2) + set (EIGEN_MD5 432ef01499d514f4606343276afa0ec3) + set (EIGEN_MAX_CXX 17) else () - set (EIGEN_URL http://bitbucket.org/eigen/eigen/get/3.3.7.tar.bz2) - set (EIGEN_MD5 05b1f7511c93980c385ebe11bd3c93fa) + set (EIGEN_URL https://gitlab.com/libeigen/eigen/-/archive/3.3.7/eigen-3.3.7.tar.bz2) + set (EIGEN_MD5 b9e98a200d2455f06db9c661c5610496) + set (EIGEN_MAX_CXX 17) endif () - +# +# Eigen +# ExternalProject_Add (eigenX PREFIX eigenX URL ${EIGEN_URL} - #URL_HASH MD5=${EIGEN_MD5} + URL_HASH MD5=${EIGEN_MD5} DOWNLOAD_DIR "$ENV{HOME}/Downloads" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" + LOG_DOWNLOAD ON ) ExternalProject_Get_Property (eigenX source_dir) -if (hasParent AND NOT EIGEN3_INCLUDE_DIRS) - set (EIGEN3_INCLUDE_DIRS "${source_dir}" PARENT_SCOPE) +if (true) # || hasParent + add_library (eigen INTERFACE IMPORTED GLOBAL) + add_dependencies (eigen eigenX) + set_property (TARGET eigen APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${source_dir}") + if (XCODE) + set (IOFORMAT "IOFormat\(FullPrecision, DontAlignCols, \", \", \"\\$\\\\n\", \"\", \"\", \"[\", \"]\"\)") + else () + set (IOFORMAT "IOFormat\(FullPrecision, DontAlignCols, \", \", \"\\$\\n\", \"\", \"\", \"[\", \"]\"\)") + endif () + #target_compile_definitions (eigen INTERFACE EIGEN_DEFAULT_IO_FORMAT=${IOFORMAT}) + #target_compile_definitions (eigen INTERFACE EIGEN_DEFAULT_IO_FORMAT=EIGEN_IO_FORMAT_OCTAVE) + set_property (TARGET eigen APPEND PROPERTY + INTERFACE_COMPILE_DEFINITIONS EIGEN_DEFAULT_IO_FORMAT=${IOFORMAT}) +endif () + +# if c++20, disable warning -Wdeprecated-enum-enum-conversion to eigen +if (CMAKE_CXX_STANDARD GREATER_EQUAL 20) + target_compile_options (eigen INTERFACE -Wno-deprecated-enum-enum-conversion) endif () # -# Eigen-Expokit +# expokit # -set (EEX_SHA 72bf6e445d5ae84218dcbd74580720491e0074db ) +#set (EEX_SHA ee28baa3bf29561501e17e5c68c2e54c85daae19 ) newer? used by spindropsSDL. md5=cebd15f9b5068c0e327753244ff6d394 +set (EEX_SHA c157dec0057be6e183a1ea2a5de353fac7e5e3a7 ) +set (EEX_MD5 89484e51f706398284235b96bc805515 ) ExternalProject_Add (expokitX PREFIX expokitX - URL https://gitlab.com/api/v4/projects/tesch1%2Feigen-expokit/repository/archive.tbz2?sha=${EEX_SHA} - #URL_HASH MD5=96b79de1d01547f6d658865b7caa02ee + URL https://gitlab.com/tesch1/eigen-expokit/-/archive/${EEX_SHA}/eigen-expokit.tar.bz2 + URL_HASH MD5=${EEX_MD5} + DOWNLOAD_NAME eigen-expokit-${EEX_SHA}.tar.bz2 DOWNLOAD_DIR "$ENV{HOME}/Downloads" + UPDATE_COMMAND "" + PATCH_COMMAND "" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" + LOG_DOWNLOAD ON ) ExternalProject_Get_Property (expokitX source_dir) if (hasParent) - set (EXPOKIT_INCLUDE_DIR "${source_dir}" PARENT_SCOPE) -endif() + add_library (expokit INTERFACE IMPORTED GLOBAL) + add_dependencies (expokit expokitX) + set_property (TARGET expokit APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${source_dir}") +endif (hasParent) + # # fmt # ExternalProject_Add (fmtX PREFIX fmtX - URL https://github.com/fmtlib/fmt/archive/6.1.1.tar.gz - URL_HASH MD5=acfb83d44afdca171ee26c597c931e7c + URL https://github.com/fmtlib/fmt/archive/11.1.4.tar.gz + URL_HASH MD5=10c2ae163accd3b82e6b8b4dff877645 DOWNLOAD_DIR ${DOWNLOAD_DIR} CONFIGURE_COMMAND "" BUILD_COMMAND "" @@ -121,7 +139,6 @@ ExternalProject_Add (fmtX ExternalProject_Get_Property (fmtX source_dir) ExternalProject_Get_Property (fmtX binary_dir) if (hasParent) - message (" FMT3_INCLUDE_DIRS: ${source_dir}") add_subdirectory (${source_dir} ${binary_dir} EXCLUDE_FROM_ALL) endif () @@ -131,19 +148,20 @@ if (CPPDUALS_BENCHMARK) # ExternalProject_Add (benchmarkX PREFIX benchmarkX - URL "http://github.com/google/benchmark/archive/v1.5.0.tar.gz" - URL_HASH MD5=eb1466370f3ae31e74557baa29729e9e + URL "http://github.com/google/benchmark/archive/v1.9.1.tar.gz" + URL_HASH MD5=92000ef8b4a7b1e9229972f8943070a7 DOWNLOAD_DIR ${DOWNLOAD_DIR} - CMAKE_ARGS --target install -DBENCHMARK_ENABLE_GTEST_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -DBENCHMARK_USE_LIBCXX=${CPPDUALS_USE_LIBCXX} - "-DCMAKE_INSTALL_PREFIX=" - INSTALL_DIR "${DEPS_ROOT}" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" ) ExternalProject_Get_Property (benchmarkX source_dir) - ExternalProject_Get_Property (benchmarkX install_dir) + ExternalProject_Get_Property (benchmarkX binary_dir) if (hasParent) - set (BENCHMARK_SRC_DIR "${source_dir}" PARENT_SCOPE) - set (BENCHMARK_INC_DIR "${install_dir}/include" PARENT_SCOPE) - message (" BENCHMARK_SRC_DIR: ${BENCHMARK_SRC_DIR}") + # https://github.com/google/benchmark#requirements + set (BENCHMARK_ENABLE_GTEST_TESTS OFF) + set (BENCHMARK_USE_LIBCXX ${CPPDUALS_USE_LIBCXX}) + add_subdirectory (${source_dir} ${binary_dir} EXCLUDE_FROM_ALL) endif() if (Boost_FOUND AND NO) @@ -158,18 +176,6 @@ if (CPPDUALS_BENCHMARK) set (Boost_INCLUDE_DIRS ${Boost_INCLUDE_DIRS} PARENT_SCOPE) endif () - # piranha - ExternalProject_Add (piranhaX PREFIX piranhaX - URL https://github.com/bluescarni/piranha/archive/v0.11.tar.gz - URL_HASH MD5=33482f719f6b8a6a5316f9bd148f5b10 - DOWNLOAD_DIR "$ENV{HOME}/Downloads" - CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" - ) - ExternalProject_Get_Property (piranhaX source_dir) - if (hasParent) - set (PIRANHA_INCLUDE_DIR "${source_dir}/include" PARENT_SCOPE) - endif () - # AuDi ExternalProject_Add (audiX PREFIX audiX URL https://github.com/darioizzo/audi/archive/v1.6.5.tar.gz From 334a67f0de638e730e7a93b814f5c939d2e47c0a Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 4 May 2025 18:34:57 +0200 Subject: [PATCH 23/38] add missing makefile.am, copied from previous cppduals/duals --- src/include/cppduals/duals/Makefile.am | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/include/cppduals/duals/Makefile.am diff --git a/src/include/cppduals/duals/Makefile.am b/src/include/cppduals/duals/Makefile.am new file mode 100644 index 000000000..406a81365 --- /dev/null +++ b/src/include/cppduals/duals/Makefile.am @@ -0,0 +1,6 @@ +## Process this file with automake to produce Makefile.in + +noinst_HEADERS = \ + dual + +MAINTAINERCLEANFILES = Makefile.in From da0338ee5cfc0545521cc5fc1da82665b1491666 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 13 Jun 2025 15:29:45 +0200 Subject: [PATCH 24/38] New CPPDUALS: re-enable compiling with CYGWIN --- src/include/cppduals/duals/dual | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/include/cppduals/duals/dual b/src/include/cppduals/duals/dual index 94688d185..4cb227e84 100644 --- a/src/include/cppduals/duals/dual +++ b/src/include/cppduals/duals/dual @@ -44,9 +44,11 @@ _LIBCPP_END_NAMESPACE_STD /// Configure whether system has POSIX extern int signgam; #ifndef CPPDUALS_HAVE_SIGNGAM #ifndef _WIN32 +#ifndef __CYGWIN__ #define CPPDUALS_HAVE_SIGNGAM 1 #endif #endif +#endif namespace duals { /** From ca0c52ba9493bca88a94231418d9e1241a5b2289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81rp=C3=A1d=20B=C5=B1rmen?= Date: Mon, 23 Jun 2025 14:12:49 +0200 Subject: [PATCH 25/38] BSIM3 3.3.0 undeclared instance IC parameters. --- src/spicelib/devices/bsim3/b3.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/spicelib/devices/bsim3/b3.c b/src/spicelib/devices/bsim3/b3.c index 85bcb15c6..5707423ef 100644 --- a/src/spicelib/devices/bsim3/b3.c +++ b/src/spicelib/devices/bsim3/b3.c @@ -30,6 +30,9 @@ IOP( "geo", BSIM3_GEO, IF_INTEGER, "ACM model drain/source connection"), IOP( "delvto", BSIM3_DELVTO, IF_REAL, "Zero bias threshold voltage variation"), IOP( "mulu0", BSIM3_MULU0, IF_REAL, "Low field mobility multiplier"), IP( "ic", BSIM3_IC, IF_REALVEC , "Vector of DS,GS,BS initial voltages"), +IP( "icvgs", BSIM3_IC_VGS, IF_REAL , "GS initial voltage"), +IP( "icvds", BSIM3_IC_VDS, IF_REAL , "DS initial voltage"), +IP( "icvbs", BSIM3_IC_VBS, IF_REAL , "BS initial voltage"), OP( "gmbs", BSIM3_GMBS, IF_REAL, "Gmb"), OP( "gm", BSIM3_GM, IF_REAL, "Gm"), OP( "gds", BSIM3_GDS, IF_REAL, "Gds"), From af7a600c206ad89ae88078ef9e74c6868990750a Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 24 Jun 2025 10:32:41 +0200 Subject: [PATCH 26/38] Tiny modifications of SEE examples --- .../xspice/see/ihp_simple_sram_seegen_subckt_vary.net | 4 ++-- examples/xspice/see/ihp_two_inverters_set.net | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/examples/xspice/see/ihp_simple_sram_seegen_subckt_vary.net b/examples/xspice/see/ihp_simple_sram_seegen_subckt_vary.net index 30b57790d..eba47cc85 100644 --- a/examples/xspice/see/ihp_simple_sram_seegen_subckt_vary.net +++ b/examples/xspice/see/ihp_simple_sram_seegen_subckt_vary.net @@ -9,7 +9,7 @@ *.param tochar = 1e-13 ; tochar dependency on LET not yet defined .param d = 1 -.param let = 12 +.param let = 8 .param tochar = 1.035e-14 * let * d .csparam let = 'let' ; send param value to .control section @@ -71,7 +71,7 @@ repeat 5 print newlet run plot xcell.n1 xcell.n2+2 wl+4 i(vm1)*10000+6 i(vm2)*10000+8 ylimit -1 10 - let newlet = newlet - 1 + let newlet = newlet + 1 alterparam let = $&newlet reset end diff --git a/examples/xspice/see/ihp_two_inverters_set.net b/examples/xspice/see/ihp_two_inverters_set.net index e31712d0b..5a1938ab6 100644 --- a/examples/xspice/see/ihp_two_inverters_set.net +++ b/examples/xspice/see/ihp_two_inverters_set.net @@ -1,5 +1,4 @@ -* IHP Open PDK -* simple inverter +* simple inverter, IHP Open PDK * Path to the PDK *.include "D:\Spice_general\skywater-pdk\libraries\sky130_fd_pr\latest\models\corners/tt.spice" @@ -11,7 +10,7 @@ * the voltage sources: Vdd vd gnd DC 'vdd' -V1 in gnd pulse(0 'vdd' 0p 200p 100p 5n 10n) +V1 in gnd pulse(0 'vdd' 0p 200p 100p 5n 10.1n) * Eponential current source Iset1 out1 0 EXP(0 250u 'deltat' 10p 'deltat' 500p) @@ -19,7 +18,7 @@ Iset2 out1 0 EXP(0 250u 'deltat2' 10p 'deltat2' 500p) *Cset out 0 10f Xnot1 in vdd vss out1 not1 -Xnot2 out1 vdd vss out not1 +Xnot2 out1 vdd vss out2 not1 Vmeasvss vss 0 0 Vmeasvdd vd vdd 0 @@ -42,7 +41,7 @@ rusage *set nolegend set xbrushwidth=3 plot i(Vmeasvss) i(Vmeasvdd) -plot in out1+2 out+4 +plot in out1+2 out2+4 .endc .end From 0654f477cb74c4da0b280e476319ad9750f051dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81rp=C3=A1d=20B=C5=B1rmen?= Date: Thu, 26 Jun 2025 09:44:47 +0200 Subject: [PATCH 27/38] icvgs, icvds, and icvbs should be IOP. --- src/spicelib/devices/bsim3/b3.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/spicelib/devices/bsim3/b3.c b/src/spicelib/devices/bsim3/b3.c index 5707423ef..d85a462ec 100644 --- a/src/spicelib/devices/bsim3/b3.c +++ b/src/spicelib/devices/bsim3/b3.c @@ -30,9 +30,9 @@ IOP( "geo", BSIM3_GEO, IF_INTEGER, "ACM model drain/source connection"), IOP( "delvto", BSIM3_DELVTO, IF_REAL, "Zero bias threshold voltage variation"), IOP( "mulu0", BSIM3_MULU0, IF_REAL, "Low field mobility multiplier"), IP( "ic", BSIM3_IC, IF_REALVEC , "Vector of DS,GS,BS initial voltages"), -IP( "icvgs", BSIM3_IC_VGS, IF_REAL , "GS initial voltage"), -IP( "icvds", BSIM3_IC_VDS, IF_REAL , "DS initial voltage"), -IP( "icvbs", BSIM3_IC_VBS, IF_REAL , "BS initial voltage"), +IOP( "icvgs", BSIM3_IC_VGS, IF_REAL , "GS initial voltage"), +IOP( "icvds", BSIM3_IC_VDS, IF_REAL , "DS initial voltage"), +IOP( "icvbs", BSIM3_IC_VBS, IF_REAL , "BS initial voltage"), OP( "gmbs", BSIM3_GMBS, IF_REAL, "Gmb"), OP( "gm", BSIM3_GM, IF_REAL, "Gm"), OP( "gds", BSIM3_GDS, IF_REAL, "Gds"), From 36edfd47c2e57aa714d5eb9867b8ac2c012537ff Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 27 Jun 2025 17:18:37 +0200 Subject: [PATCH 28/38] typo --- src/frontend/inp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/inp.c b/src/frontend/inp.c index 93ddea901..c12489ef8 100644 --- a/src/frontend/inp.c +++ b/src/frontend/inp.c @@ -1779,7 +1779,7 @@ com_alterparam(wordlist *wl) /* alterparam subcktname pname=vpval Parameters from within subcircuit are no longer .param lines, but have been added to the .subckt line as pname=paval and to the x line as pval. pval in the x line takes - precedence when subciruit is called, so has to be replaced here. + precedence when subcircuit is called, so has to be replaced here. Find subcircuit with subcktname. After params: Count the number of parameters (notok) until parameter pname is found. When found, search for x-line with subcktname. From 005aad92d7782adc2b6a8c58bb020603d31543e1 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 27 Jun 2025 17:20:34 +0200 Subject: [PATCH 29/38] Fix a bug: do not read in front of string s by s[-1]. Still needs more checking: we remmove and add 'params:'? --- src/frontend/inpcom.c | 114 +++++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 56 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index c3debe462..615baf042 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -3645,74 +3645,76 @@ static char *inp_fix_subckt(struct names *subckt_w_params, char *s) char *equal, *beg, *buffer, *ptr1, *ptr2, *new_str; equal = strchr(s, '='); - if (equal && - (!strstr(s, "params:") || !isspace_c(s[-1]))) { - /* get subckt name (ptr1 will point to name) */ + if (equal) { + char* paramstr = strstr(s, "params:"); + if (!paramstr || !isspace_c(paramstr[-1])) { - ptr1 = skip_token(s); - for (ptr2 = ptr1; *ptr2 && !isspace_c(*ptr2) && !isquote(*ptr2); + /* get subckt name (ptr1 will point to name) */ + ptr1 = skip_token(s); + for (ptr2 = ptr1; *ptr2 && !isspace_c(*ptr2) && !isquote(*ptr2); ptr2++) - ; + ; - add_name(subckt_w_params, copy_substring(ptr1, ptr2)); + add_name(subckt_w_params, copy_substring(ptr1, ptr2)); - /* go to beginning of first parameter word */ - /* s will contain only subckt definition */ - /* beg will point to start of param list */ - beg = skip_back_ws(equal, s); - beg = skip_back_non_ws(beg, s); - beg[-1] = '\0'; /* fixme can be < s */ + /* go to beginning of first parameter word */ + /* s will contain only subckt definition */ + /* beg will point to start of param list */ + beg = skip_back_ws(equal, s); + beg = skip_back_non_ws(beg, s); + beg[-1] = '\0'; /* fixme can be < s */ - head = insert_new_line(NULL, NULL, 0, 0, "internal"); - /* create list of parameters that need to get sorted */ - first_param_card = c = NULL; - while ((ptr1 = strchr(beg, '=')) != NULL) { - ptr2 = skip_ws(ptr1 + 1); - ptr1 = skip_back_ws(ptr1, beg); - ptr1 = skip_back_non_ws(ptr1, beg); - /* ptr1 points to beginning of parameter */ + head = insert_new_line(NULL, NULL, 0, 0, "internal"); + /* create list of parameters that need to get sorted */ + first_param_card = c = NULL; + while ((ptr1 = strchr(beg, '=')) != NULL) { + ptr2 = skip_ws(ptr1 + 1); + ptr1 = skip_back_ws(ptr1, beg); + ptr1 = skip_back_non_ws(ptr1, beg); + /* ptr1 points to beginning of parameter */ - if (*ptr2 == '{') - ptr2 = inp_spawn_brace(ptr2); - else - ptr2 = skip_non_ws(ptr2); + if (*ptr2 == '{') + ptr2 = inp_spawn_brace(ptr2); + else + ptr2 = skip_non_ws(ptr2); - if (!ptr2) { - fprintf(stderr, "Error: Missing } in line %s\n", s); - controlled_exit(EXIT_FAILURE); + if (!ptr2) { + fprintf(stderr, "Error: Missing } in line %s\n", s); + controlled_exit(EXIT_FAILURE); + } + + beg = ptr2; + + c = insert_new_line(c, copy_substring(ptr1, ptr2), 0, 0, "internal"); + + if (!first_param_card) + first_param_card = c; } + /* now sort parameters in order of dependencies */ + inp_sort_params(first_param_card, head, NULL, NULL); - beg = ptr2; + /* create new ordered parameter string for subckt call */ + new_str = NULL; + for (c = head->nextcard; c; c = c->nextcard) + if (new_str == NULL) { + new_str = copy(c->line); + } + else { + char* x = tprintf("%s %s", new_str, c->line); + tfree(new_str); + new_str = x; + } - c = insert_new_line(c, copy_substring(ptr1, ptr2), 0, 0, "internal"); + line_free_x(head, TRUE); - if (!first_param_card) - first_param_card = c; + /* create buffer and insert params: */ + buffer = tprintf("%s params: %s", s, new_str); + + tfree(s); + tfree(new_str); + + s = buffer; } - /* now sort parameters in order of dependencies */ - inp_sort_params(first_param_card, head, NULL, NULL); - - /* create new ordered parameter string for subckt call */ - new_str = NULL; - for (c = head->nextcard; c; c = c->nextcard) - if (new_str == NULL) { - new_str = copy(c->line); - } - else { - char *x = tprintf("%s %s", new_str, c->line); - tfree(new_str); - new_str = x; - } - - line_free_x(head, TRUE); - - /* create buffer and insert params: */ - buffer = tprintf("%s params: %s", s, new_str); - - tfree(s); - tfree(new_str); - - s = buffer; } return s; From 99ed8ceb66bcd52d4f4fab68c0807ac06a6127a9 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 28 Jun 2025 11:11:53 +0200 Subject: [PATCH 30/38] Add error checking when parsing the .dc or dc commands. --- src/spicelib/parser/inp2dot.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/spicelib/parser/inp2dot.c b/src/spicelib/parser/inp2dot.c index 40f81e366..5285297b5 100644 --- a/src/spicelib/parser/inp2dot.c +++ b/src/spicelib/parser/inp2dot.c @@ -288,8 +288,8 @@ dot_dc(char *line, CKTcircuit *ckt, INPtables *tab, struct card *current, NG_IGNORE(gnode); - /* .dc SRC1NAME Vstart1 Vstop1 Vinc1 [SRC2NAME Vstart2 */ - /* Vstop2 Vinc2 */ + /* .dc SRC1NAME Vstart1 Vstop1 Vinc1 [SRC2NAME Vstart2 Vstop2 Vinc2] + Return 1 upon error because of bad syntax (missing tokens).*/ which = ft_find_analysis("DC"); if (which == -1) { LITERR("DC transfer curve analysis unsupported\n"); @@ -297,23 +297,37 @@ dot_dc(char *line, CKTcircuit *ckt, INPtables *tab, struct card *current, } IFC(newAnalysis, (ckt, which, "DC transfer characteristic", &foo, task)); INPgetTok(&line, &name, 1); + if (*name == '\0') + return 1; INPinsert(&name, tab); ptemp.uValue = name; GCA(INPapName, (ckt, which, foo, "name1", &ptemp)); + if (*line == '\0') + return 1; parm = INPgetValue(ckt, &line, IF_REAL, tab); /* vstart1 */ GCA(INPapName, (ckt, which, foo, "start1", parm)); + if (*line == '\0') + return 1; parm = INPgetValue(ckt, &line, IF_REAL, tab); /* vstop1 */ GCA(INPapName, (ckt, which, foo, "stop1", parm)); + if (*line == '\0') + return 1; parm = INPgetValue(ckt, &line, IF_REAL, tab); /* vinc1 */ GCA(INPapName, (ckt, which, foo, "step1", parm)); if (*line) { INPgetTok(&line, &name, 1); + if (*line == '\0') + return 1; INPinsert(&name, tab); ptemp.uValue = name; GCA(INPapName, (ckt, which, foo, "name2", &ptemp)); parm = INPgetValue(ckt, &line, IF_REAL, tab); /* vstart2 */ + if (*line == '\0') + return 1; GCA(INPapName, (ckt, which, foo, "start2", parm)); parm = INPgetValue(ckt, &line, IF_REAL, tab); /* vstop2 */ + if (*line == '\0') + return 1; GCA(INPapName, (ckt, which, foo, "stop2", parm)); parm = INPgetValue(ckt, &line, IF_REAL, tab); /* vinc2 */ GCA(INPapName, (ckt, which, foo, "step2", parm)); @@ -861,6 +875,9 @@ INP2dot(CKTcircuit *ckt, INPtables *tab, struct card *current, TSKtask *task, CK goto quit; } else if ((strcmp(token, ".dc") == 0)) { rtn = dot_dc(line, ckt, tab, current, task, gnode, foo); + if (rtn == 1) { + current->error = copy("Bad syntax! "); + } goto quit; } else if ((strcmp(token, ".tf") == 0)) { rtn = dot_tf(line, ckt, tab, current, task, gnode, foo); From 62d3e3a51d80792bdf50e1186dc835fc7707d040 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 28 Jun 2025 16:07:42 +0200 Subject: [PATCH 31/38] Prevent from endless loop if step evaluates to 0. --- src/spicelib/parser/inp2dot.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/spicelib/parser/inp2dot.c b/src/spicelib/parser/inp2dot.c index 5285297b5..7c871cc66 100644 --- a/src/spicelib/parser/inp2dot.c +++ b/src/spicelib/parser/inp2dot.c @@ -313,6 +313,8 @@ dot_dc(char *line, CKTcircuit *ckt, INPtables *tab, struct card *current, if (*line == '\0') return 1; parm = INPgetValue(ckt, &line, IF_REAL, tab); /* vinc1 */ + if (parm->rValue == 0) + return 1; GCA(INPapName, (ckt, which, foo, "step1", parm)); if (*line) { INPgetTok(&line, &name, 1); @@ -330,6 +332,8 @@ dot_dc(char *line, CKTcircuit *ckt, INPtables *tab, struct card *current, return 1; GCA(INPapName, (ckt, which, foo, "stop2", parm)); parm = INPgetValue(ckt, &line, IF_REAL, tab); /* vinc2 */ + if (parm->rValue == 0) + return 1; GCA(INPapName, (ckt, which, foo, "step2", parm)); } return 0; From ef8858f7dcaed02514b53e8c842fe3cf71063f1d Mon Sep 17 00:00:00 2001 From: dwarning Date: Fri, 4 Jul 2025 17:26:28 +0200 Subject: [PATCH 32/38] allow showmod command for verilog-a models - feature request #100 --- src/osdi/osdiext.h | 2 +- src/osdi/osdiinit.c | 1 + src/osdi/osdiparam.c | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/osdi/osdiext.h b/src/osdi/osdiext.h index 9174a2cf3..936424c86 100644 --- a/src/osdi/osdiext.h +++ b/src/osdi/osdiext.h @@ -22,6 +22,7 @@ extern int OSDIparam(int, IFvalue *, GENinstance *, IFvalue *); extern int OSDIsetup(SMPmatrix *, GENmodel *, CKTcircuit *, int *); extern int OSDIunsetup(GENmodel *, CKTcircuit *); extern int OSDIask(CKTcircuit *, GENinstance *, int, IFvalue *, IFvalue *); +extern int OSDImAsk(CKTcircuit *, GENmodel *, int, IFvalue *); extern int OSDIload(GENmodel *, CKTcircuit *); extern int OSDItemp(GENmodel *, CKTcircuit *); extern int OSDIacLoad(GENmodel *, CKTcircuit *); @@ -39,5 +40,4 @@ extern int OSDIbindCSCComplex(GENmodel *inModel, CKTcircuit *ckt); /* extern int OSDIconvTest(GENmodel*,CKTcircuit*); */ /* extern int OSDImDelete(GENmodel*); */ /* extern int OSDIgetic(GENmodel*,CKTcircuit*); */ -/* extern int OSDImAsk(CKTcircuit*,GENmodel*,int,IFvalue*); */ /* extern int OSDIsoaCheck(CKTcircuit *, GENmodel *); */ diff --git a/src/osdi/osdiinit.c b/src/osdi/osdiinit.c index b647de25e..58174d022 100644 --- a/src/osdi/osdiinit.c +++ b/src/osdi/osdiinit.c @@ -188,6 +188,7 @@ extern SPICEdev *osdi_create_spicedev(const OsdiRegistryEntry *entry) { OSDIinfo->DEVparam = OSDIparam; OSDIinfo->DEVmodParam = OSDImParam; OSDIinfo->DEVask = OSDIask; + OSDIinfo->DEVmodAsk = OSDImAsk; OSDIinfo->DEVsetup = OSDIsetup; OSDIinfo->DEVpzSetup = OSDIsetup; OSDIinfo->DEVtemperature = OSDItemp; diff --git a/src/osdi/osdiparam.c b/src/osdi/osdiparam.c index bf39aaa19..f4664629d 100644 --- a/src/osdi/osdiparam.c +++ b/src/osdi/osdiparam.c @@ -162,3 +162,21 @@ extern int OSDIask(CKTcircuit *ckt, GENinstance *instPtr, int id, void *src = descr->access(inst, model, (uint32_t)id, flags); return osdi_read_param(src, value, id, descr); } + +extern int OSDImAsk(CKTcircuit *ckt, GENmodel *modelPtr, int id, + IFvalue *value) { + + NG_IGNORE(ckt); + + OsdiRegistryEntry *entry = osdi_reg_entry_model(modelPtr); + const OsdiDescriptor *descr = entry->descriptor; + + void *model = osdi_model_data(modelPtr); + + if (id >= (int)(descr->num_params)) { + return (E_BADPARM); + } + + void *src = descr->access(NULL, model, (uint32_t)id, ACCESS_FLAG_READ); + return osdi_read_param(src, value, id, descr); +} From fe20d8a340678c98c9b07619a9b3cf8d5b3bf8ca Mon Sep 17 00:00:00 2001 From: Vadim Kuznetsov Date: Tue, 10 Jun 2025 21:51:57 +0300 Subject: [PATCH 33/38] Add license header for new files --- src/xspice/icm/tlines/cpline/cfunc.mod | 13 +++++++++++-- src/xspice/icm/tlines/cpline/ifspec.ifs | 15 +++++++++++--- src/xspice/icm/tlines/cpmlin/cfunc.mod | 13 +++++++++++-- src/xspice/icm/tlines/cpmlin/ifspec.ifs | 15 +++++++++++--- src/xspice/icm/tlines/mlin/cfunc.mod | 13 +++++++++++-- src/xspice/icm/tlines/mlin/ifspec.ifs | 15 +++++++++++--- src/xspice/icm/tlines/tline/cfunc.mod | 13 +++++++++++-- src/xspice/icm/tlines/tline/ifspec.ifs | 15 +++++++++++--- src/xspice/tlines/msline_common.c | 26 ++++++++++++++++++++++--- src/xspice/tlines/msline_common.h | 26 ++++++++++++++++++++++--- src/xspice/tlines/tline_common.c | 17 +++++++++++++++- src/xspice/tlines/tline_common.h | 17 +++++++++++++++- 12 files changed, 170 insertions(+), 28 deletions(-) diff --git a/src/xspice/icm/tlines/cpline/cfunc.mod b/src/xspice/icm/tlines/cpline/cfunc.mod index 1eeeb3172..83f2f3493 100644 --- a/src/xspice/icm/tlines/cpline/cfunc.mod +++ b/src/xspice/icm/tlines/cpline/cfunc.mod @@ -1,7 +1,16 @@ /* =========================================================================== - FILE cfunc.mod + FILE cfunc.mod + Copyright 2025 Vadim Kuznetsov - (c) Vadim Kuznetsov 2025 + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ diff --git a/src/xspice/icm/tlines/cpline/ifspec.ifs b/src/xspice/icm/tlines/cpline/ifspec.ifs index aa5639010..136ec0982 100644 --- a/src/xspice/icm/tlines/cpline/ifspec.ifs +++ b/src/xspice/icm/tlines/cpline/ifspec.ifs @@ -1,9 +1,18 @@ /* =========================================================================== -FILE ifspec.ifs + FILE ifspec.ifs + Copyright 2025 Vadim Kuznetsov -(c) vadim Kuznetsov 2025 + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -=========================================================================== */ + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ /* Ports connection 4 --||||||-- 3 diff --git a/src/xspice/icm/tlines/cpmlin/cfunc.mod b/src/xspice/icm/tlines/cpmlin/cfunc.mod index c1975dfec..6bfde502a 100644 --- a/src/xspice/icm/tlines/cpmlin/cfunc.mod +++ b/src/xspice/icm/tlines/cpmlin/cfunc.mod @@ -1,7 +1,16 @@ /* =========================================================================== - FILE cfunc.mod + FILE cfunc.mod + Copyright 2025 Vadim Kuznetsov - (c) Vadim Kuznetsov 2025 + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ diff --git a/src/xspice/icm/tlines/cpmlin/ifspec.ifs b/src/xspice/icm/tlines/cpmlin/ifspec.ifs index 04a58eb67..c8d37ea8b 100644 --- a/src/xspice/icm/tlines/cpmlin/ifspec.ifs +++ b/src/xspice/icm/tlines/cpmlin/ifspec.ifs @@ -1,9 +1,18 @@ /* =========================================================================== -FILE ifspec.ifs + FILE ifspec.ifs + Copyright 2025 Vadim Kuznetsov -(c) vadim Kuznetsov 2025 + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -=========================================================================== */ + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ /* Ports connection 4 --||||||-- 3 diff --git a/src/xspice/icm/tlines/mlin/cfunc.mod b/src/xspice/icm/tlines/mlin/cfunc.mod index 7aea193ab..d21bb7b5b 100644 --- a/src/xspice/icm/tlines/mlin/cfunc.mod +++ b/src/xspice/icm/tlines/mlin/cfunc.mod @@ -1,7 +1,16 @@ /* =========================================================================== - FILE cfunc.mod + FILE cfunc.mod + Copyright 2025 Vadim Kuznetsov - (c) Vadim Kuznetsov 2025 + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ diff --git a/src/xspice/icm/tlines/mlin/ifspec.ifs b/src/xspice/icm/tlines/mlin/ifspec.ifs index 1e3404e69..3136f51e3 100644 --- a/src/xspice/icm/tlines/mlin/ifspec.ifs +++ b/src/xspice/icm/tlines/mlin/ifspec.ifs @@ -1,9 +1,18 @@ /* =========================================================================== -FILE ifspec.ifs + FILE ifspec.ifs + Copyright 2025 Vadim Kuznetsov -(c) vadim Kuznetsov 2025 + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -=========================================================================== */ + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ NAME_TABLE: diff --git a/src/xspice/icm/tlines/tline/cfunc.mod b/src/xspice/icm/tlines/tline/cfunc.mod index 61ec1f904..58f748b3b 100644 --- a/src/xspice/icm/tlines/tline/cfunc.mod +++ b/src/xspice/icm/tlines/tline/cfunc.mod @@ -1,7 +1,16 @@ /* =========================================================================== - FILE cfunc.mod + FILE cfunc.mod + Copyright 2025 Vadim Kuznetsov - (c) Vadim Kuznetsov 2025 + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ diff --git a/src/xspice/icm/tlines/tline/ifspec.ifs b/src/xspice/icm/tlines/tline/ifspec.ifs index b3caa7491..cfe95aead 100644 --- a/src/xspice/icm/tlines/tline/ifspec.ifs +++ b/src/xspice/icm/tlines/tline/ifspec.ifs @@ -1,9 +1,18 @@ /* =========================================================================== -FILE ifspec.ifs + FILE ifspec.ifs + Copyright 2025 Vadim Kuznetsov -(c) vadim Kuznetsov 2025 + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -=========================================================================== */ + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ NAME_TABLE: diff --git a/src/xspice/tlines/msline_common.c b/src/xspice/tlines/msline_common.c index 0cac78357..bc52a9367 100644 --- a/src/xspice/tlines/msline_common.c +++ b/src/xspice/tlines/msline_common.c @@ -1,6 +1,26 @@ -/* msline_common.c - * common definitions for microstrip devices - * (c) Vadim Kuznetsov 2025 +/* + * msline_common.c - common definitions for microstrip devices + * + * Copyright (C) 2025 Vadim Kuznetsov + * Based on works by Stefan Jahn, Qucsator project + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * $Id$ + * */ #include diff --git a/src/xspice/tlines/msline_common.h b/src/xspice/tlines/msline_common.h index a4c72c3a4..55e8966ea 100644 --- a/src/xspice/tlines/msline_common.h +++ b/src/xspice/tlines/msline_common.h @@ -1,6 +1,26 @@ -/* msline_common.h - * common definitions for microstrip devices - * (c) Vadim Kuznetsov 2025 +/* + * msline_common.h - common definitions for microstrip devices + * + * Copyright (C) 2025 Vadim Kuznetsov + * Based on works by Stefan Jahn, Qucsator project + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * $Id$ + * */ diff --git a/src/xspice/tlines/tline_common.c b/src/xspice/tlines/tline_common.c index 53bd4293f..08e8bb77d 100644 --- a/src/xspice/tlines/tline_common.c +++ b/src/xspice/tlines/tline_common.c @@ -1,6 +1,21 @@ /* tline_common.c * common definitions for all transmission lines - * (c) Vadim Kuznetsov 2025 + */ + +/* =========================================================================== + FILE tline_common.c + Copyright 2025 Vadim Kuznetsov + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ #include diff --git a/src/xspice/tlines/tline_common.h b/src/xspice/tlines/tline_common.h index f531e54c3..4932ce581 100644 --- a/src/xspice/tlines/tline_common.h +++ b/src/xspice/tlines/tline_common.h @@ -1,6 +1,21 @@ /* tline_common.h * common definitions for all transmission lines - * (c) Vadim Kuznetsov 2025 + */ + +/* =========================================================================== + FILE tline_common.h + Copyright 2025 Vadim Kuznetsov + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ From f90f5172acfe06b81175b789d3c812ee563344dd Mon Sep 17 00:00:00 2001 From: Vadim Kuznetsov Date: Wed, 11 Jun 2025 20:58:43 +0300 Subject: [PATCH 34/38] Implement rollback; fix memory management --- src/xspice/icm/tlines/cpline/cfunc.mod | 29 +++++++-- src/xspice/icm/tlines/cpline/ifspec.ifs | 6 ++ src/xspice/icm/tlines/cpmlin/cfunc.mod | 44 +++++++++++-- src/xspice/icm/tlines/cpmlin/ifspec.ifs | 16 +++++ src/xspice/icm/tlines/mlin/cfunc.mod | 32 ++++++++-- src/xspice/icm/tlines/mlin/ifspec.ifs | 6 +- src/xspice/icm/tlines/tline/cfunc.mod | 32 ++++++++-- src/xspice/icm/tlines/tline/ifspec.ifs | 4 ++ src/xspice/tlines/tline_common.c | 84 +++++++++++++++++++++++++ src/xspice/tlines/tline_common.h | 7 +++ 10 files changed, 243 insertions(+), 17 deletions(-) diff --git a/src/xspice/icm/tlines/cpline/cfunc.mod b/src/xspice/icm/tlines/cpline/cfunc.mod index 83f2f3493..7bde30526 100644 --- a/src/xspice/icm/tlines/cpline/cfunc.mod +++ b/src/xspice/icm/tlines/cpline/cfunc.mod @@ -30,8 +30,9 @@ static void copy_complex(double complex s, Complex_t *d) d->imag = cimag(s); } -cpline_state_t *sim_points = NULL; +//cpline_state_t *sim_points = NULL; +static void cm_cpline_callback(ARGS, Mif_Callback_Reason_t reason); void cm_cpline (ARGS) { @@ -49,7 +50,8 @@ void cm_cpline (ARGS) ao = pow(10, 0.05*ao); if(INIT) { - + CALLBACK = cm_cpline_callback; + STATIC_VAR(sim_points_data) = NULL; } /* Compute the output */ @@ -121,9 +123,19 @@ void cm_cpline (ARGS) Ip[2] = INPUT(p3); Ip[3] = INPUT(p4); double delay = l/(C0); - append_cpline_state(&sim_points, t, Vp, Ip, 1.2*delay); + + void **sim_points = &(STATIC_VAR(sim_points_data)); + + cpline_state_t *last = get_cpline_last_state(*(cpline_state_t **)sim_points); + double last_time = 0; + if (last != NULL) last_time = last->time; + + if (TIME < last_time) { + delete_cpline_last_state((cpline_state_t **)sim_points); + } + append_cpline_state((cpline_state_t **)sim_points, t, Vp, Ip, 1.2*delay); if (t > delay) { - cpline_state_t *pp = find_cpline_state(sim_points, t - delay); + cpline_state_t *pp = find_cpline_state(*(cpline_state_t **)sim_points, t - delay); if (pp != NULL) { double J1e = 0.5*(Ip[3] + Ip[0]); @@ -165,3 +177,12 @@ void cm_cpline (ARGS) } } +static void cm_cpline_callback(ARGS, Mif_Callback_Reason_t reason) +{ + switch (reason) { + case MIF_CB_DESTROY: + delete_cpline_states((cpline_state_t **)&(STATIC_VAR(sim_points_data))); + break; + default: break; + } +} diff --git a/src/xspice/icm/tlines/cpline/ifspec.ifs b/src/xspice/icm/tlines/cpline/ifspec.ifs index 136ec0982..03bf014bf 100644 --- a/src/xspice/icm/tlines/cpline/ifspec.ifs +++ b/src/xspice/icm/tlines/cpline/ifspec.ifs @@ -183,3 +183,9 @@ Vector_Bounds: - Null_Allowed: yes +STATIC_VAR_TABLE: + +Static_Var_Name: sim_points_data +Description: "local static data" +Data_Type: pointer + diff --git a/src/xspice/icm/tlines/cpmlin/cfunc.mod b/src/xspice/icm/tlines/cpmlin/cfunc.mod index 6bfde502a..6d6b0939c 100644 --- a/src/xspice/icm/tlines/cpmlin/cfunc.mod +++ b/src/xspice/icm/tlines/cpmlin/cfunc.mod @@ -33,7 +33,8 @@ static void copy_complex(double complex s, Complex_t *d) } -static cpline_state_t *state = NULL; +//static cpline_state_t *state = NULL; +static void cm_cpmline_callback(ARGS, Mif_Callback_Reason_t reason); static void analyseQuasiStatic (double W, double h, double s, double t, double er, @@ -377,6 +378,7 @@ void cm_cpmline (ARGS) double s = PARAM(s); int SModel = PARAM(model); int DModel = PARAM(disp); + int TModel = PARAM(tranmodel); /* how to get properties of the substrate, e.g. Er, H */ double er = PARAM(er); @@ -386,6 +388,10 @@ void cm_cpmline (ARGS) double rho = PARAM(rho); double D = PARAM(d); + if(INIT) { + CALLBACK = cm_cpmline_callback; + STATIC_VAR(sim_points_data) = NULL; + } /* Compute the output */ @@ -459,9 +465,19 @@ void cm_cpmline (ARGS) Ip[2] = INPUT(p3); Ip[3] = INPUT(p4); double delay = l/(C0); - append_cpline_state(&state, t, Vp, Ip, 1.2*delay); - if (t > delay) { - cpline_state_t *pp = find_cpline_state(state, t - delay); + void **sim_points = &(STATIC_VAR(sim_points_data)); + if (TModel == TRAN_FULL) { + cpline_state_t *last = get_cpline_last_state(*(cpline_state_t **)sim_points); + double last_time = 0; + if (last != NULL) last_time = last->time; + + if (TIME < last_time) { + delete_cpline_last_state((cpline_state_t **)sim_points); + } + append_cpline_state((cpline_state_t **)sim_points, t, Vp, Ip, 1.2*delay); + } + if (t > delay && TModel == TRAN_FULL) { + cpline_state_t *pp = find_cpline_state(*(cpline_state_t **)sim_points, t - delay); if (pp != NULL) { double J1e = 0.5*(Ip[3] + Ip[0]); @@ -498,8 +514,28 @@ void cm_cpmline (ARGS) } cm_analog_auto_partial(); } else { + double z = sqrt(ze*zo); + double V2out = Vp[0] + z*Ip[0]; + double V1out = Vp[1] + z*Ip[1]; + OUTPUT(p1) = V1out + Ip[0]*z; + OUTPUT(p2) = V2out + Ip[1]*z; + + double V3out = Vp[3] + z*Ip[3]; + double V4out = Vp[2] + z*Ip[2]; + OUTPUT(p3) = V3out + Ip[2]*z; + OUTPUT(p4) = V4out + Ip[3]*z; + cm_analog_auto_partial(); } } } +static void cm_cpmline_callback(ARGS, Mif_Callback_Reason_t reason) +{ + switch (reason) { + case MIF_CB_DESTROY: + delete_cpline_states((cpline_state_t **)&(STATIC_VAR(sim_points_data))); + break; + default: break; + } +} diff --git a/src/xspice/icm/tlines/cpmlin/ifspec.ifs b/src/xspice/icm/tlines/cpmlin/ifspec.ifs index c8d37ea8b..d4a6367c0 100644 --- a/src/xspice/icm/tlines/cpmlin/ifspec.ifs +++ b/src/xspice/icm/tlines/cpmlin/ifspec.ifs @@ -222,4 +222,20 @@ Vector: no Vector_Bounds: - Null_Allowed: yes +PARAMETER_TABLE: +Parameter_Name: tranmodel +Description: "TRAN model DC/FULL" +Data_Type: int +Default_Value: 0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +STATIC_VAR_TABLE: + +Static_Var_Name: sim_points_data +Description: "local static data" +Data_Type: pointer diff --git a/src/xspice/icm/tlines/mlin/cfunc.mod b/src/xspice/icm/tlines/mlin/cfunc.mod index d21bb7b5b..caa53d2fe 100644 --- a/src/xspice/icm/tlines/mlin/cfunc.mod +++ b/src/xspice/icm/tlines/mlin/cfunc.mod @@ -22,10 +22,12 @@ #include "msline_common.h" -static tline_state_t *sim_points = NULL; +//static tline_state_t *sim_points = NULL; static double zl, alpha, beta, ereff; +static void cm_mline_callback(ARGS, Mif_Callback_Reason_t reason); + static void calcPropagation (double W, int SModel, int DModel, double er, double h, double t, double tand, double rho, double D, double frequency) { @@ -56,6 +58,7 @@ static void calcPropagation (double W, int SModel, int DModel, void cm_mlin (ARGS) { Complex_t z11, z21; + void **sim_points; /* how to get properties of this component, e.g. L, W */ @@ -77,7 +80,8 @@ void cm_mlin (ARGS) /* Initialize/access instance specific storage for capacitor voltage */ if(INIT) { - + CALLBACK = cm_mline_callback; + STATIC_VAR(sim_points_data) = NULL; } /* Compute the output */ @@ -111,6 +115,7 @@ void cm_mlin (ARGS) } else if(ANALYSIS == TRANSIENT) { calcPropagation(W,SModel,DModel,er,h,t,tand,rho,D,0); + sim_points = &(STATIC_VAR(sim_points_data)); double t = TIME; double V1 = INPUT(V1sens); double V2 = INPUT(V2sens); @@ -118,10 +123,19 @@ void cm_mlin (ARGS) double I2 = INPUT(port2); double delay = l/(C0) * sqrt(ereff); if (TModel == TRAN_FULL) { - append_state(&sim_points, t, V1, V2, I1, I2, 1.2*delay); + + tline_state_t *last = get_tline_last_state(*(tline_state_t **)sim_points); + double last_time = 0; + if (last != NULL) last_time = last->time; + + if (TIME < last_time) { + //fprintf(stderr,"Rollbacki time=%g\n",TIME); + delete_tline_last_state((tline_state_t **)sim_points); + } + append_state((tline_state_t **)sim_points, t, V1, V2, I1, I2, 1.2*delay); } if (t > delay && TModel == TRAN_FULL) { - tline_state_t *pp = get_state(sim_points, t - delay); + tline_state_t *pp = get_state(*(tline_state_t **)sim_points, t - delay); if (pp != NULL) { double V2out = pp->V1 + zl*(pp->I1); double V1out = pp->V2 + zl*(pp->I2); @@ -140,3 +154,13 @@ void cm_mlin (ARGS) } } +static void cm_mline_callback(ARGS, Mif_Callback_Reason_t reason) +{ + switch (reason) { + case MIF_CB_DESTROY: + delete_tline_states((tline_state_t **)&(STATIC_VAR(sim_points_data))); + break; + default: break; + } +} + diff --git a/src/xspice/icm/tlines/mlin/ifspec.ifs b/src/xspice/icm/tlines/mlin/ifspec.ifs index 3136f51e3..a0e268116 100644 --- a/src/xspice/icm/tlines/mlin/ifspec.ifs +++ b/src/xspice/icm/tlines/mlin/ifspec.ifs @@ -169,7 +169,7 @@ Null_Allowed: yes PARAMETER_TABLE: Parameter_Name: tranmodel -Description: "RMS Substrate roughness" +Description: "TRAN model DC/FULL" Data_Type: int Default_Value: 0 Limits: - @@ -178,5 +178,9 @@ Vector_Bounds: - Null_Allowed: yes +STATIC_VAR_TABLE: +Static_Var_Name: sim_points_data +Description: "local static data" +Data_Type: pointer diff --git a/src/xspice/icm/tlines/tline/cfunc.mod b/src/xspice/icm/tlines/tline/cfunc.mod index 58f748b3b..207a0ee58 100644 --- a/src/xspice/icm/tlines/tline/cfunc.mod +++ b/src/xspice/icm/tlines/tline/cfunc.mod @@ -21,12 +21,14 @@ #include "msline_common.h" #include "tline_common.h" -static tline_state_t *sim_points = NULL; +//static tline_state_t *sim_points = NULL; +static void cm_tline_callback(ARGS, Mif_Callback_Reason_t reason); void cm_tline (ARGS) { Complex_t z11, z21; + void **sim_points; /* how to get properties of this component, e.g. L, W */ @@ -39,7 +41,8 @@ void cm_tline (ARGS) /* Initialize/access instance specific storage for capacitor voltage */ if(INIT) { - + CALLBACK = cm_tline_callback; + STATIC_VAR(sim_points_data) = NULL; } /* Compute the output */ @@ -72,15 +75,26 @@ void cm_tline (ARGS) AC_GAIN(in,out) = z21; AC_GAIN(out,in) = z21; } else if(ANALYSIS == TRANSIENT) { + sim_points = &(STATIC_VAR(sim_points_data)); double t = TIME; double V1 = INPUT(V1sens); double V2 = INPUT(V2sens); double I1 = INPUT(in); double I2 = INPUT(out); double delay = l/(C0); - append_state(&sim_points, t, V1, V2, I1, I2, 1.2*delay); + + tline_state_t *last = get_tline_last_state(*(tline_state_t **)sim_points); + double last_time = 0; + if (last != NULL) last_time = last->time; + + if (TIME < last_time) { + //fprintf(stderr,"Rollback time=%g\n",TIME); + delete_tline_last_state((tline_state_t **)sim_points); + } + + append_state((tline_state_t **)sim_points, t, V1, V2, I1, I2, 1.2*delay); if (t > delay) { - tline_state_t *pp = get_state(sim_points, t - delay); + tline_state_t *pp = get_state(*(tline_state_t **)sim_points, t - delay); if (pp != NULL) { double V2out = pp->V1 + z*(pp->I1); double V1out = pp->V2 + z*(pp->I2); @@ -98,3 +112,13 @@ void cm_tline (ARGS) } } + +static void cm_tline_callback(ARGS, Mif_Callback_Reason_t reason) +{ + switch (reason) { + case MIF_CB_DESTROY: + delete_tline_states((tline_state_t **)&(STATIC_VAR(sim_points_data))); + break; + default: break; + } +} diff --git a/src/xspice/icm/tlines/tline/ifspec.ifs b/src/xspice/icm/tlines/tline/ifspec.ifs index cfe95aead..5e45685b8 100644 --- a/src/xspice/icm/tlines/tline/ifspec.ifs +++ b/src/xspice/icm/tlines/tline/ifspec.ifs @@ -93,4 +93,8 @@ Vector: no Vector_Bounds: - Null_Allowed: yes +STATIC_VAR_TABLE: +Static_Var_Name: sim_points_data +Description: "local static data" +Data_Type: pointer diff --git a/src/xspice/tlines/tline_common.c b/src/xspice/tlines/tline_common.c index 08e8bb77d..90f652688 100644 --- a/src/xspice/tlines/tline_common.c +++ b/src/xspice/tlines/tline_common.c @@ -61,6 +61,47 @@ tline_state_t *get_state(tline_state_t *first, double time) return pp; } +tline_state_t *get_tline_last_state(tline_state_t *first) +{ + tline_state_t *pp = first; + if (first == NULL) return NULL; + while (pp->next != NULL) { + pp = pp->next; + } + return pp; +} + + +void delete_tline_last_state(tline_state_t **first) +{ + tline_state_t *pn = *first; + if (*first == NULL) return; + + if ((*first)->next == NULL) { + free (*first); + *first = NULL; + return; + } + + while (pn->next->next != NULL) { + pn = pn->next; + } + free(pn->next); + pn->next = NULL; +} + +void delete_tline_states(tline_state_t **first) +{ + if (*first == NULL) return; + tline_state_t *pn; + tline_state_t *pc = *first; + while (pc != NULL) { + pn = pc->next; + free (pc); + pc = pn; + } + *first = NULL; +} void append_cpline_state(cpline_state_t **first, double time, double *Vp, double *Ip, double tmax) { @@ -99,3 +140,46 @@ cpline_state_t *find_cpline_state(cpline_state_t *first, double time) return pp; } +cpline_state_t *get_cpline_last_state(cpline_state_t *first) +{ + cpline_state_t *pp = first; + if (first == NULL) return NULL; + while (pp->next != NULL) { + pp = pp->next; + } + return pp; +} + + +void delete_cpline_last_state(cpline_state_t **first) +{ + cpline_state_t *pn = *first; + if (*first == NULL) return; + + if ((*first)->next == NULL) { + free (*first); + *first = NULL; + return; + } + + while (pn->next->next != NULL) { + pn = pn->next; + } + free(pn->next); + pn->next = NULL; +} + +void delete_cpline_states(cpline_state_t **first) +{ + if (*first == NULL) return; + cpline_state_t *pn; + cpline_state_t *pc = *first; + while (pc != NULL) { + pn = pc->next; + free (pc); + pc = pn; + } + *first = NULL; +} + + diff --git a/src/xspice/tlines/tline_common.h b/src/xspice/tlines/tline_common.h index 4932ce581..8448d47bb 100644 --- a/src/xspice/tlines/tline_common.h +++ b/src/xspice/tlines/tline_common.h @@ -59,6 +59,10 @@ void append_state(tline_state_t **first, double time, double V1, double V2, tline_state_t *get_state(tline_state_t *first, double time); +void delete_tline_states(tline_state_t **first); +void delete_tline_last_state(tline_state_t **first); +tline_state_t *get_tline_last_state(tline_state_t *first); + #define PORT_NUM 4 typedef struct cpline_state { @@ -74,5 +78,8 @@ void append_cpline_state(cpline_state_t **first, double time, double *Vp, double cpline_state_t *find_cpline_state(cpline_state_t *first, double time); +void delete_cpline_states(cpline_state_t **first); +void delete_cpline_last_state(cpline_state_t **first); +cpline_state_t *get_cpline_last_state(cpline_state_t *first); #endif From 1cac0ff6d6d4fcec85edaf66f0bc5dc284c07de7 Mon Sep 17 00:00:00 2001 From: Vadim Kuznetsov Date: Mon, 23 Jun 2025 19:51:34 +0300 Subject: [PATCH 35/38] Added MSOPEN model --- src/xspice/icm/tlines/modpath.lst | 1 + src/xspice/icm/tlines/msopen/cfunc.mod | 120 ++++++++++++++++++++ src/xspice/icm/tlines/msopen/ifspec.ifs | 140 ++++++++++++++++++++++++ 3 files changed, 261 insertions(+) create mode 100644 src/xspice/icm/tlines/msopen/cfunc.mod create mode 100644 src/xspice/icm/tlines/msopen/ifspec.ifs diff --git a/src/xspice/icm/tlines/modpath.lst b/src/xspice/icm/tlines/modpath.lst index a7ce53ef9..c5b11351f 100644 --- a/src/xspice/icm/tlines/modpath.lst +++ b/src/xspice/icm/tlines/modpath.lst @@ -2,3 +2,4 @@ mlin tline cpline cpmlin +msopen diff --git a/src/xspice/icm/tlines/msopen/cfunc.mod b/src/xspice/icm/tlines/msopen/cfunc.mod new file mode 100644 index 000000000..c07a36cb0 --- /dev/null +++ b/src/xspice/icm/tlines/msopen/cfunc.mod @@ -0,0 +1,120 @@ +/* =========================================================================== + FILE cfunc.mod + Copyright 2025 Vadim Kuznetsov + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + + +#include +#include +#include + + +#include "msline_common.h" +#include "tline_common.h" + + +#define MSOPEN_KIRSCHNING 0 +#define MSOPEN_HAMMERSTAD 1 +#define MSOPEN_ALEXOPOULOS 2 + + +// Returns the microstrip open end capacitance. +static double calcCend (double frequency, double W, + double h, double t, double er, + int SModel, int DModel, + int Model) { + + double ZlEff, ErEff, WEff, ZlEffFreq, ErEffFreq; + mslineAnalyseQuasiStatic (W, h, t, er, SModel, &ZlEff, &ErEff, &WEff); + mslineAnalyseDispersion (WEff, h, er, ZlEff, ErEff, frequency, DModel, + &ZlEffFreq, &ErEffFreq); + + W /= h; + double dl = 0; + /* Kirschning, Jansen and Koster */ + if (Model == MSOPEN_KIRSCHNING) { + double Q6 = pow (ErEffFreq, 0.81); + double Q7 = pow (W, 0.8544); + double Q1 = 0.434907 * + (Q6 + 0.26) / (Q6 - 0.189) * (Q7 + 0.236) / (Q7 + 0.87); + double Q2 = pow (W, 0.371) / (2.358 * er + 1.0) + 1.0; + double Q3 = atan (0.084 * pow (W, 1.9413 / Q2)) * + 0.5274 / pow (ErEffFreq, 0.9236) + 1.0; + double Q4 = 0.0377 * (6.0 - 5.0 * exp (0.036 * (1.0 - er))) * + atan (0.067 * pow (W, 1.456)) + 1.0; + double Q5 = 1.0 - 0.218 * exp (-7.5 * W); + dl = Q1 * Q3 * Q5 / Q4; + } + /* Hammerstad */ + else if (Model == MSOPEN_HAMMERSTAD) { + dl = 0.102 * (W + 0.106) / (W + 0.264) * + (1.166 + (er + 1) / er * (0.9 + log (W + 2.475))); + } + return dl * h * sqrt (ErEffFreq) / C0 / ZlEffFreq; +} + + +void cm_msopen (ARGS) +{ + Complex_t ac_gain; + + /* how to get properties of this component, e.g. L, W */ + double W = PARAM(w); + int SModel = PARAM(model); + int DModel = PARAM(disp); + int Model = PARAM(msopen_model); + + /* how to get properties of the substrate, e.g. Er, H */ + double er = PARAM(er); + double h = PARAM(h); + double t = PARAM(t); + + + /* Compute the output */ + if(ANALYSIS == AC) { + if (Model == MSOPEN_ALEXOPOULOS) { + double ZlEff, ErEff, WEff, ZlEffFreq, ErEffFreq; + mslineAnalyseQuasiStatic (W, h, t, er, SModel, &ZlEff, &ErEff, &WEff); + mslineAnalyseDispersion (WEff, h, er, ZlEff, ErEff, RAD_FREQ/(2*M_PI), DModel, + &ZlEffFreq, &ErEffFreq); + + if (fabs (er - 9.9) > 0.2) { + fprintf (stderr, "WARNING: Model for microstrip open end defined " + "for er = 9.9 (er = %g)\n", er); + } + + double c1, c2, l2, r2; + c1 = (1.125 * tanh (1.358 * W / h) - 0.315) * + h / 2.54e-5 / 25 / ZlEffFreq * 1e-12; + c2 = (6.832 * tanh (0.0109 * W / h) + 0.919) * + h / 2.54e-5 / 25 / ZlEffFreq * 1e-12; + l2 = (0.008285 * tanh (0.5665 * W / h) + 0.0103) * + h / 2.54e-5 / 25 * ZlEffFreq * 1e-9; + r2 = (1.024 * tanh (2.025 * W / h)) * ZlEffFreq; + double complex d1 = 0 + I*c1 * RAD_FREQ; + double complex d2 = r2 + I*(l2 * RAD_FREQ - 1.0 / c2 / RAD_FREQ); + double complex y = d1 + 1.0/d2; + + ac_gain.real = creal(y); + ac_gain.imag = cimag(y); + AC_GAIN(p1, p1) = ac_gain; + } else { + double Ce = calcCend(RAD_FREQ/(2*M_PI), W, h, t, er, SModel, DModel, Model); + ac_gain.real = 0.0; + ac_gain.imag = RAD_FREQ * Ce; + AC_GAIN(p1, p1) = ac_gain; + } + } +} + diff --git a/src/xspice/icm/tlines/msopen/ifspec.ifs b/src/xspice/icm/tlines/msopen/ifspec.ifs new file mode 100644 index 000000000..9f1773d4b --- /dev/null +++ b/src/xspice/icm/tlines/msopen/ifspec.ifs @@ -0,0 +1,140 @@ +/* =========================================================================== + FILE ifspec.ifs + Copyright 2025 Vadim Kuznetsov + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +NAME_TABLE: + +Spice_Model_Name: msopen +C_Function_Name: cm_msopen +Description: "Microstrip open end" + + +PORT_TABLE: + +Port_Name: p1 +Description: "terminals" +Direction: inout +Default_Type: gd +Allowed_Types: [gd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +PARAMETER_TABLE: +Parameter_Name: w +Description: "width" +Data_Type: real +Default_Value: 1e-3 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +PARAMETER_TABLE: +Parameter_Name: model +Description: "Model type" +Data_Type: int +Default_Value: 0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +PARAMETER_TABLE: +Parameter_Name: disp +Description: "Dispersion type" +Data_Type: int +Default_Value: 0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: msopen_model +Description: "MSOpen model" +Data_Type: int +Default_Value: 0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +PARAMETER_TABLE: +Parameter_Name: er +Description: "Substrate dielectric permittivity" +Data_Type: real +Default_Value: 9.8 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: h +Description: "Substrate thickness" +Data_Type: real +Default_Value: 1e-3 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: t +Description: "Metal strip thickness" +Data_Type: real +Default_Value: 35e-6 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: tand +Description: "Substrate dielectric loss" +Data_Type: real +Default_Value: 2e-4 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +PARAMETER_TABLE: +Parameter_Name: rho +Description: "Metal resistance" +Data_Type: real +Default_Value: 0.022e-6 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: +Parameter_Name: d +Description: "RMS Substrate roughness" +Data_Type: real +Default_Value: 0.15e-6 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + + From f954772f644673f38696580bd24bad9248e961a8 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 13 Jul 2025 11:55:30 +0200 Subject: [PATCH 36/38] retain type=0, type=1, type=+1, or type=-1 in a .model card, even if compatmode PS or LT are set. --- src/frontend/inpcom.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 615baf042..e31118e76 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -9057,7 +9057,8 @@ static void rem_mfg_from_models(struct card *deck) } } start = search_plain_identifier(curr_line, "type"); - if (start && start[4] == '=') { + /* still retain type=0, type=1, type=+1, or type=-1 */ + if (start && start[4] == '=' && !isdigit_c(start[5]) && !((start[5] == '-' || start[5] == '+') && isdigit_c(start[6]))) { end = nexttok(start); if (*end == '\0') *start = '\0'; From e3e4906b120bab921e39b672c5e949fdded26fa5 Mon Sep 17 00:00:00 2001 From: Vadim Kuznetsov Date: Sun, 13 Jul 2025 17:55:35 +0300 Subject: [PATCH 37/38] Fix licence header in msline_common --- src/xspice/tlines/msline_common.c | 38 ++++++++++++------------------- src/xspice/tlines/msline_common.h | 37 ++++++++++++------------------ 2 files changed, 29 insertions(+), 46 deletions(-) diff --git a/src/xspice/tlines/msline_common.c b/src/xspice/tlines/msline_common.c index bc52a9367..39f6ad473 100644 --- a/src/xspice/tlines/msline_common.c +++ b/src/xspice/tlines/msline_common.c @@ -1,28 +1,20 @@ -/* - * msline_common.c - common definitions for microstrip devices - * - * Copyright (C) 2025 Vadim Kuznetsov - * Based on works by Stefan Jahn, Qucsator project - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this package; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * $Id$ - * +/* =========================================================================== + FILE msline_common.c - common definitions for microstrip devices + Copyright 2025 Vadim Kuznetsov + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #include #include diff --git a/src/xspice/tlines/msline_common.h b/src/xspice/tlines/msline_common.h index 55e8966ea..a048a3d6b 100644 --- a/src/xspice/tlines/msline_common.h +++ b/src/xspice/tlines/msline_common.h @@ -1,26 +1,17 @@ -/* - * msline_common.h - common definitions for microstrip devices - * - * Copyright (C) 2025 Vadim Kuznetsov - * Based on works by Stefan Jahn, Qucsator project - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this package; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * $Id$ - * +/* =========================================================================== + FILE msline_common.h - common definitions for microstrip devices + Copyright 2025 Vadim Kuznetsov + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ From 1618f71f49640667f1c3437fb5127d1896b98187 Mon Sep 17 00:00:00 2001 From: dwarning Date: Tue, 15 Jul 2025 18:05:03 +0200 Subject: [PATCH 38/38] bsim4 update to version 4.8.3 --- src/spicelib/devices/bsim4/b4.c | 196 +- src/spicelib/devices/bsim4/b4acld.c | 360 ++- src/spicelib/devices/bsim4/b4ask.c | 212 +- src/spicelib/devices/bsim4/b4check.c | 756 ++--- src/spicelib/devices/bsim4/b4cvtest.c | 59 +- src/spicelib/devices/bsim4/b4geo.c | 224 +- src/spicelib/devices/bsim4/b4getic.c | 47 +- src/spicelib/devices/bsim4/b4ld.c | 3630 ++++++++++++------------- src/spicelib/devices/bsim4/b4mask.c | 648 ++--- src/spicelib/devices/bsim4/b4mdel.c | 20 +- src/spicelib/devices/bsim4/b4mpar.c | 392 +-- src/spicelib/devices/bsim4/b4noi.c | 844 +++--- src/spicelib/devices/bsim4/b4par.c | 50 +- src/spicelib/devices/bsim4/b4pzld.c | 563 ++-- src/spicelib/devices/bsim4/b4set.c | 787 +++--- src/spicelib/devices/bsim4/b4temp.c | 2274 ++++++++-------- src/spicelib/devices/bsim4/b4trunc.c | 33 +- src/spicelib/devices/bsim4/bsim4def.h | 432 +-- src/spicelib/devices/bsim4/bsim4ext.h | 22 +- src/spicelib/devices/bsim4/bsim4itf.h | 20 +- 20 files changed, 5774 insertions(+), 5795 deletions(-) diff --git a/src/spicelib/devices/bsim4/b4.c b/src/spicelib/devices/bsim4/b4.c index 586b68cae..d0fddd8b3 100644 --- a/src/spicelib/devices/bsim4/b4.c +++ b/src/spicelib/devices/bsim4/b4.c @@ -1,31 +1,28 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* Licensed under Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the license at http://opensource.org/licenses/ECL-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc */ + #include "ngspice/ngspice.h" #include "ngspice/devdefs.h" #include "bsim4def.h" @@ -57,11 +54,10 @@ IOP( "rbpb", BSIM4_RBPB, IF_REAL , "Body resistance"), 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"), +IOPR("delvt0", BSIM4_DELVTO, IF_REAL , "Zero bias threshold voltage variation"), 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"), @@ -69,6 +65,10 @@ IOP( "rbodymod", BSIM4_RBODYMOD, IF_INTEGER, "Distributed body R model selector" IOP( "rgatemod", BSIM4_RGATEMOD, IF_INTEGER, "Gate resistance model selector"), IOP( "geomod", BSIM4_GEOMOD, IF_INTEGER, "Geometry dependent parasitics model selector"), IOP( "rgeomod", BSIM4_RGEOMOD, IF_INTEGER, "S/D resistance and contact model selector"), + +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"), OP( "gmbs", BSIM4_GMBS, IF_REAL, "Gmb"), OP( "gm", BSIM4_GM, IF_REAL, "Gm"), @@ -138,7 +138,6 @@ IOP( "rbodymod", BSIM4_MOD_RBODYMOD, IF_INTEGER, "Distributed body R model selec IOP( "rgatemod", BSIM4_MOD_RGATEMOD, IF_INTEGER, "Gate R model selector"), IOP( "permod", BSIM4_MOD_PERMOD, IF_INTEGER, "Pd and Ps model selector"), IOP( "geomod", BSIM4_MOD_GEOMOD, IF_INTEGER, "Geometry dependent parasitics model selector"), -IOP( "rgeomod", BSIM4_MOD_RGEOMOD, IF_INTEGER, "S/D resistance and contact model selector"), IOP( "fnoimod", BSIM4_MOD_FNOIMOD, IF_INTEGER, "Flicker noise model selector"), IOP( "tnoimod", BSIM4_MOD_TNOIMOD, IF_INTEGER, "Thermal noise model selector"), IOP( "mtrlmod", BSIM4_MOD_MTRLMOD, IF_INTEGER, "parameter for non-silicon substrate or metal gate selector"), @@ -164,18 +163,19 @@ IOP( "toxref", BSIM4_MOD_TOXREF, IF_REAL, "Target tox value"), IOP( "dtox", BSIM4_MOD_DTOX, IF_REAL, "Defined as (toxe - toxp) "), IOP( "epsrox", BSIM4_MOD_EPSROX, IF_REAL, "Dielectric constant of the gate oxide relative to vacuum"), IOP( "cdsc", BSIM4_MOD_CDSC, IF_REAL, "Drain/Source and channel coupling capacitance"), -IOP( "cdscb", BSIM4_MOD_CDSCB, IF_REAL, "Body-bias dependence of cdsc"), -IOP( "cdscd", BSIM4_MOD_CDSCD, IF_REAL, "Drain-bias dependence of cdsc"), +IOP( "cdscb", BSIM4_MOD_CDSCB, IF_REAL, "Body-bias dependence of cdsc"), +IOP( "cdscd", BSIM4_MOD_CDSCD, IF_REAL, "Drain-bias dependence of cdsc"), IOP( "cit", BSIM4_MOD_CIT, IF_REAL, "Interface state capacitance"), IOP( "nfactor", BSIM4_MOD_NFACTOR, IF_REAL, "Subthreshold swing Coefficient"), IOP( "xj", BSIM4_MOD_XJ, IF_REAL, "Junction depth in meters"), IOP( "vsat", BSIM4_MOD_VSAT, IF_REAL, "Saturation velocity at tnom"), IOP( "at", BSIM4_MOD_AT, IF_REAL, "Temperature coefficient of vsat"), -IOP( "a0", BSIM4_MOD_A0, IF_REAL, "Non-uniform depletion width effect coefficient."), -IOP( "ags", BSIM4_MOD_AGS, IF_REAL, "Gate bias coefficient of Abulk."), +IOP( "a0", BSIM4_MOD_A0, IF_REAL, "Non-uniform depletion width effect coefficient."), +IOP( "ags", BSIM4_MOD_AGS, IF_REAL, "Gate bias coefficient of Abulk."), IOP( "a1", BSIM4_MOD_A1, IF_REAL, "Non-saturation effect coefficient"), IOP( "a2", BSIM4_MOD_A2, IF_REAL, "Non-saturation effect coefficient"), IOP( "keta", BSIM4_MOD_KETA, IF_REAL, "Body-bias coefficient of non-uniform depletion width effect."), +IOP( "ketac", BSIM4_MOD_KETAC, IF_REAL, "Body-bias coefficient of non-uniform depletion width effect in dynamic evaluation."), IOP( "phig", BSIM4_MOD_PHIG, IF_REAL, "Work function of gate"), IOP( "epsrgate", BSIM4_MOD_EPSRGATE, IF_REAL, "Dielectric constant of gate relative to vacuum"), IOP( "easub",BSIM4_MOD_EASUB, IF_REAL, "Electron affinity of substrate"), @@ -248,30 +248,30 @@ IOP( "cgbo", BSIM4_MOD_CGBO, IF_REAL, "Gate-bulk overlap capacitance per length" IOP( "xpart", BSIM4_MOD_XPART, IF_REAL, "Channel charge partitioning"), IOP( "delta", BSIM4_MOD_DELTA, IF_REAL, "Effective Vds parameter"), IOP( "rsh", BSIM4_MOD_RSH, IF_REAL, "Source-drain sheet resistance"), -IOP( "rdsw", BSIM4_MOD_RDSW, IF_REAL, "Source-drain resistance per width"), +IOP( "rdsw", BSIM4_MOD_RDSW, IF_REAL, "Source-drain resistance per width"), IOP( "rdswmin", BSIM4_MOD_RDSWMIN, IF_REAL, "Source-drain resistance per width at high Vg"), IOP( "rsw", BSIM4_MOD_RSW, IF_REAL, "Source resistance per width"), IOP( "rdw", BSIM4_MOD_RDW, IF_REAL, "Drain resistance per width"), IOP( "rdwmin", BSIM4_MOD_RDWMIN, IF_REAL, "Drain resistance per width at high Vg"), IOP( "rswmin", BSIM4_MOD_RSWMIN, IF_REAL, "Source resistance per width at high Vg"), -IOP( "prwg", BSIM4_MOD_PRWG, IF_REAL, "Gate-bias effect on parasitic resistance "), -IOP( "prwb", BSIM4_MOD_PRWB, IF_REAL, "Body-effect on parasitic resistance "), +IOP( "prwg", BSIM4_MOD_PRWG, IF_REAL, "Gate-bias effect on parasitic resistance "), +IOP( "prwb", BSIM4_MOD_PRWB, IF_REAL, "Body-effect on parasitic resistance "), -IOP( "prt", BSIM4_MOD_PRT, IF_REAL, "Temperature coefficient of parasitic resistance "), +IOP( "prt", BSIM4_MOD_PRT, IF_REAL, "Temperature coefficient of parasitic resistance "), IOP( "eta0", BSIM4_MOD_ETA0, IF_REAL, "Subthreshold region DIBL coefficient"), IOP( "etab", BSIM4_MOD_ETAB, IF_REAL, "Subthreshold region DIBL coefficient"), IOP( "pclm", BSIM4_MOD_PCLM, IF_REAL, "Channel length modulation Coefficient"), -IOP( "pdiblc1", BSIM4_MOD_PDIBL1, IF_REAL, "Drain-induced barrier lowering coefficient"), -IOP( "pdiblc2", BSIM4_MOD_PDIBL2, IF_REAL, "Drain-induced barrier lowering coefficient"), -IOP( "pdiblcb", BSIM4_MOD_PDIBLB, IF_REAL, "Body-effect on drain-induced barrier lowering"), +IOP( "pdiblc1", BSIM4_MOD_PDIBL1, IF_REAL, "Drain-induced barrier lowering coefficient"), +IOP( "pdiblc2", BSIM4_MOD_PDIBL2, IF_REAL, "Drain-induced barrier lowering coefficient"), +IOP( "pdiblcb", BSIM4_MOD_PDIBLB, IF_REAL, "Body-effect on drain-induced barrier lowering"), IOP( "fprout", BSIM4_MOD_FPROUT, IF_REAL, "Rout degradation coefficient for pocket devices"), IOP( "pdits", BSIM4_MOD_PDITS, IF_REAL, "Coefficient for drain-induced Vth shifts"), IOP( "pditsl", BSIM4_MOD_PDITSL, IF_REAL, "Length dependence of drain-induced Vth shifts"), IOP( "pditsd", BSIM4_MOD_PDITSD, IF_REAL, "Vds dependence of drain-induced Vth shifts"), -IOP( "pscbe1", BSIM4_MOD_PSCBE1, IF_REAL, "Substrate current body-effect coefficient"), -IOP( "pscbe2", BSIM4_MOD_PSCBE2, IF_REAL, "Substrate current body-effect coefficient"), -IOP( "pvag", BSIM4_MOD_PVAG, IF_REAL, "Gate dependence of output resistance parameter"), +IOP( "pscbe1", BSIM4_MOD_PSCBE1, IF_REAL, "Substrate current body-effect coefficient"), +IOP( "pscbe2", BSIM4_MOD_PSCBE2, IF_REAL, "Substrate current body-effect coefficient"), +IOP( "pvag", BSIM4_MOD_PVAG, IF_REAL, "Gate dependence of output resistance parameter"), IOP( "jss", BSIM4_MOD_JSS, IF_REAL, "Bottom source junction reverse saturation current density"), IOP( "jsws", BSIM4_MOD_JSWS, IF_REAL, "Isolation edge sidewall source junction reverse saturation current density"), @@ -390,14 +390,14 @@ IOP( "beta0", BSIM4_MOD_BETA0, IF_REAL, "substrate current model parameter"), IOP( "agidl", BSIM4_MOD_AGIDL, IF_REAL, "Pre-exponential constant for GIDL"), IOP( "bgidl", BSIM4_MOD_BGIDL, IF_REAL, "Exponential constant for GIDL"), IOP( "cgidl", BSIM4_MOD_CGIDL, IF_REAL, "Parameter for body-bias dependence of GIDL"), -IOP( "rgidl", BSIM4_MOD_RGIDL, IF_REAL, "GIDL vg parameter"), /* v4.7 New GIDL/GISL */ +IOP( "rgidl", BSIM4_MOD_RGIDL, IF_REAL, "GIDL vg parameter"), /* v4.7 New GIDL/GISL */ IOP( "kgidl", BSIM4_MOD_KGIDL, IF_REAL, "GIDL vb parameter"), /* v4.7 New GIDL/GISL */ IOP( "fgidl", BSIM4_MOD_FGIDL, IF_REAL, "GIDL vb parameter"), /* v4.7 New GIDL/GISL */ IOP( "egidl", BSIM4_MOD_EGIDL, IF_REAL, "Fitting parameter for Bandbending"), IOP( "agisl", BSIM4_MOD_AGISL, IF_REAL, "Pre-exponential constant for GISL"), IOP( "bgisl", BSIM4_MOD_BGISL, IF_REAL, "Exponential constant for GISL"), IOP( "cgisl", BSIM4_MOD_CGISL, IF_REAL, "Parameter for body-bias dependence of GISL"), -IOP( "rgisl", BSIM4_MOD_RGISL, IF_REAL, "GISL vg parameter"), /* v4.7 New GIDL/GISL */ +IOP( "rgisl", BSIM4_MOD_RGISL, IF_REAL, "GISL vg parameter"), /* v4.7 New GIDL/GISL */ IOP( "kgisl", BSIM4_MOD_KGISL, IF_REAL, "GISL vb parameter"), /* v4.7 New GIDL/GISL */ IOP( "fgisl", BSIM4_MOD_FGISL, IF_REAL, "GISL vb parameter"), /* v4.7 New GIDL/GISL */ IOP( "egisl", BSIM4_MOD_EGISL, IF_REAL, "Fitting parameter for Bandbending"), @@ -442,7 +442,7 @@ IOP( "jtssws", BSIM4_MOD_JTSSWS, IF_REAL, "Source STI sidewall trap-assisted sat IOP( "jtsswd", BSIM4_MOD_JTSSWD, IF_REAL, "Drain STI sidewall trap-assisted saturation current density"), IOP( "jtsswgs", BSIM4_MOD_JTSSWGS, IF_REAL, "Source gate-edge sidewall trap-assisted saturation current density"), IOP( "jtsswgd", BSIM4_MOD_JTSSWGD, IF_REAL, "Drain gate-edge sidewall trap-assisted saturation current density"), -IOP( "jtweff", BSIM4_MOD_JTWEFF, IF_REAL, "TAT current width dependence"), +IOP( "jtweff", BSIM4_MOD_JTWEFF, IF_REAL, "TAT current width dependance"), IOP( "njts", BSIM4_MOD_NJTS, IF_REAL, "Non-ideality factor for bottom junction"), IOP( "njtssw", BSIM4_MOD_NJTSSW, IF_REAL, "Non-ideality factor for STI sidewall junction"), IOP( "njtsswg", BSIM4_MOD_NJTSSWG, IF_REAL, "Non-ideality factor for gate-edge sidewall junction"), @@ -514,11 +514,12 @@ IOP( "lnfactor", BSIM4_MOD_LNFACTOR, IF_REAL, "Length dependence of nfactor"), IOP( "lxj", BSIM4_MOD_LXJ, IF_REAL, "Length dependence of xj"), IOP( "lvsat", BSIM4_MOD_LVSAT, IF_REAL, "Length dependence of vsat"), IOP( "lat", BSIM4_MOD_LAT, IF_REAL, "Length dependence of at"), -IOP( "la0", BSIM4_MOD_LA0, IF_REAL, "Length dependence of a0"), -IOP( "lags", BSIM4_MOD_LAGS, IF_REAL, "Length dependence of ags"), +IOP( "la0", BSIM4_MOD_LA0, IF_REAL, "Length dependence of a0"), +IOP( "lags", BSIM4_MOD_LAGS, IF_REAL, "Length dependence of ags"), IOP( "la1", BSIM4_MOD_LA1, IF_REAL, "Length dependence of a1"), IOP( "la2", BSIM4_MOD_LA2, IF_REAL, "Length dependence of a2"), IOP( "lketa", BSIM4_MOD_LKETA, IF_REAL, "Length dependence of keta"), +IOP( "lketac", BSIM4_MOD_LKETAC, IF_REAL, "Length dependence of ketac"), IOP( "lnsub", BSIM4_MOD_LNSUB, IF_REAL, "Length dependence of nsub"), IOP( "lndep", BSIM4_MOD_LNDEP, IF_REAL, "Length dependence of ndep"), IOP( "lnsd", BSIM4_MOD_LNSD, IF_REAL, "Length dependence of nsd"), @@ -553,8 +554,8 @@ IOP( "ldvt1w", BSIM4_MOD_LDVT1W, IF_REAL, "Length dependence of dvt1w"), IOP( "ldvt2w", BSIM4_MOD_LDVT2W, IF_REAL, "Length dependence of dvt2w"), IOP( "ldrout", BSIM4_MOD_LDROUT, IF_REAL, "Length dependence of drout"), IOP( "ldsub", BSIM4_MOD_LDSUB, IF_REAL, "Length dependence of dsub"), -IOP( "lvth0", BSIM4_MOD_LVTH0, IF_REAL,"Length dependence of vth0"), -IOPR("lvtho", BSIM4_MOD_LVTH0, IF_REAL,"Length dependence of vtho"), +IOP( "lvth0", BSIM4_MOD_LVTH0, IF_REAL,"Length dependence of vto"), +IOPR("lvtho", BSIM4_MOD_LVTH0, IF_REAL,"Length dependence of vto"), IOP( "lua", BSIM4_MOD_LUA, IF_REAL, "Length dependence of ua"), IOP( "lua1", BSIM4_MOD_LUA1, IF_REAL, "Length dependence of ua1"), IOP( "lub", BSIM4_MOD_LUB, IF_REAL, "Length dependence of ub"), @@ -572,26 +573,26 @@ IOP( "lvoff", BSIM4_MOD_LVOFF, IF_REAL, "Length dependence of voff"), IOP( "lminv", BSIM4_MOD_LMINV, IF_REAL, "Length dependence of minv"), IOP( "lminvcv", BSIM4_MOD_LMINVCV, IF_REAL, "Length dependence of minvcv"), IOP( "ldelta", BSIM4_MOD_LDELTA, IF_REAL, "Length dependence of delta"), -IOP( "lrdsw", BSIM4_MOD_LRDSW, IF_REAL, "Length dependence of rdsw "), +IOP( "lrdsw", BSIM4_MOD_LRDSW, IF_REAL, "Length dependence of rdsw "), IOP( "lrsw", BSIM4_MOD_LRSW, IF_REAL, "Length dependence of rsw"), IOP( "lrdw", BSIM4_MOD_LRDW, IF_REAL, "Length dependence of rdw"), -IOP( "lprwg", BSIM4_MOD_LPRWG, IF_REAL, "Length dependence of prwg "), -IOP( "lprwb", BSIM4_MOD_LPRWB, IF_REAL, "Length dependence of prwb "), +IOP( "lprwg", BSIM4_MOD_LPRWG, IF_REAL, "Length dependence of prwg "), +IOP( "lprwb", BSIM4_MOD_LPRWB, IF_REAL, "Length dependence of prwb "), -IOP( "lprt", BSIM4_MOD_LPRT, IF_REAL, "Length dependence of prt "), -IOP( "leta0", BSIM4_MOD_LETA0, IF_REAL, "Length dependence of eta0"), -IOP( "letab", BSIM4_MOD_LETAB, IF_REAL, "Length dependence of etab"), -IOP( "lpclm", BSIM4_MOD_LPCLM, IF_REAL, "Length dependence of pclm"), -IOP( "lpdiblc1", BSIM4_MOD_LPDIBL1, IF_REAL, "Length dependence of pdiblc1"), -IOP( "lpdiblc2", BSIM4_MOD_LPDIBL2, IF_REAL, "Length dependence of pdiblc2"), -IOP( "lpdiblcb", BSIM4_MOD_LPDIBLB, IF_REAL, "Length dependence of pdiblcb"), +IOP( "lprt", BSIM4_MOD_LPRT, IF_REAL, "Length dependence of prt "), +IOP( "leta0", BSIM4_MOD_LETA0, IF_REAL, "Length dependence of eta0"), +IOP( "letab", BSIM4_MOD_LETAB, IF_REAL, "Length dependence of etab"), +IOP( "lpclm", BSIM4_MOD_LPCLM, IF_REAL, "Length dependence of pclm"), +IOP( "lpdiblc1", BSIM4_MOD_LPDIBL1, IF_REAL, "Length dependence of pdiblc1"), +IOP( "lpdiblc2", BSIM4_MOD_LPDIBL2, IF_REAL, "Length dependence of pdiblc2"), +IOP( "lpdiblcb", BSIM4_MOD_LPDIBLB, IF_REAL, "Length dependence of pdiblcb"), IOP( "lfprout", BSIM4_MOD_LFPROUT, IF_REAL, "Length dependence of pdiblcb"), IOP( "lpdits", BSIM4_MOD_LPDITS, IF_REAL, "Length dependence of pdits"), IOP( "lpditsd", BSIM4_MOD_LPDITSD, IF_REAL, "Length dependence of pditsd"), -IOP( "lpscbe1", BSIM4_MOD_LPSCBE1, IF_REAL, "Length dependence of pscbe1"), -IOP( "lpscbe2", BSIM4_MOD_LPSCBE2, IF_REAL, "Length dependence of pscbe2"), -IOP( "lpvag", BSIM4_MOD_LPVAG, IF_REAL, "Length dependence of pvag"), +IOP( "lpscbe1", BSIM4_MOD_LPSCBE1, IF_REAL, "Length dependence of pscbe1"), +IOP( "lpscbe2", BSIM4_MOD_LPSCBE2, IF_REAL, "Length dependence of pscbe2"), +IOP( "lpvag", BSIM4_MOD_LPVAG, IF_REAL, "Length dependence of pvag"), IOP( "lwr", BSIM4_MOD_LWR, IF_REAL, "Length dependence of wr"), IOP( "ldwg", BSIM4_MOD_LDWG, IF_REAL, "Length dependence of dwg"), IOP( "ldwb", BSIM4_MOD_LDWB, IF_REAL, "Length dependence of dwb"), @@ -611,16 +612,16 @@ IOP( "lbeta0", BSIM4_MOD_LBETA0, IF_REAL, "Length dependence of beta0"), IOP( "lagidl", BSIM4_MOD_LAGIDL, IF_REAL, "Length dependence of agidl"), IOP( "lbgidl", BSIM4_MOD_LBGIDL, IF_REAL, "Length dependence of bgidl"), IOP( "lcgidl", BSIM4_MOD_LCGIDL, IF_REAL, "Length dependence of cgidl"), -IOP( "lrgidl", BSIM4_MOD_LRGIDL, IF_REAL, "Length dependence of rgidl"), /* v4.7 New GIDL/GISL */ -IOP( "lkgidl", BSIM4_MOD_LKGIDL, IF_REAL, "Length dependence of kgidl"), /* v4.7 New GIDL/GISL */ -IOP( "lfgidl", BSIM4_MOD_LFGIDL, IF_REAL, "Length dependence of fgidl"), /* v4.7 New GIDL/GISL */ +IOP( "lrgidl", BSIM4_MOD_LRGIDL, IF_REAL, "Length dependence of rgidl"), /* v4.7 New GIDL/GISL */ +IOP( "lkgidl", BSIM4_MOD_LKGIDL, IF_REAL, "Length dependence of kgidl"), /* v4.7 New GIDL/GISL */ +IOP( "lfgidl", BSIM4_MOD_LFGIDL, IF_REAL, "Length dependence of fgidl"), /* v4.7 New GIDL/GISL */ IOP( "legidl", BSIM4_MOD_LEGIDL, IF_REAL, "Length dependence of egidl"), IOP( "lagisl", BSIM4_MOD_LAGISL, IF_REAL, "Length dependence of agisl"), IOP( "lbgisl", BSIM4_MOD_LBGISL, IF_REAL, "Length dependence of bgisl"), IOP( "lcgisl", BSIM4_MOD_LCGISL, IF_REAL, "Length dependence of cgisl"), -IOP( "lrgisl", BSIM4_MOD_LRGISL, IF_REAL, "Length dependence of rgisl"), /* v4.7 New GIDL/GISL */ -IOP( "lkgisl", BSIM4_MOD_LKGISL, IF_REAL, "Length dependence of kgisl"), /* v4.7 New GIDL/GISL */ -IOP( "lfgisl", BSIM4_MOD_LFGISL, IF_REAL, "Length dependence of fgisl"), /* v4.7 New GIDL/GISL */ +IOP( "lrgisl", BSIM4_MOD_LRGISL, IF_REAL, "Length dependence of rgisl"), /* v4.7 New GIDL/GISL */ +IOP( "lkgisl", BSIM4_MOD_LKGISL, IF_REAL, "Length dependence of kgisl"), /* v4.7 New GIDL/GISL */ +IOP( "lfgisl", BSIM4_MOD_LFGISL, IF_REAL, "Length dependence of fgisl"), /* v4.7 New GIDL/GISL */ IOP( "legisl", BSIM4_MOD_LEGISL, IF_REAL, "Length dependence of egisl"), IOP( "laigc", BSIM4_MOD_LAIGC, IF_REAL, "Length dependence of aigc"), IOP( "lbigc", BSIM4_MOD_LBIGC, IF_REAL, "Length dependence of bigc"), @@ -669,18 +670,19 @@ IOP( "lteta0", BSIM4_MOD_LTETA0, IF_REAL, "Length dependence of teta0"), IOP( "ltvoffcv", BSIM4_MOD_LTVOFFCV, IF_REAL, "Length dependence of tvoffcv"), /* v4.7 Tanvir*/ IOP( "wcdsc", BSIM4_MOD_WCDSC, IF_REAL, "Width dependence of cdsc"), -IOP( "wcdscb", BSIM4_MOD_WCDSCB, IF_REAL, "Width dependence of cdscb"), -IOP( "wcdscd", BSIM4_MOD_WCDSCD, IF_REAL, "Width dependence of cdscd"), +IOP( "wcdscb", BSIM4_MOD_WCDSCB, IF_REAL, "Width dependence of cdscb"), +IOP( "wcdscd", BSIM4_MOD_WCDSCD, IF_REAL, "Width dependence of cdscd"), IOP( "wcit", BSIM4_MOD_WCIT, IF_REAL, "Width dependence of cit"), IOP( "wnfactor", BSIM4_MOD_WNFACTOR, IF_REAL, "Width dependence of nfactor"), IOP( "wxj", BSIM4_MOD_WXJ, IF_REAL, "Width dependence of xj"), IOP( "wvsat", BSIM4_MOD_WVSAT, IF_REAL, "Width dependence of vsat"), IOP( "wat", BSIM4_MOD_WAT, IF_REAL, "Width dependence of at"), -IOP( "wa0", BSIM4_MOD_WA0, IF_REAL, "Width dependence of a0"), -IOP( "wags", BSIM4_MOD_WAGS, IF_REAL, "Width dependence of ags"), +IOP( "wa0", BSIM4_MOD_WA0, IF_REAL, "Width dependence of a0"), +IOP( "wags", BSIM4_MOD_WAGS, IF_REAL, "Width dependence of ags"), IOP( "wa1", BSIM4_MOD_WA1, IF_REAL, "Width dependence of a1"), IOP( "wa2", BSIM4_MOD_WA2, IF_REAL, "Width dependence of a2"), IOP( "wketa", BSIM4_MOD_WKETA, IF_REAL, "Width dependence of keta"), +IOP( "wketac", BSIM4_MOD_WKETAC, IF_REAL, "Width dependence of ketac"), IOP( "wnsub", BSIM4_MOD_WNSUB, IF_REAL, "Width dependence of nsub"), IOP( "wndep", BSIM4_MOD_WNDEP, IF_REAL, "Width dependence of ndep"), IOP( "wnsd", BSIM4_MOD_WNSD, IF_REAL, "Width dependence of nsd"), @@ -715,8 +717,8 @@ IOP( "wdvt1w", BSIM4_MOD_WDVT1W, IF_REAL, "Width dependence of dvt1w"), IOP( "wdvt2w", BSIM4_MOD_WDVT2W, IF_REAL, "Width dependence of dvt2w"), IOP( "wdrout", BSIM4_MOD_WDROUT, IF_REAL, "Width dependence of drout"), IOP( "wdsub", BSIM4_MOD_WDSUB, IF_REAL, "Width dependence of dsub"), -IOP( "wvth0", BSIM4_MOD_WVTH0, IF_REAL,"Width dependence of vth0"), -IOPR("wvtho", BSIM4_MOD_WVTH0, IF_REAL,"Width dependence of vtho"), +IOP( "wvth0", BSIM4_MOD_WVTH0, IF_REAL,"Width dependence of vto"), +IOPR("wvtho", BSIM4_MOD_WVTH0, IF_REAL,"Width dependence of vto"), IOP( "wua", BSIM4_MOD_WUA, IF_REAL, "Width dependence of ua"), IOP( "wua1", BSIM4_MOD_WUA1, IF_REAL, "Width dependence of ua1"), IOP( "wub", BSIM4_MOD_WUB, IF_REAL, "Width dependence of ub"), @@ -742,18 +744,18 @@ IOP( "wprwg", BSIM4_MOD_WPRWG, IF_REAL, "Width dependence of prwg "), IOP( "wprwb", BSIM4_MOD_WPRWB, IF_REAL, "Width dependence of prwb "), IOP( "wprt", BSIM4_MOD_WPRT, IF_REAL, "Width dependence of prt"), -IOP( "weta0", BSIM4_MOD_WETA0, IF_REAL, "Width dependence of eta0"), -IOP( "wetab", BSIM4_MOD_WETAB, IF_REAL, "Width dependence of etab"), -IOP( "wpclm", BSIM4_MOD_WPCLM, IF_REAL, "Width dependence of pclm"), -IOP( "wpdiblc1", BSIM4_MOD_WPDIBL1, IF_REAL, "Width dependence of pdiblc1"), -IOP( "wpdiblc2", BSIM4_MOD_WPDIBL2, IF_REAL, "Width dependence of pdiblc2"), -IOP( "wpdiblcb", BSIM4_MOD_WPDIBLB, IF_REAL, "Width dependence of pdiblcb"), +IOP( "weta0", BSIM4_MOD_WETA0, IF_REAL, "Width dependence of eta0"), +IOP( "wetab", BSIM4_MOD_WETAB, IF_REAL, "Width dependence of etab"), +IOP( "wpclm", BSIM4_MOD_WPCLM, IF_REAL, "Width dependence of pclm"), +IOP( "wpdiblc1", BSIM4_MOD_WPDIBL1, IF_REAL, "Width dependence of pdiblc1"), +IOP( "wpdiblc2", BSIM4_MOD_WPDIBL2, IF_REAL, "Width dependence of pdiblc2"), +IOP( "wpdiblcb", BSIM4_MOD_WPDIBLB, IF_REAL, "Width dependence of pdiblcb"), IOP( "wfprout", BSIM4_MOD_WFPROUT, IF_REAL, "Width dependence of pdiblcb"), IOP( "wpdits", BSIM4_MOD_WPDITS, IF_REAL, "Width dependence of pdits"), IOP( "wpditsd", BSIM4_MOD_WPDITSD, IF_REAL, "Width dependence of pditsd"), -IOP( "wpscbe1", BSIM4_MOD_WPSCBE1, IF_REAL, "Width dependence of pscbe1"), -IOP( "wpscbe2", BSIM4_MOD_WPSCBE2, IF_REAL, "Width dependence of pscbe2"), -IOP( "wpvag", BSIM4_MOD_WPVAG, IF_REAL, "Width dependence of pvag"), +IOP( "wpscbe1", BSIM4_MOD_WPSCBE1, IF_REAL, "Width dependence of pscbe1"), +IOP( "wpscbe2", BSIM4_MOD_WPSCBE2, IF_REAL, "Width dependence of pscbe2"), +IOP( "wpvag", BSIM4_MOD_WPVAG, IF_REAL, "Width dependence of pvag"), IOP( "wwr", BSIM4_MOD_WWR, IF_REAL, "Width dependence of wr"), IOP( "wdwg", BSIM4_MOD_WDWG, IF_REAL, "Width dependence of dwg"), IOP( "wdwb", BSIM4_MOD_WDWB, IF_REAL, "Width dependence of dwb"), @@ -773,16 +775,16 @@ IOP( "wbeta0", BSIM4_MOD_WBETA0, IF_REAL, "Width dependence of beta0"), IOP( "wagidl", BSIM4_MOD_WAGIDL, IF_REAL, "Width dependence of agidl"), IOP( "wbgidl", BSIM4_MOD_WBGIDL, IF_REAL, "Width dependence of bgidl"), IOP( "wcgidl", BSIM4_MOD_WCGIDL, IF_REAL, "Width dependence of cgidl"), -IOP( "wrgidl", BSIM4_MOD_WRGIDL, IF_REAL, "Width dependence of rgidl"), /* v4.7 New GIDL/GISL */ -IOP( "wkgidl", BSIM4_MOD_WKGIDL, IF_REAL, "Width dependence of kgidl"), /* v4.7 New GIDL/GISL */ -IOP( "wfgidl", BSIM4_MOD_WFGIDL, IF_REAL, "Width dependence of fgidl"), /* v4.7 New GIDL/GISL */ +IOP( "wrgidl", BSIM4_MOD_WRGIDL, IF_REAL, "Width dependence of rgidl"), /* v4.7 New GIDL/GISL */ +IOP( "wkgidl", BSIM4_MOD_WKGIDL, IF_REAL, "Width dependence of kgidl"), /* v4.7 New GIDL/GISL */ +IOP( "wfgidl", BSIM4_MOD_WFGIDL, IF_REAL, "Width dependence of fgidl"), /* v4.7 New GIDL/GISL */ IOP( "wegidl", BSIM4_MOD_WEGIDL, IF_REAL, "Width dependence of egidl"), IOP( "wagisl", BSIM4_MOD_WAGISL, IF_REAL, "Width dependence of agisl"), IOP( "wbgisl", BSIM4_MOD_WBGISL, IF_REAL, "Width dependence of bgisl"), IOP( "wcgisl", BSIM4_MOD_WCGISL, IF_REAL, "Width dependence of cgisl"), -IOP( "wrgisl", BSIM4_MOD_WRGISL, IF_REAL, "Width dependence of rgisl"), /* v4.7 New GIDL/GISL */ -IOP( "wkgisl", BSIM4_MOD_WKGISL, IF_REAL, "Width dependence of kgisl"), /* v4.7 New GIDL/GISL */ -IOP( "wfgisl", BSIM4_MOD_WFGISL, IF_REAL, "Width dependence of fgisl"), /* v4.7 New GIDL/GISL */ +IOP( "wrgisl", BSIM4_MOD_WRGISL, IF_REAL, "Width dependence of rgisl"), /* v4.7 New GIDL/GISL */ +IOP( "wkgisl", BSIM4_MOD_WKGISL, IF_REAL, "Width dependence of kgisl"), /* v4.7 New GIDL/GISL */ +IOP( "wfgisl", BSIM4_MOD_WFGISL, IF_REAL, "Width dependence of fgisl"), /* v4.7 New GIDL/GISL */ IOP( "wegisl", BSIM4_MOD_WEGISL, IF_REAL, "Width dependence of egisl"), IOP( "waigc", BSIM4_MOD_WAIGC, IF_REAL, "Width dependence of aigc"), IOP( "wbigc", BSIM4_MOD_WBIGC, IF_REAL, "Width dependence of bigc"), @@ -830,18 +832,19 @@ IOP( "wteta0", BSIM4_MOD_WTETA0, IF_REAL, "Width dependence of teta0"), IOP( "wtvoffcv", BSIM4_MOD_WTVOFFCV, IF_REAL, "Width dependence of tvoffcv"), /* v4.7 Tanvir*/ IOP( "pcdsc", BSIM4_MOD_PCDSC, IF_REAL, "Cross-term dependence of cdsc"), -IOP( "pcdscb", BSIM4_MOD_PCDSCB, IF_REAL, "Cross-term dependence of cdscb"), +IOP( "pcdscb", BSIM4_MOD_PCDSCB, IF_REAL, "Cross-term dependence of cdscb"), IOP( "pcdscd", BSIM4_MOD_PCDSCD, IF_REAL, "Cross-term dependence of cdscd"), IOP( "pcit", BSIM4_MOD_PCIT, IF_REAL, "Cross-term dependence of cit"), IOP( "pnfactor", BSIM4_MOD_PNFACTOR, IF_REAL, "Cross-term dependence of nfactor"), IOP( "pxj", BSIM4_MOD_PXJ, IF_REAL, "Cross-term dependence of xj"), IOP( "pvsat", BSIM4_MOD_PVSAT, IF_REAL, "Cross-term dependence of vsat"), IOP( "pat", BSIM4_MOD_PAT, IF_REAL, "Cross-term dependence of at"), -IOP( "pa0", BSIM4_MOD_PA0, IF_REAL, "Cross-term dependence of a0"), +IOP( "pa0", BSIM4_MOD_PA0, IF_REAL, "Cross-term dependence of a0"), IOP( "pags", BSIM4_MOD_PAGS, IF_REAL, "Cross-term dependence of ags"), IOP( "pa1", BSIM4_MOD_PA1, IF_REAL, "Cross-term dependence of a1"), IOP( "pa2", BSIM4_MOD_PA2, IF_REAL, "Cross-term dependence of a2"), IOP( "pketa", BSIM4_MOD_PKETA, IF_REAL, "Cross-term dependence of keta"), +IOP( "pketac", BSIM4_MOD_PKETAC, IF_REAL, "Cross-term dependence of ketac"), IOP( "pnsub", BSIM4_MOD_PNSUB, IF_REAL, "Cross-term dependence of nsub"), IOP( "pndep", BSIM4_MOD_PNDEP, IF_REAL, "Cross-term dependence of ndep"), IOP( "pnsd", BSIM4_MOD_PNSD, IF_REAL, "Cross-term dependence of nsd"), @@ -876,8 +879,8 @@ IOP( "pdvt1w", BSIM4_MOD_PDVT1W, IF_REAL, "Cross-term dependence of dvt1w"), IOP( "pdvt2w", BSIM4_MOD_PDVT2W, IF_REAL, "Cross-term dependence of dvt2w"), IOP( "pdrout", BSIM4_MOD_PDROUT, IF_REAL, "Cross-term dependence of drout"), IOP( "pdsub", BSIM4_MOD_PDSUB, IF_REAL, "Cross-term dependence of dsub"), -IOP( "pvth0", BSIM4_MOD_PVTH0, IF_REAL,"Cross-term dependence of vth0"), -IOPR("pvtho", BSIM4_MOD_PVTH0, IF_REAL,"Cross-term dependence of vtho"), +IOP( "pvth0", BSIM4_MOD_PVTH0, IF_REAL,"Cross-term dependence of vto"), +IOPR("pvtho", BSIM4_MOD_PVTH0, IF_REAL,"Cross-term dependence of vto"), IOP( "pua", BSIM4_MOD_PUA, IF_REAL, "Cross-term dependence of ua"), IOP( "pua1", BSIM4_MOD_PUA1, IF_REAL, "Cross-term dependence of ua1"), IOP( "pub", BSIM4_MOD_PUB, IF_REAL, "Cross-term dependence of ub"), @@ -895,12 +898,12 @@ IOP( "pvoff", BSIM4_MOD_PVOFF, IF_REAL, "Cross-term dependence of voff"), IOP( "pminv", BSIM4_MOD_PMINV, IF_REAL, "Cross-term dependence of minv"), IOP( "pminvcv", BSIM4_MOD_PMINVCV, IF_REAL, "Cross-term dependence of minvcv"), IOP( "pdelta", BSIM4_MOD_PDELTA, IF_REAL, "Cross-term dependence of delta"), -IOP( "prdsw", BSIM4_MOD_PRDSW, IF_REAL, "Cross-term dependence of rdsw "), +IOP( "prdsw", BSIM4_MOD_PRDSW, IF_REAL, "Cross-term dependence of rdsw "), IOP( "prsw", BSIM4_MOD_PRSW, IF_REAL, "Cross-term dependence of rsw"), IOP( "prdw", BSIM4_MOD_PRDW, IF_REAL, "Cross-term dependence of rdw"), -IOP( "pprwg", BSIM4_MOD_PPRWG, IF_REAL, "Cross-term dependence of prwg "), -IOP( "pprwb", BSIM4_MOD_PPRWB, IF_REAL, "Cross-term dependence of prwb "), +IOP( "pprwg", BSIM4_MOD_PPRWG, IF_REAL, "Cross-term dependence of prwg "), +IOP( "pprwb", BSIM4_MOD_PPRWB, IF_REAL, "Cross-term dependence of prwb "), IOP( "pprt", BSIM4_MOD_PPRT, IF_REAL, "Cross-term dependence of prt "), IOP( "peta0", BSIM4_MOD_PETA0, IF_REAL, "Cross-term dependence of eta0"), @@ -914,7 +917,7 @@ IOP( "ppdits", BSIM4_MOD_PPDITS, IF_REAL, "Cross-term dependence of pdits"), IOP( "ppditsd", BSIM4_MOD_PPDITSD, IF_REAL, "Cross-term dependence of pditsd"), IOP( "ppscbe1", BSIM4_MOD_PPSCBE1, IF_REAL, "Cross-term dependence of pscbe1"), IOP( "ppscbe2", BSIM4_MOD_PPSCBE2, IF_REAL, "Cross-term dependence of pscbe2"), -IOP( "ppvag", BSIM4_MOD_PPVAG, IF_REAL, "Cross-term dependence of pvag"), +IOP( "ppvag", BSIM4_MOD_PPVAG, IF_REAL, "Cross-term dependence of pvag"), IOP( "pwr", BSIM4_MOD_PWR, IF_REAL, "Cross-term dependence of wr"), IOP( "pdwg", BSIM4_MOD_PDWG, IF_REAL, "Cross-term dependence of dwg"), IOP( "pdwb", BSIM4_MOD_PDWB, IF_REAL, "Cross-term dependence of dwb"), @@ -934,17 +937,17 @@ IOP( "pbeta0", BSIM4_MOD_PBETA0, IF_REAL, "Cross-term dependence of beta0"), IOP( "pagidl", BSIM4_MOD_PAGIDL, IF_REAL, "Cross-term dependence of agidl"), IOP( "pbgidl", BSIM4_MOD_PBGIDL, IF_REAL, "Cross-term dependence of bgidl"), IOP( "pcgidl", BSIM4_MOD_PCGIDL, IF_REAL, "Cross-term dependence of cgidl"), -IOP( "prgidl", BSIM4_MOD_PRGIDL, IF_REAL, "Cross-term dependence of rgidl"), /* v4.7 New GIDL/GISL */ -IOP( "pkgidl", BSIM4_MOD_PKGIDL, IF_REAL, "Cross-term dependence of kgidl"), /* v4.7 New GIDL/GISL */ -IOP( "pfgidl", BSIM4_MOD_PFGIDL, IF_REAL, "Cross-term dependence of fgidl"), /* v4.7 New GIDL/GISL */ +IOP( "prgidl", BSIM4_MOD_PRGIDL, IF_REAL, "Cross-term dependence of rgidl"), /* v4.7 New GIDL/GISL */ +IOP( "pkgidl", BSIM4_MOD_PKGIDL, IF_REAL, "Cross-term dependence of kgidl"), /* v4.7 New GIDL/GISL */ +IOP( "pfgidl", BSIM4_MOD_PFGIDL, IF_REAL, "Cross-term dependence of fgidl"), /* v4.7 New GIDL/GISL */ IOP( "pegidl", BSIM4_MOD_PEGIDL, IF_REAL, "Cross-term dependence of egidl"), IOP( "pagisl", BSIM4_MOD_PAGISL, IF_REAL, "Cross-term dependence of agisl"), IOP( "pbgisl", BSIM4_MOD_PBGISL, IF_REAL, "Cross-term dependence of bgisl"), IOP( "pcgisl", BSIM4_MOD_PCGISL, IF_REAL, "Cross-term dependence of cgisl"), IOP( "pegisl", BSIM4_MOD_PEGISL, IF_REAL, "Cross-term dependence of egisl"), -IOP( "prgisl", BSIM4_MOD_PRGISL, IF_REAL, "Cross-term dependence of rgisl"), /* v4.7 New GIDL/GISL */ -IOP( "pkgisl", BSIM4_MOD_PKGISL, IF_REAL, "Cross-term dependence of kgisl"), /* v4.7 New GIDL/GISL */ -IOP( "pfgisl", BSIM4_MOD_PFGISL, IF_REAL, "Cross-term dependence of fgisl"), /* v4.7 New GIDL/GISL */ +IOP( "prgisl", BSIM4_MOD_PRGISL, IF_REAL, "Cross-term dependence of rgisl"), /* v4.7 New GIDL/GISL */ +IOP( "pkgisl", BSIM4_MOD_PKGISL, IF_REAL, "Cross-term dependence of kgisl"), /* v4.7 New GIDL/GISL */ +IOP( "pfgisl", BSIM4_MOD_PFGISL, IF_REAL, "Cross-term dependence of fgisl"), /* v4.7 New GIDL/GISL */ IOP( "paigc", BSIM4_MOD_PAIGC, IF_REAL, "Cross-term dependence of aigc"), IOP( "pbigc", BSIM4_MOD_PBIGC, IF_REAL, "Cross-term dependence of bigc"), IOP( "pcigc", BSIM4_MOD_PCIGC, IF_REAL, "Cross-term dependence of cigc"), @@ -1071,8 +1074,9 @@ char *BSIM4names[] = { "Charge" }; -int BSIM4nSize = NUMELEMS(BSIM4names); -int BSIM4pTSize = NUMELEMS(BSIM4pTable); -int BSIM4mPTSize = NUMELEMS(BSIM4mPTable); -int BSIM4iSize = sizeof(BSIM4instance); -int BSIM4mSize = sizeof(BSIM4model); +int BSIM4nSize = NUMELEMS(BSIM4names); +int BSIM4pTSize = NUMELEMS(BSIM4pTable); +int BSIM4mPTSize = NUMELEMS(BSIM4mPTable); +int BSIM4iSize = sizeof(BSIM4instance); +int BSIM4mSize = sizeof(BSIM4model); + diff --git a/src/spicelib/devices/bsim4/b4acld.c b/src/spicelib/devices/bsim4/b4acld.c index 1bb486cd7..18257423c 100644 --- a/src/spicelib/devices/bsim4/b4acld.c +++ b/src/spicelib/devices/bsim4/b4acld.c @@ -1,38 +1,34 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* Licensed under Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the license at http://opensource.org/licenses/ECL-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc */ + #include "ngspice/ngspice.h" #include "ngspice/cktdefs.h" #include "bsim4def.h" #include "ngspice/sperror.h" #include "ngspice/suffix.h" - int BSIM4acLoad( GENmodel *inModel, @@ -68,15 +64,13 @@ double FwdSumr, RevSumr, Gmr, Gmbsr; double FwdSumi, RevSumi, Gmi, Gmbsi; struct bsim4SizeDependParam *pParam; double ggidld, ggidlg, ggidlb, ggislg, ggislb, ggisls; - -double m; +double m, mult_i, mult_q; omega = ckt->CKTomega; for (; model != NULL; model = BSIM4nextModel(model)) { for (here = BSIM4instances(model); here!= NULL; here = BSIM4nextInstance(here)) - { - pParam = here->pParam; + { pParam = here->pParam; capbd = here->BSIM4capbd; capbs = here->BSIM4capbs; cgso = here->BSIM4cgso; @@ -106,7 +100,7 @@ double m; Cdsr = here->BSIM4cdsb * T2; Cdbr = -(Cddr + Cdgr + Cdsr); - /* WDLiu: Cxyi mulitplied by jomega below, and actually to be of conductance */ + /* WDLiu: Cxyi mulitplied by jomega below, and actually to be of conductance */ Cddi = here->BSIM4cddb * T3 * omega; Cdgi = here->BSIM4cdgb * T3 * omega; Cdsi = here->BSIM4cdsb * T3 * omega; @@ -158,7 +152,7 @@ double m; } - if (here->BSIM4mode >= 0) + if (here->BSIM4mode >= 0) { Gmr = gmr; Gmbsr = gmbsr; FwdSumr = Gmr + Gmbsr; @@ -236,16 +230,16 @@ double m; xcgmdb = -cgdo * omega; xcgmsb = -cgso * omega; xcgmbb = -pParam->BSIM4cgbo * omega; - + xcdgmb = xcgmdb; xcsgmb = xcgmsb; xcbgmb = xcgmbb; - + xcggbr = Cggr * omega; xcgdbr = Cgdr * omega; xcgsbr = Cgsr * omega; xcgbbr = -(xcggbr + xcgdbr + xcgsbr); - + xcdgbr = Cdgr * omega; xcsgbr = Csgr * omega; xcbgb = here->BSIM4cbgb * omega; @@ -255,18 +249,18 @@ double m; xcgdbr = (Cgdr - cgdo) * omega; xcgsbr = (Cgsr - cgso) * omega; xcgbbr = -(xcggbr + xcgdbr + xcgsbr); - + xcdgbr = (Cdgr - cgdo) * omega; xcsgbr = (Csgr - cgso) * omega; xcbgb = (here->BSIM4cbgb - pParam->BSIM4cgbo) * omega; - + xcdgmb = xcsgmb = xcbgmb = 0.0; } xcddbr = (Cddr + here->BSIM4capbd + cgdo) * omega; xcdsbr = Cdsr * omega; xcsdbr = Csdr * omega; xcssbr = (here->BSIM4capbs + cgso + Cssr) * omega; - + if (!here->BSIM4rbodyMod) { xcdbbr = -(xcdgbr + xcddbr + xcdsbr + xcdgmb); xcsbbr = -(xcsgbr + xcsdbr + xcssbr + xcsgmb); @@ -278,11 +272,11 @@ double m; else { xcdbbr = Cdbr * omega; xcsbbr = -(xcsgbr + xcsdbr + xcssbr + xcsgmb) - + here->BSIM4capbs * omega; + + here->BSIM4capbs * omega; xcbdb = here->BSIM4cbdb * omega; xcbsb = here->BSIM4cbsb * omega; - + xcdbdb = -here->BSIM4capbd * omega; xcsbsb = -here->BSIM4capbs * omega; } @@ -300,7 +294,7 @@ double m; xcgdbi = Cgdi; xcgsbi = Cgsi; xcgbbi = Cgbi; - } + } else /* Reverse mode */ { Gmr = -gmr; Gmbsr = -gmbsr; @@ -380,16 +374,16 @@ double m; xcgmdb = -cgdo * omega; xcgmsb = -cgso * omega; xcgmbb = -pParam->BSIM4cgbo * omega; - + xcdgmb = xcgmdb; xcsgmb = xcgmsb; xcbgmb = xcgmbb; - + xcggbr = Cggr * omega; xcgdbr = Cgsr * omega; xcgsbr = Cgdr * omega; xcgbbr = -(xcggbr + xcgdbr + xcgsbr); - + xcdgbr = Csgr * omega; xcsgbr = Cdgr * omega; xcbgb = here->BSIM4cbgb * omega; @@ -399,18 +393,18 @@ double m; xcgdbr = (Cgsr - cgdo) * omega; xcgsbr = (Cgdr - cgso) * omega; xcgbbr = -(xcggbr + xcgdbr + xcgsbr); - + xcdgbr = (Csgr - cgdo) * omega; xcsgbr = (Cdgr - cgso) * omega; xcbgb = (here->BSIM4cbgb - pParam->BSIM4cgbo) * omega; - + xcdgmb = xcsgmb = xcbgmb = 0.0; } xcddbr = (here->BSIM4capbd + cgdo + Cssr) * omega; xcdsbr = Csdr * omega; xcsdbr = Cdsr * omega; xcssbr = (Cddr + here->BSIM4capbs + cgso) * omega; - + if (!here->BSIM4rbodyMod) { xcdbbr = -(xcdgbr + xcddbr + xcdsbr + xcdgmb); xcsbbr = -(xcsgbr + xcsdbr + xcssbr + xcsgmb); @@ -468,6 +462,8 @@ double m; * Loading AC matrix */ m = here->BSIM4m; + mult_i = here->BSIM4mult_i; + mult_q = here->BSIM4mult_q; if (!model->BSIM4rdsMod) { gdpr = here->BSIM4drainConductance; @@ -486,122 +482,122 @@ double m; geltd = here->BSIM4grgeltd; if (here->BSIM4rgateMod == 1) - { *(here->BSIM4GEgePtr) += m * geltd; - *(here->BSIM4GPgePtr) -= m * geltd; - *(here->BSIM4GEgpPtr) -= m * geltd; + { *(here->BSIM4GEgePtr) += mult_i * geltd; + *(here->BSIM4GPgePtr) -= mult_i * geltd; + *(here->BSIM4GEgpPtr) -= mult_i * geltd; - *(here->BSIM4GPgpPtr +1) += m * xcggbr; - *(here->BSIM4GPgpPtr) += m * (geltd + xcggbi + gIgtotg); - *(here->BSIM4GPdpPtr +1) += m * xcgdbr; - *(here->BSIM4GPdpPtr) += m * (xcgdbi + gIgtotd); - *(here->BSIM4GPspPtr +1) += m * xcgsbr; - *(here->BSIM4GPspPtr) += m * (xcgsbi + gIgtots); - *(here->BSIM4GPbpPtr +1) += m * xcgbbr; - *(here->BSIM4GPbpPtr) += m * (xcgbbi + gIgtotb); + *(here->BSIM4GPgpPtr +1) += mult_q * xcggbr; + *(here->BSIM4GPgpPtr) += mult_i * (geltd + gIgtotg) + mult_q * xcggbi; + *(here->BSIM4GPdpPtr +1) += mult_q * xcgdbr; + *(here->BSIM4GPdpPtr) += mult_q * xcgdbi + mult_i * gIgtotd; + *(here->BSIM4GPspPtr +1) += mult_q * xcgsbr; + *(here->BSIM4GPspPtr) += mult_q * xcgsbi + mult_i * gIgtots; + *(here->BSIM4GPbpPtr +1) += mult_q * xcgbbr; + *(here->BSIM4GPbpPtr) += mult_q * xcgbbi + mult_i * gIgtotb; } /* WDLiu: gcrg already subtracted from all gcrgg below */ else if (here->BSIM4rgateMod == 2) - { *(here->BSIM4GEgePtr) += m * gcrg; - *(here->BSIM4GEgpPtr) += m * gcrgg; - *(here->BSIM4GEdpPtr) += m * gcrgd; - *(here->BSIM4GEspPtr) += m * gcrgs; - *(here->BSIM4GEbpPtr) += m * gcrgb; + { *(here->BSIM4GEgePtr) += mult_i * gcrg; + *(here->BSIM4GEgpPtr) += mult_i * gcrgg; + *(here->BSIM4GEdpPtr) += mult_i * gcrgd; + *(here->BSIM4GEspPtr) += mult_i * gcrgs; + *(here->BSIM4GEbpPtr) += mult_i * gcrgb; - *(here->BSIM4GPgePtr) -= m * gcrg; - *(here->BSIM4GPgpPtr +1) += m * xcggbr; - *(here->BSIM4GPgpPtr) -= m * (gcrgg - xcggbi - gIgtotg); - *(here->BSIM4GPdpPtr +1) += m * xcgdbr; - *(here->BSIM4GPdpPtr) -= m * (gcrgd - xcgdbi - gIgtotd); - *(here->BSIM4GPspPtr +1) += m * xcgsbr; - *(here->BSIM4GPspPtr) -= m * (gcrgs - xcgsbi - gIgtots); - *(here->BSIM4GPbpPtr +1) += m * xcgbbr; - *(here->BSIM4GPbpPtr) -= m * (gcrgb - xcgbbi - gIgtotb); + *(here->BSIM4GPgePtr) -= mult_i * gcrg; + *(here->BSIM4GPgpPtr +1) += mult_q * xcggbr; + *(here->BSIM4GPgpPtr) -= mult_i * (gcrgg - gIgtotg) - mult_q * xcggbi; + *(here->BSIM4GPdpPtr +1) += mult_q * xcgdbr; + *(here->BSIM4GPdpPtr) -= mult_i * (gcrgd - gIgtotd) - mult_q * xcgdbi; + *(here->BSIM4GPspPtr +1) += mult_q * xcgsbr; + *(here->BSIM4GPspPtr) -= mult_i * (gcrgs - gIgtots) - mult_q * xcgsbi; + *(here->BSIM4GPbpPtr +1) += mult_q * xcgbbr; + *(here->BSIM4GPbpPtr) -= mult_i * (gcrgb - gIgtotb) - mult_q * xcgbbi; } else if (here->BSIM4rgateMod == 3) - { *(here->BSIM4GEgePtr) += m * geltd; - *(here->BSIM4GEgmPtr) -= m * geltd; - *(here->BSIM4GMgePtr) -= m * geltd; - *(here->BSIM4GMgmPtr) += m * (geltd + gcrg); - *(here->BSIM4GMgmPtr +1) += m * xcgmgmb; - - *(here->BSIM4GMdpPtr) += m * gcrgd; - *(here->BSIM4GMdpPtr +1) += m * xcgmdb; - *(here->BSIM4GMgpPtr) += m * gcrgg; - *(here->BSIM4GMspPtr) += m * gcrgs; - *(here->BSIM4GMspPtr +1) += m * xcgmsb; - *(here->BSIM4GMbpPtr) += m * gcrgb; - *(here->BSIM4GMbpPtr +1) += m * xcgmbb; - - *(here->BSIM4DPgmPtr +1) += m * xcdgmb; - *(here->BSIM4GPgmPtr) -= m * gcrg; - *(here->BSIM4SPgmPtr +1) += m * xcsgmb; - *(here->BSIM4BPgmPtr +1) += m * xcbgmb; - - *(here->BSIM4GPgpPtr) -= m * (gcrgg - xcggbi - gIgtotg); - *(here->BSIM4GPgpPtr +1) += m * xcggbr; - *(here->BSIM4GPdpPtr) -= m * (gcrgd - xcgdbi - gIgtotd); - *(here->BSIM4GPdpPtr +1) += m * xcgdbr; - *(here->BSIM4GPspPtr) -= m * (gcrgs - xcgsbi - gIgtots); - *(here->BSIM4GPspPtr +1) += m * xcgsbr; - *(here->BSIM4GPbpPtr) -= m * (gcrgb - xcgbbi - gIgtotb); - *(here->BSIM4GPbpPtr +1) += m * xcgbbr; + { *(here->BSIM4GEgePtr) += mult_i * geltd; + *(here->BSIM4GEgmPtr) -= mult_i * geltd; + *(here->BSIM4GMgePtr) -= mult_i * geltd; + *(here->BSIM4GMgmPtr) += mult_i * (geltd + gcrg); + *(here->BSIM4GMgmPtr +1) += mult_q * xcgmgmb; + + *(here->BSIM4GMdpPtr) += mult_i * gcrgd; + *(here->BSIM4GMdpPtr +1) += mult_q * xcgmdb; + *(here->BSIM4GMgpPtr) += mult_i * gcrgg; + *(here->BSIM4GMspPtr) += mult_i * gcrgs; + *(here->BSIM4GMspPtr +1) += mult_q * xcgmsb; + *(here->BSIM4GMbpPtr) += mult_i * gcrgb; + *(here->BSIM4GMbpPtr +1) += mult_q * xcgmbb; + + *(here->BSIM4DPgmPtr +1) += mult_q * xcdgmb; + *(here->BSIM4GPgmPtr) -= mult_i * gcrg; + *(here->BSIM4SPgmPtr +1) += mult_q * xcsgmb; + *(here->BSIM4BPgmPtr +1) += mult_q * xcbgmb; + + *(here->BSIM4GPgpPtr) -= mult_i * (gcrgg - gIgtotg) - mult_q * xcggbi; + *(here->BSIM4GPgpPtr +1) += mult_q * xcggbr; + *(here->BSIM4GPdpPtr) -= mult_i * (gcrgd - gIgtotd) - mult_q * xcgdbi; + *(here->BSIM4GPdpPtr +1) += mult_q * xcgdbr; + *(here->BSIM4GPspPtr) -= mult_i * (gcrgs - gIgtots) - mult_q * xcgsbi; + *(here->BSIM4GPspPtr +1) += mult_q * xcgsbr; + *(here->BSIM4GPbpPtr) -= mult_i * (gcrgb - gIgtotb) - mult_q * xcgbbi; + *(here->BSIM4GPbpPtr +1) += mult_q * xcgbbr; } else - { *(here->BSIM4GPgpPtr +1) += m * xcggbr; - *(here->BSIM4GPgpPtr) += m * (xcggbi + gIgtotg); - *(here->BSIM4GPdpPtr +1) += m * xcgdbr; - *(here->BSIM4GPdpPtr) += m * (xcgdbi + gIgtotd); - *(here->BSIM4GPspPtr +1) += m * xcgsbr; - *(here->BSIM4GPspPtr) += m * (xcgsbi + gIgtots); - *(here->BSIM4GPbpPtr +1) += m * xcgbbr; - *(here->BSIM4GPbpPtr) += m * (xcgbbi + gIgtotb); + { *(here->BSIM4GPgpPtr +1) += mult_q * xcggbr; + *(here->BSIM4GPgpPtr) += mult_q * xcggbi + mult_i * gIgtotg; + *(here->BSIM4GPdpPtr +1) += mult_q * xcgdbr; + *(here->BSIM4GPdpPtr) += mult_q * xcgdbi + mult_i * gIgtotd; + *(here->BSIM4GPspPtr +1) += mult_q * xcgsbr; + *(here->BSIM4GPspPtr) += mult_q * xcgsbi + mult_i * gIgtots; + *(here->BSIM4GPbpPtr +1) += mult_q * xcgbbr; + *(here->BSIM4GPbpPtr) += mult_q * xcgbbi + mult_i * gIgtotb; } if (model->BSIM4rdsMod) - { (*(here->BSIM4DgpPtr) += m * gdtotg); - (*(here->BSIM4DspPtr) += m * gdtots); - (*(here->BSIM4DbpPtr) += m * gdtotb); - (*(here->BSIM4SdpPtr) += m * gstotd); - (*(here->BSIM4SgpPtr) += m * gstotg); - (*(here->BSIM4SbpPtr) += m * gstotb); + { (*(here->BSIM4DgpPtr) += mult_i * gdtotg); + (*(here->BSIM4DspPtr) += mult_i * gdtots); + (*(here->BSIM4DbpPtr) += mult_i * gdtotb); + (*(here->BSIM4SdpPtr) += mult_i * gstotd); + (*(here->BSIM4SgpPtr) += mult_i * gstotg); + (*(here->BSIM4SbpPtr) += mult_i * gstotb); } - *(here->BSIM4DPdpPtr +1) += m * (xcddbr + gdsi + RevSumi); - *(here->BSIM4DPdpPtr) += m * (gdpr + xcddbi + gdsr + here->BSIM4gbd - - gdtotd + RevSumr + gbdpdp - gIdtotd); - *(here->BSIM4DPdPtr) -= m * (gdpr + gdtot); - *(here->BSIM4DPgpPtr +1) += m * (xcdgbr + Gmi); - *(here->BSIM4DPgpPtr) += m * (Gmr + xcdgbi - gdtotg + gbdpg - gIdtotg); - *(here->BSIM4DPspPtr +1) += m * (xcdsbr - gdsi - FwdSumi); - *(here->BSIM4DPspPtr) -= m * (gdsr - xcdsbi + FwdSumr + gdtots - gbdpsp + gIdtots); - *(here->BSIM4DPbpPtr +1) += m * (xcdbbr + Gmbsi); - *(here->BSIM4DPbpPtr) -= m * (gjbd + gdtotb - xcdbbi - Gmbsr - gbdpb + gIdtotb); + *(here->BSIM4DPdpPtr +1) += mult_q * xcddbr + mult_i * (gdsi + RevSumi); + *(here->BSIM4DPdpPtr) += + mult_i * (gdpr + gdsr + here->BSIM4gbd + - gdtotd + RevSumr + gbdpdp - gIdtotd) + mult_q * xcddbi; + *(here->BSIM4DPdPtr) -= mult_i * (gdpr + gdtot); + *(here->BSIM4DPgpPtr +1) += mult_q * xcdgbr + mult_i * Gmi; + *(here->BSIM4DPgpPtr) += mult_i * (Gmr - gdtotg + gbdpg - gIdtotg) + mult_q * xcdgbi; + *(here->BSIM4DPspPtr +1) += mult_q * xcdsbr - mult_i * (gdsi + FwdSumi); + *(here->BSIM4DPspPtr) -= mult_i * (gdsr + FwdSumr + gdtots - gbdpsp + gIdtots) - mult_q * xcdsbi; + *(here->BSIM4DPbpPtr +1) += mult_q * xcdbbr + mult_i * Gmbsi; + *(here->BSIM4DPbpPtr) -= mult_i * (gjbd + gdtotb - Gmbsr - gbdpb + gIdtotb) - mult_q * xcdbbi; - *(here->BSIM4DdpPtr) -= m * (gdpr - gdtotd); - *(here->BSIM4DdPtr) += m * (gdpr + gdtot); + *(here->BSIM4DdpPtr) -= mult_i * (gdpr - gdtotd); + *(here->BSIM4DdPtr) += mult_i * (gdpr + gdtot); - *(here->BSIM4SPdpPtr +1) += m * (xcsdbr - gdsi - RevSumi); - *(here->BSIM4SPdpPtr) -= m * (gdsr - xcsdbi + gstotd + RevSumr - gbspdp + gIstotd); - *(here->BSIM4SPgpPtr +1) += m * (xcsgbr - Gmi); - *(here->BSIM4SPgpPtr) -= m * (Gmr - xcsgbi + gstotg - gbspg + gIstotg); - *(here->BSIM4SPspPtr +1) += m * (xcssbr + gdsi + FwdSumi); - *(here->BSIM4SPspPtr) += m * (gspr + xcssbi + gdsr + here->BSIM4gbs - - gstots + FwdSumr + gbspsp - gIstots); - *(here->BSIM4SPsPtr) -= m * (gspr + gstot); - *(here->BSIM4SPbpPtr +1) += m * (xcsbbr - Gmbsi); - *(here->BSIM4SPbpPtr) -= m * (gjbs + gstotb - xcsbbi + Gmbsr - gbspb + gIstotb); + *(here->BSIM4SPdpPtr +1) += mult_q * xcsdbr - mult_i * (gdsi + RevSumi); + *(here->BSIM4SPdpPtr) -= mult_i * (gdsr + gstotd + RevSumr - gbspdp + gIstotd) - mult_q * xcsdbi; + *(here->BSIM4SPgpPtr +1) += mult_q * xcsgbr - mult_i * Gmi; + *(here->BSIM4SPgpPtr) -= mult_i * (Gmr + gstotg - gbspg + gIstotg) - mult_q * xcsgbi; + *(here->BSIM4SPspPtr +1) += mult_q * xcssbr + mult_i * (gdsi + FwdSumi); + *(here->BSIM4SPspPtr) += mult_i * (gspr + gdsr + here->BSIM4gbs + - gstots + FwdSumr + gbspsp - gIstots) + mult_q * xcssbi; + *(here->BSIM4SPsPtr) -= mult_i * (gspr + gstot); + *(here->BSIM4SPbpPtr +1) += mult_q * xcsbbr - mult_i * Gmbsi; + *(here->BSIM4SPbpPtr) -= mult_i * (gjbs + gstotb + Gmbsr - gbspb + gIstotb) - mult_q * xcsbbi; - *(here->BSIM4SspPtr) -= m * (gspr - gstots); - *(here->BSIM4SsPtr) += m * (gspr + gstot); + *(here->BSIM4SspPtr) -= mult_i * (gspr - gstots); + *(here->BSIM4SsPtr) += mult_i * (gspr + gstot); - *(here->BSIM4BPdpPtr +1) += m * xcbdb; - *(here->BSIM4BPdpPtr) -= m * (gjbd - gbbdp + gIbtotd); - *(here->BSIM4BPgpPtr +1) += m * xcbgb; - *(here->BSIM4BPgpPtr) -= m * (here->BSIM4gbgs + gIbtotg); - *(here->BSIM4BPspPtr +1) += m * xcbsb; - *(here->BSIM4BPspPtr) -= m * (gjbs - gbbsp + gIbtots); - *(here->BSIM4BPbpPtr +1) += m * xcbbb; - *(here->BSIM4BPbpPtr) += m * (gjbd + gjbs - here->BSIM4gbbs - - gIbtotb); + *(here->BSIM4BPdpPtr +1) += mult_q * xcbdb; + *(here->BSIM4BPdpPtr) -= mult_i * (gjbd - gbbdp + gIbtotd); + *(here->BSIM4BPgpPtr +1) += mult_q * xcbgb; + *(here->BSIM4BPgpPtr) -= mult_i * (here->BSIM4gbgs + gIbtotg); + *(here->BSIM4BPspPtr +1) += mult_q * xcbsb; + *(here->BSIM4BPspPtr) -= mult_i * (gjbs - gbbsp + gIbtots); + *(here->BSIM4BPbpPtr +1) += mult_q * xcbbb; + *(here->BSIM4BPbpPtr) += mult_i * (gjbd + gjbs - here->BSIM4gbbs + - gIbtotb); ggidld = here->BSIM4ggidld; ggidlg = here->BSIM4ggidlg; ggidlb = here->BSIM4ggidlb; @@ -610,67 +606,67 @@ double m; ggislb = here->BSIM4ggislb; /* stamp gidl */ - (*(here->BSIM4DPdpPtr) += m * ggidld); - (*(here->BSIM4DPgpPtr) += m * ggidlg); - (*(here->BSIM4DPspPtr) -= m * ((ggidlg + ggidld) + ggidlb)); - (*(here->BSIM4DPbpPtr) += m * ggidlb); - (*(here->BSIM4BPdpPtr) -= m * ggidld); - (*(here->BSIM4BPgpPtr) -= m * ggidlg); - (*(here->BSIM4BPspPtr) += m * ((ggidlg + ggidld) + ggidlb)); - (*(here->BSIM4BPbpPtr) -= m * ggidlb); + (*(here->BSIM4DPdpPtr) += mult_i * ggidld); + (*(here->BSIM4DPgpPtr) += mult_i * ggidlg); + (*(here->BSIM4DPspPtr) -= mult_i * ((ggidlg + ggidld) + ggidlb)); + (*(here->BSIM4DPbpPtr) += mult_i * ggidlb); + (*(here->BSIM4BPdpPtr) -= mult_i * ggidld); + (*(here->BSIM4BPgpPtr) -= mult_i * ggidlg); + (*(here->BSIM4BPspPtr) += mult_i * ((ggidlg + ggidld) + ggidlb)); + (*(here->BSIM4BPbpPtr) -= mult_i * ggidlb); /* stamp gisl */ - (*(here->BSIM4SPdpPtr) -= m * ((ggisls + ggislg) + ggislb)); - (*(here->BSIM4SPgpPtr) += m * ggislg); - (*(here->BSIM4SPspPtr) += m * ggisls); - (*(here->BSIM4SPbpPtr) += m * ggislb); - (*(here->BSIM4BPdpPtr) += m * ((ggislg + ggisls) + ggislb)); - (*(here->BSIM4BPgpPtr) -= m * ggislg); - (*(here->BSIM4BPspPtr) -= m * ggisls); - (*(here->BSIM4BPbpPtr) -= m * ggislb); + (*(here->BSIM4SPdpPtr) -= mult_i * ((ggisls + ggislg) + ggislb)); + (*(here->BSIM4SPgpPtr) += mult_i * ggislg); + (*(here->BSIM4SPspPtr) += mult_i * ggisls); + (*(here->BSIM4SPbpPtr) += mult_i * ggislb); + (*(here->BSIM4BPdpPtr) += mult_i * ((ggislg + ggisls) + ggislb)); + (*(here->BSIM4BPgpPtr) -= mult_i * ggislg); + (*(here->BSIM4BPspPtr) -= mult_i * ggisls); + (*(here->BSIM4BPbpPtr) -= mult_i * ggislb); if (here->BSIM4rbodyMod) - { (*(here->BSIM4DPdbPtr +1) += m * xcdbdb); - (*(here->BSIM4DPdbPtr) -= m * here->BSIM4gbd); - (*(here->BSIM4SPsbPtr +1) += m * xcsbsb); - (*(here->BSIM4SPsbPtr) -= m * here->BSIM4gbs); + { (*(here->BSIM4DPdbPtr +1) += mult_q * xcdbdb); + (*(here->BSIM4DPdbPtr) -= mult_i * here->BSIM4gbd); + (*(here->BSIM4SPsbPtr +1) += mult_q * xcsbsb); + (*(here->BSIM4SPsbPtr) -= mult_i * here->BSIM4gbs); - (*(here->BSIM4DBdpPtr +1) += m * xcdbdb); - (*(here->BSIM4DBdpPtr) -= m * here->BSIM4gbd); - (*(here->BSIM4DBdbPtr +1) -= m * xcdbdb); - (*(here->BSIM4DBdbPtr) += m * (here->BSIM4gbd + here->BSIM4grbpd + (*(here->BSIM4DBdpPtr +1) += mult_q * xcdbdb); + (*(here->BSIM4DBdpPtr) -= mult_i * here->BSIM4gbd); + (*(here->BSIM4DBdbPtr +1) -= mult_q * xcdbdb); + (*(here->BSIM4DBdbPtr) += mult_i * (here->BSIM4gbd + here->BSIM4grbpd + here->BSIM4grbdb)); - (*(here->BSIM4DBbpPtr) -= m * here->BSIM4grbpd); - (*(here->BSIM4DBbPtr) -= m * here->BSIM4grbdb); + (*(here->BSIM4DBbpPtr) -= mult_i * here->BSIM4grbpd); + (*(here->BSIM4DBbPtr) -= mult_i * here->BSIM4grbdb); - (*(here->BSIM4BPdbPtr) -= m * here->BSIM4grbpd); - (*(here->BSIM4BPbPtr) -= m * here->BSIM4grbpb); - (*(here->BSIM4BPsbPtr) -= m * here->BSIM4grbps); - (*(here->BSIM4BPbpPtr) += m * (here->BSIM4grbpd + here->BSIM4grbps - + here->BSIM4grbpb)); - /* WDLiu: (-here->BSIM4gbbs) already added to BPbpPtr */ + (*(here->BSIM4BPdbPtr) -= mult_i * here->BSIM4grbpd); + (*(here->BSIM4BPbPtr) -= mult_i * here->BSIM4grbpb); + (*(here->BSIM4BPsbPtr) -= mult_i * here->BSIM4grbps); + (*(here->BSIM4BPbpPtr) += mult_i * (here->BSIM4grbpd + here->BSIM4grbps + + here->BSIM4grbpb)); + /* WDLiu: (-here->BSIM4gbbs) already added to BPbpPtr */ - (*(here->BSIM4SBspPtr +1) += m * xcsbsb); - (*(here->BSIM4SBspPtr) -= m * here->BSIM4gbs); - (*(here->BSIM4SBbpPtr) -= m * here->BSIM4grbps); - (*(here->BSIM4SBbPtr) -= m * here->BSIM4grbsb); - (*(here->BSIM4SBsbPtr +1) -= m * xcsbsb); - (*(here->BSIM4SBsbPtr) += m * (here->BSIM4gbs - + here->BSIM4grbps + here->BSIM4grbsb)); + (*(here->BSIM4SBspPtr +1) += mult_q * xcsbsb); + (*(here->BSIM4SBspPtr) -= mult_i * here->BSIM4gbs); + (*(here->BSIM4SBbpPtr) -= mult_i * here->BSIM4grbps); + (*(here->BSIM4SBbPtr) -= mult_i * here->BSIM4grbsb); + (*(here->BSIM4SBsbPtr +1) -= mult_q * xcsbsb); + (*(here->BSIM4SBsbPtr) += mult_i * (here->BSIM4gbs + + here->BSIM4grbps + here->BSIM4grbsb)); - (*(here->BSIM4BdbPtr) -= m * here->BSIM4grbdb); - (*(here->BSIM4BbpPtr) -= m * here->BSIM4grbpb); - (*(here->BSIM4BsbPtr) -= m * here->BSIM4grbsb); - (*(here->BSIM4BbPtr) += m * (here->BSIM4grbsb + here->BSIM4grbdb + (*(here->BSIM4BdbPtr) -= mult_i * here->BSIM4grbdb); + (*(here->BSIM4BbpPtr) -= mult_i * here->BSIM4grbpb); + (*(here->BSIM4BsbPtr) -= mult_i * here->BSIM4grbsb); + (*(here->BSIM4BbPtr) += mult_i * (here->BSIM4grbsb + here->BSIM4grbdb + here->BSIM4grbpb)); } - /* - * WDLiu: The internal charge node generated for transient NQS is not needed for - * AC NQS. The following is not doing a real job, but we have to keep it; - * otherwise a singular AC NQS matrix may occur if the transient NQS is on. - * The charge node is isolated from the instance. - */ + /* + * WDLiu: The internal charge node generated for transient NQS is not needed for + * AC NQS. The following is not doing a real job, but we have to keep it; + * otherwise a singular AC NQS matrix may occur if the transient NQS is on. + * The charge node is isolated from the instance. + */ if (here->BSIM4trnqsMod) { (*(here->BSIM4QqPtr) += m * 1.0); (*(here->BSIM4QgpPtr) += 0.0); diff --git a/src/spicelib/devices/bsim4/b4ask.c b/src/spicelib/devices/bsim4/b4ask.c index 77dee5693..51913e7ed 100644 --- a/src/spicelib/devices/bsim4/b4ask.c +++ b/src/spicelib/devices/bsim4/b4ask.c @@ -1,31 +1,28 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* Licensed under Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the license at http://opensource.org/licenses/ECL-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc */ + #include "ngspice/ngspice.h" #include "ngspice/ifsim.h" #include "ngspice/cktdefs.h" @@ -46,7 +43,7 @@ BSIM4instance *here = (BSIM4instance*)inst; NG_IGNORE(select); - switch(which) + switch(which) { case BSIM4_L: value->rValue = here->BSIM4l; return(OK); @@ -56,6 +53,15 @@ BSIM4instance *here = (BSIM4instance*)inst; case BSIM4_M: value->rValue = here->BSIM4m; return(OK); + case BSIM4_MULT_I: + value->rValue = here->BSIM4mult_i; + return(OK); + case BSIM4_MULT_Q: + value->rValue = here->BSIM4mult_q; + return(OK); + case BSIM4_MULT_FN: + value->rValue = here->BSIM4mult_fn; + return(OK); case BSIM4_NF: value->rValue = here->BSIM4nf; return(OK); @@ -123,12 +129,6 @@ 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); @@ -197,11 +197,11 @@ BSIM4instance *here = (BSIM4instance*)inst; return(OK); case BSIM4_SOURCECONDUCT: value->rValue = here->BSIM4sourceConductance; - value->rValue *= here->BSIM4m; + value->rValue *= here->BSIM4mult_i; return(OK); case BSIM4_DRAINCONDUCT: value->rValue = here->BSIM4drainConductance; - value->rValue *= here->BSIM4m; + value->rValue *= here->BSIM4mult_i; return(OK); case BSIM4_VBD: value->rValue = *(ckt->CKTstate0 + here->BSIM4vbd); @@ -216,204 +216,202 @@ BSIM4instance *here = (BSIM4instance*)inst; value->rValue = *(ckt->CKTstate0 + here->BSIM4vds); return(OK); case BSIM4_CD: - value->rValue = here->BSIM4cd; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4cd; + value->rValue *= here->BSIM4mult_i; return(OK); case BSIM4_CBS: - value->rValue = here->BSIM4cbs; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4cbs; + value->rValue *= here->BSIM4mult_i; return(OK); case BSIM4_CBD: - value->rValue = here->BSIM4cbd; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4cbd; + value->rValue *= here->BSIM4mult_i; return(OK); case BSIM4_CSUB: - value->rValue = here->BSIM4csub; - value->rValue *= here->BSIM4m; - return(OK); - case BSIM4_QINV: - value->rValue = here-> BSIM4qinv; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4csub; + value->rValue *= here->BSIM4mult_i; return(OK); case BSIM4_IGIDL: - value->rValue = here->BSIM4Igidl; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4Igidl; + value->rValue *= here->BSIM4mult_i; return(OK); case BSIM4_IGISL: - value->rValue = here->BSIM4Igisl; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4Igisl; + value->rValue *= here->BSIM4mult_i; return(OK); case BSIM4_IGS: - value->rValue = here->BSIM4Igs; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4Igs; + value->rValue *= here->BSIM4mult_i; return(OK); case BSIM4_IGD: - value->rValue = here->BSIM4Igd; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4Igd; + value->rValue *= here->BSIM4mult_i; return(OK); case BSIM4_IGB: - value->rValue = here->BSIM4Igb; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4Igb; + value->rValue *= here->BSIM4mult_i; return(OK); case BSIM4_IGCS: - value->rValue = here->BSIM4Igcs; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4Igcs; + value->rValue *= here->BSIM4mult_i; return(OK); case BSIM4_IGCD: - value->rValue = here->BSIM4Igcd; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4Igcd; + value->rValue *= here->BSIM4mult_i; return(OK); case BSIM4_GM: - value->rValue = here->BSIM4gm; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4gm; + value->rValue *= here->BSIM4mult_i; return(OK); case BSIM4_GDS: - value->rValue = here->BSIM4gds; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4gds; + value->rValue *= here->BSIM4mult_i; return(OK); case BSIM4_GMBS: - value->rValue = here->BSIM4gmbs; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4gmbs; + value->rValue *= here->BSIM4mult_i; return(OK); case BSIM4_GBD: - value->rValue = here->BSIM4gbd; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4gbd; + value->rValue *= here->BSIM4mult_i; return(OK); case BSIM4_GBS: - value->rValue = here->BSIM4gbs; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4gbs; + value->rValue *= here->BSIM4mult_i; return(OK); /* case BSIM4_QB: - value->rValue = *(ckt->CKTstate0 + here->BSIM4qb); + value->rValue = *(ckt->CKTstate0 + here->BSIM4qb); return(OK); */ case BSIM4_CQB: - value->rValue = *(ckt->CKTstate0 + here->BSIM4cqb); + value->rValue = *(ckt->CKTstate0 + here->BSIM4cqb); return(OK); /* case BSIM4_QG: - value->rValue = *(ckt->CKTstate0 + here->BSIM4qg); + value->rValue = *(ckt->CKTstate0 + here->BSIM4qg); return(OK); */ case BSIM4_CQG: - value->rValue = *(ckt->CKTstate0 + here->BSIM4cqg); + value->rValue = *(ckt->CKTstate0 + here->BSIM4cqg); return(OK); /* case BSIM4_QD: - value->rValue = *(ckt->CKTstate0 + here->BSIM4qd); + value->rValue = *(ckt->CKTstate0 + here->BSIM4qd); return(OK); */ case BSIM4_CQD: - value->rValue = *(ckt->CKTstate0 + here->BSIM4cqd); + value->rValue = *(ckt->CKTstate0 + here->BSIM4cqd); return(OK); /* case BSIM4_QS: - value->rValue = *(ckt->CKTstate0 + here->BSIM4qs); + value->rValue = *(ckt->CKTstate0 + here->BSIM4qs); return(OK); */ case BSIM4_QB: - value->rValue = here->BSIM4qbulk; - value->rValue *= here->BSIM4m; - return(OK); + value->rValue = here->BSIM4qbulk; + value->rValue *= here->BSIM4mult_q; + return(OK); case BSIM4_QG: - value->rValue = here->BSIM4qgate; - value->rValue *= here->BSIM4m; - return(OK); + value->rValue = here->BSIM4qgate; + value->rValue *= here->BSIM4mult_q; + return(OK); case BSIM4_QS: - value->rValue = here->BSIM4qsrc; - value->rValue *= here->BSIM4m; - return(OK); + value->rValue = here->BSIM4qsrc; + value->rValue *= here->BSIM4mult_q; + return(OK); case BSIM4_QD: - value->rValue = here->BSIM4qdrn; - value->rValue *= here->BSIM4m; - return(OK); + value->rValue = here->BSIM4qdrn; + value->rValue *= here->BSIM4mult_q; + return(OK); + case BSIM4_QINV: + value->rValue = here->BSIM4qinv; + return(OK); case BSIM4_QDEF: - value->rValue = *(ckt->CKTstate0 + here->BSIM4qdef); - return(OK); + value->rValue = *(ckt->CKTstate0 + here->BSIM4qdef); + return(OK); case BSIM4_GCRG: value->rValue = here->BSIM4gcrg; - value->rValue *= here->BSIM4m; + value->rValue *= here->BSIM4mult_i; return(OK); case BSIM4_GTAU: value->rValue = here->BSIM4gtau; - value->rValue *= here->BSIM4m; return(OK); case BSIM4_CGGB: - value->rValue = here->BSIM4cggb; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4cggb; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_CGDB: value->rValue = here->BSIM4cgdb; - value->rValue *= here->BSIM4m; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_CGSB: value->rValue = here->BSIM4cgsb; - value->rValue *= here->BSIM4m; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_CDGB: - value->rValue = here->BSIM4cdgb; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4cdgb; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_CDDB: - value->rValue = here->BSIM4cddb; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4cddb; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_CDSB: - value->rValue = here->BSIM4cdsb; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4cdsb; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_CBGB: value->rValue = here->BSIM4cbgb; - value->rValue *= here->BSIM4m; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_CBDB: value->rValue = here->BSIM4cbdb; - value->rValue *= here->BSIM4m; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_CBSB: value->rValue = here->BSIM4cbsb; - value->rValue *= here->BSIM4m; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_CSGB: value->rValue = here->BSIM4csgb; - value->rValue *= here->BSIM4m; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_CSDB: value->rValue = here->BSIM4csdb; - value->rValue *= here->BSIM4m; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_CSSB: value->rValue = here->BSIM4cssb; - value->rValue *= here->BSIM4m; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_CGBB: value->rValue = here->BSIM4cgbb; - value->rValue *= here->BSIM4m; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_CDBB: value->rValue = here->BSIM4cdbb; - value->rValue *= here->BSIM4m; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_CSBB: value->rValue = here->BSIM4csbb; - value->rValue *= here->BSIM4m; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_CBBB: value->rValue = here->BSIM4cbbb; - value->rValue *= here->BSIM4m; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_CAPBD: - value->rValue = here->BSIM4capbd; - value->rValue *= here->BSIM4m; + value->rValue = here->BSIM4capbd; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_CAPBS: value->rValue = here->BSIM4capbs; - value->rValue *= here->BSIM4m; + value->rValue *= here->BSIM4mult_q; return(OK); case BSIM4_VON: - value->rValue = here->BSIM4von; + value->rValue = here->BSIM4von; return(OK); case BSIM4_VDSAT: - value->rValue = here->BSIM4vdsat; + value->rValue = here->BSIM4vdsat; return(OK); case BSIM4_QBS: - value->rValue = *(ckt->CKTstate0 + here->BSIM4qbs); + value->rValue = *(ckt->CKTstate0 + here->BSIM4qbs); return(OK); case BSIM4_QBD: - value->rValue = *(ckt->CKTstate0 + here->BSIM4qbd); + value->rValue = *(ckt->CKTstate0 + here->BSIM4qbd); return(OK); case BSIM4_VGSTEFF: value->rValue = here->BSIM4Vgsteff; diff --git a/src/spicelib/devices/bsim4/b4check.c b/src/spicelib/devices/bsim4/b4check.c index 111c6a8f9..b3e43ac6e 100644 --- a/src/spicelib/devices/bsim4/b4check.c +++ b/src/spicelib/devices/bsim4/b4check.c @@ -1,29 +1,25 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* Licensed under Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the license at http://opensource.org/licenses/ECL-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc */ #include "ngspice/ngspice.h" @@ -37,21 +33,16 @@ under the License. #include "ngspice/wordlist.h" #include "ngspice/cpextern.h" - - -/* Check for correctness of the BSIM4.8 parameters: - If parameter excursions are found, put the warning or error message into a wordlist. - Only then open a file bsim4.out and print the data into the file. */ int BSIM4checkModel( BSIM4model *model, BSIM4instance *here, CKTcircuit *ckt) { - struct bsim4SizeDependParam *pParam; - int Fatal_Flag = 0; - FILE *fplog; - wordlist* wl, *wlstart; +struct bsim4SizeDependParam *pParam; +int Fatal_Flag = 0; +FILE *fplog; +wordlist* wl, *wlstart; if (cp_getvar("ng_nomodcheck", CP_BOOL, NULL, 0)) return(0); @@ -75,38 +66,42 @@ CKTcircuit *ckt) wl->wl_word = tprintf("\nChecking parameters for BSIM 4.8 model %s\n", model->BSIM4modName); if ((strcmp(model->BSIM4version, "4.8.0")) && (strncmp(model->BSIM4version, "4.80", 4)) && (strncmp(model->BSIM4version, "4.8", 3)) && - (strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4))) + (strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && + (strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4))) { printf("Warning: This model supports BSIM4 version 4.8\n"); - printf("You specified a wrong version number. Working now with BSIM4.8.2\n"); + printf("You specified a wrong version number. Working now with BSIM4.8.3\n"); wl_append_word(&wl, &wl, tprintf("Warning: This model supports BSIM4 version 4.8\n")); - wl_append_word(&wl, &wl, tprintf("You specified a wrong version number. Working now with BSIM4.8.2.\n")); + wl_append_word(&wl, &wl, tprintf("You specified a wrong version number. Working now with BSIM4.8.3.\n")); } if ((here->BSIM4rgateMod == 2) || (here->BSIM4rgateMod == 3)) - { if ((here->BSIM4trnqsMod == 1) || (here->BSIM4acnqsMod == 1)) { + { if ((here->BSIM4trnqsMod == 1) || (here->BSIM4acnqsMod == 1)) + { wl_append_word(&wl, &wl, tprintf("Warning: You've selected both Rg and charge deficit NQS; select one only.\n")); } } if (model->BSIM4toxe <= 0.0) { - wl_append_word(&wl, &wl, tprintf("Fatal: Toxe = %g is not positive.\n", - model->BSIM4toxe)); + wl_append_word(&wl, &wl, tprintf("Fatal: Toxe = %g is not positive.\n", model->BSIM4toxe)); Fatal_Flag = 1; } - - if (model->BSIM4toxp <= 0.0) + if (here->BSIM4toxp <= 0.0) { - wl_append_word(&wl, &wl, tprintf("Fatal: Toxp = %g is not positive.\n", model->BSIM4toxp)); + wl_append_word(&wl, &wl, tprintf("Fatal: Toxp = %g is not positive.\n", here->BSIM4toxp)); Fatal_Flag = 1; } - if (model->BSIM4eot <= 0.0) { wl_append_word(&wl, &wl, tprintf("Fatal: EOT = %g is not positive.\n", model->BSIM4eot)); Fatal_Flag = 1; } + if(model->BSIM4tempeot <= 0.0) + { + wl_append_word(&wl, &wl, tprintf("Fatal: TEMPEOT = %g is not positive.\n", model->BSIM4tempeot)); + Fatal_Flag = 1; + } if (model->BSIM4epsrgate < 0.0) { wl_append_word(&wl, &wl, tprintf("Fatal: Epsrgate = %g is not positive.\n", model->BSIM4epsrgate)); @@ -133,6 +128,7 @@ CKTcircuit *ckt) wl_append_word(&wl, &wl, tprintf("Fatal: Toxm = %g is not positive.\n", model->BSIM4toxm)); Fatal_Flag = 1; } + if (model->BSIM4toxref <= 0.0) { wl_append_word(&wl, &wl, tprintf("Fatal: Toxref = %g is not positive.\n", model->BSIM4toxref)); @@ -142,51 +138,52 @@ CKTcircuit *ckt) if (pParam->BSIM4lpe0 < -pParam->BSIM4leff) { wl_append_word(&wl, &wl, tprintf("Fatal: Lpe0 = %g is less than -Leff.\n", - pParam->BSIM4lpe0)); + pParam->BSIM4lpe0)); Fatal_Flag = 1; } - if (model->BSIM4lintnoi > pParam->BSIM4leff / 2) + if (model->BSIM4lintnoi > pParam->BSIM4leff/2) { wl_append_word(&wl, &wl, tprintf("Fatal: Lintnoi = %g is too large - Leff for noise is negative.\n", - model->BSIM4lintnoi)); + model->BSIM4lintnoi)); Fatal_Flag = 1; } if (pParam->BSIM4lpeb < -pParam->BSIM4leff) { wl_append_word(&wl, &wl, tprintf("Fatal: Lpeb = %g is less than -Leff.\n", - pParam->BSIM4lpeb)); + pParam->BSIM4lpeb)); Fatal_Flag = 1; } if (pParam->BSIM4ndep <= 0.0) { wl_append_word(&wl, &wl, tprintf("Fatal: Ndep = %g is not positive.\n", - pParam->BSIM4ndep)); + pParam->BSIM4ndep)); Fatal_Flag = 1; } if (pParam->BSIM4phi <= 0.0) { wl_append_word(&wl, &wl, tprintf("Fatal: Phi = %g is not positive. Please check Phin and Ndep\n", - pParam->BSIM4phi)); - wl_append_word(&wl, &wl, tprintf(" Phin = %g Ndep = %g \n", - pParam->BSIM4phin, pParam->BSIM4ndep)); + pParam->BSIM4phi)); + wl_append_word(&wl, &wl, tprintf(" Phin = %g Ndep = %g \n", + pParam->BSIM4phin, pParam->BSIM4ndep)); Fatal_Flag = 1; } + if (pParam->BSIM4nsub <= 0.0) { wl_append_word(&wl, &wl, tprintf("Fatal: Nsub = %g is not positive.\n", - pParam->BSIM4nsub)); + pParam->BSIM4nsub)); Fatal_Flag = 1; } if (pParam->BSIM4ngate < 0.0) { wl_append_word(&wl, &wl, tprintf("Fatal: Ngate = %g Ngate is not positive.\n", - pParam->BSIM4ngate)); + pParam->BSIM4ngate)); Fatal_Flag = 1; } if (pParam->BSIM4ngate > 1.e25) { wl_append_word(&wl, &wl, tprintf("Fatal: Ngate = %g Ngate is too high\n", - pParam->BSIM4ngate)); + pParam->BSIM4ngate)); Fatal_Flag = 1; } if (pParam->BSIM4xj <= 0.0) @@ -211,7 +208,7 @@ CKTcircuit *ckt) { wl_append_word(&wl, &wl, tprintf("Fatal: (W0 + Weff) = 0 causing divided-by-zero.\n")); Fatal_Flag = 1; - } + } if (pParam->BSIM4dsub < 0.0) { @@ -226,7 +223,7 @@ CKTcircuit *ckt) if (here->BSIM4u0temp <= 0.0) { wl_append_word(&wl, &wl, tprintf("Fatal: u0 at current temperature = %g is not positive.\n", - here->BSIM4u0temp)); + here->BSIM4u0temp)); Fatal_Flag = 1; } @@ -239,7 +236,7 @@ CKTcircuit *ckt) if (here->BSIM4vsattemp <= 0.0) { wl_append_word(&wl, &wl, tprintf("Fatal: Vsat at current temperature = %g is not positive.\n", - here->BSIM4vsattemp)); + here->BSIM4vsattemp)); Fatal_Flag = 1; } @@ -260,23 +257,23 @@ CKTcircuit *ckt) wl_append_word(&wl, &wl, tprintf("Fatal: multiplier = %g is not positive.\n", here->BSIM4m)); Fatal_Flag = 1; } + if (here->BSIM4nf < 1.0) { wl_append_word(&wl, &wl, tprintf("Fatal: Number of finger = %g is smaller than one.\n", here->BSIM4nf)); Fatal_Flag = 1; } - if ((here->BSIM4sa > 0.0) && (here->BSIM4sb > 0.0) && - ((here->BSIM4nf == 1.0) || ((here->BSIM4nf > 1.0) && (here->BSIM4sd > 0.0)))) - { - if (model->BSIM4saref <= 0.0) + if((here->BSIM4sa > 0.0) && (here->BSIM4sb > 0.0) && + ((here->BSIM4nf == 1.0) || ((here->BSIM4nf > 1.0) && (here->BSIM4sd > 0.0))) ) + { if (model->BSIM4saref <= 0.0) { - wl_append_word(&wl, &wl, tprintf("Fatal: SAref = %g is not positive.\n", model->BSIM4saref)); + wl_append_word(&wl, &wl, tprintf("Fatal: SAref = %g is not positive.\n",model->BSIM4saref)); Fatal_Flag = 1; } if (model->BSIM4sbref <= 0.0) { - wl_append_word(&wl, &wl, tprintf("Fatal: SBref = %g is not positive.\n", model->BSIM4sbref)); + wl_append_word(&wl, &wl, tprintf("Fatal: SBref = %g is not positive.\n",model->BSIM4sbref)); Fatal_Flag = 1; } } @@ -292,8 +289,7 @@ CKTcircuit *ckt) Fatal_Flag = 1; } if ((here->BSIM4ngcon != 1.0) && (here->BSIM4ngcon != 2.0)) - { - here->BSIM4ngcon = 1.0; + { here->BSIM4ngcon = 1.0; wl_append_word(&wl, &wl, tprintf("Warning: Ngcon must be equal to one or two; reset to 1.0.\n")); } @@ -321,40 +317,40 @@ CKTcircuit *ckt) /* Check gate current parameters */ if (model->BSIM4igbMod) { - if (pParam->BSIM4nigbinv <= 0.0) - { - wl_append_word(&wl, &wl, tprintf("Fatal: nigbinv = %g is non-positive.\n", pParam->BSIM4nigbinv)); - Fatal_Flag = 1; - } - if (pParam->BSIM4nigbacc <= 0.0) - { - wl_append_word(&wl, &wl, tprintf("Fatal: nigbacc = %g is non-positive.\n", pParam->BSIM4nigbacc)); - Fatal_Flag = 1; - } + if (pParam->BSIM4nigbinv <= 0.0) + { + wl_append_word(&wl, &wl, tprintf("Fatal: nigbinv = %g is non-positive.\n", pParam->BSIM4nigbinv)); + Fatal_Flag = 1; + } + if (pParam->BSIM4nigbacc <= 0.0) + { + wl_append_word(&wl, &wl, tprintf("Fatal: nigbacc = %g is non-positive.\n", pParam->BSIM4nigbacc)); + Fatal_Flag = 1; + } } if (model->BSIM4igcMod) { - if (pParam->BSIM4nigc <= 0.0) - { - wl_append_word(&wl, &wl, tprintf("Fatal: nigc = %g is non-positive.\n", pParam->BSIM4nigc)); - Fatal_Flag = 1; - } - if (pParam->BSIM4poxedge <= 0.0) - { - wl_append_word(&wl, &wl, tprintf("Fatal: poxedge = %g is non-positive.\n", pParam->BSIM4poxedge)); - Fatal_Flag = 1; - } - if (pParam->BSIM4pigcd <= 0.0) - { - wl_append_word(&wl, &wl, tprintf("Fatal: pigcd = %g is non-positive.\n", pParam->BSIM4pigcd)); - Fatal_Flag = 1; - } + if (pParam->BSIM4nigc <= 0.0) + { + wl_append_word(&wl, &wl, tprintf("Fatal: nigc = %g is non-positive.\n", pParam->BSIM4nigc)); + Fatal_Flag = 1; + } + if (pParam->BSIM4poxedge <= 0.0) + { + wl_append_word(&wl, &wl, tprintf("Fatal: poxedge = %g is non-positive.\n", pParam->BSIM4poxedge)); + Fatal_Flag = 1; + } + if (pParam->BSIM4pigcd <= 0.0) + { + wl_append_word(&wl, &wl, tprintf("Fatal: pigcd = %g is non-positive.\n", pParam->BSIM4pigcd)); + Fatal_Flag = 1; + } } /* Check capacitance parameters */ if (pParam->BSIM4clc < 0.0) { - wl_append_word(&wl, &wl, tprintf("Fatal: Clc = %g is negative.\n", pParam->BSIM4clc)); - Fatal_Flag = 1; + wl_append_word(&wl, &wl, tprintf("Fatal: Clc = %g is negative.\n", pParam->BSIM4clc)); + Fatal_Flag = 1; } /* Check overlap capacitance parameters */ @@ -407,9 +403,9 @@ CKTcircuit *ckt) } - if (model->BSIM4paramChk == 1) + if (model->BSIM4paramChk ==1) { - /* Check L and W parameters */ + /* Check L and W parameters */ if (pParam->BSIM4leff <= 1.0e-9) { wl_append_word(&wl, &wl, tprintf("Warning: Leff = %g <= 1.0e-9. Recommended Leff >= 1e-8 \n", @@ -422,10 +418,10 @@ CKTcircuit *ckt) pParam->BSIM4leffCV)); } - if (pParam->BSIM4weff <= 1.0e-9) + if (pParam->BSIM4weff <= 1.0e-9) { wl_append_word(&wl, &wl, tprintf("Warning: Weff = %g <= 1.0e-9. Recommended Weff >=1e-7 \n", - pParam->BSIM4weff)); + pParam->BSIM4weff)); } if (pParam->BSIM4weffCV <= 1.0e-9) @@ -439,9 +435,9 @@ CKTcircuit *ckt) { wl_append_word(&wl, &wl, tprintf("Warning: Toxe = %g is less than 1A. Recommended Toxe >= 5A\n", model->BSIM4toxe)); } - if (model->BSIM4toxp < 1.0e-10) + if (here->BSIM4toxp < 1.0e-10) { - wl_append_word(&wl, &wl, tprintf("Warning: Toxp = %g is less than 1A. Recommended Toxp >= 5A\n", model->BSIM4toxp)); + wl_append_word(&wl, &wl, tprintf("Warning: Toxp = %g is less than 1A. Recommended Toxp >= 5A\n", here->BSIM4toxp)); } if (model->BSIM4toxm < 1.0e-10) { @@ -451,33 +447,33 @@ CKTcircuit *ckt) if (pParam->BSIM4ndep <= 1.0e12) { wl_append_word(&wl, &wl, tprintf("Warning: Ndep = %g may be too small.\n", - pParam->BSIM4ndep)); + pParam->BSIM4ndep)); } else if (pParam->BSIM4ndep >= 1.0e21) { wl_append_word(&wl, &wl, tprintf("Warning: Ndep = %g may be too large.\n", - pParam->BSIM4ndep)); + pParam->BSIM4ndep)); } if (pParam->BSIM4nsub <= 1.0e14) { wl_append_word(&wl, &wl, tprintf("Warning: Nsub = %g may be too small.\n", - pParam->BSIM4nsub)); + pParam->BSIM4nsub)); } else if (pParam->BSIM4nsub >= 1.0e21) { wl_append_word(&wl, &wl, tprintf("Warning: Nsub = %g may be too large.\n", - pParam->BSIM4nsub)); + pParam->BSIM4nsub)); } if ((pParam->BSIM4ngate > 0.0) && (pParam->BSIM4ngate <= 1.e18)) { wl_append_word(&wl, &wl, tprintf("Warning: Ngate = %g is less than 1.E18cm^-3.\n", - pParam->BSIM4ngate)); + pParam->BSIM4ngate)); } - if (pParam->BSIM4dvt0 < 0.0) + if (pParam->BSIM4dvt0 < 0.0) { wl_append_word(&wl, &wl, tprintf("Warning: Dvt0 = %g is negative.\n", pParam->BSIM4dvt0)); } @@ -485,9 +481,9 @@ CKTcircuit *ckt) if (fabs(1.0e-8 / (pParam->BSIM4w0 + pParam->BSIM4weff)) > 10.0) { wl_append_word(&wl, &wl, tprintf("Warning: (W0 + Weff) may be too small.\n")); - } + } - /* Check subthreshold parameters */ + /* Check subthreshold parameters */ if (pParam->BSIM4nfactor < 0.0) { wl_append_word(&wl, &wl, tprintf("Warning: Nfactor = %g is negative.\n", pParam->BSIM4nfactor)); @@ -500,7 +496,7 @@ CKTcircuit *ckt) { wl_append_word(&wl, &wl, tprintf("Warning: Cdscd = %g is negative.\n", pParam->BSIM4cdscd)); } - /* Check DIBL parameters */ + /* Check DIBL parameters */ if (here->BSIM4eta0 < 0.0) { wl_append_word(&wl, &wl, tprintf("Warning: Eta0 = %g is negative.\n", here->BSIM4eta0)); @@ -510,24 +506,24 @@ CKTcircuit *ckt) { wl_append_word(&wl, &wl, tprintf("Warning: gidlclamp = %g is zero or positive.\n", model->BSIM4gidlclamp)); } - /* Check Abulk parameters */ + /* Check Abulk parameters */ if (fabs(1.0e-8 / (pParam->BSIM4b1 + pParam->BSIM4weff)) > 10.0) { wl_append_word(&wl, &wl, tprintf("Warning: (B1 + Weff) may be too small.\n")); } - /* Check Saturation parameters */ + /* Check Saturation parameters */ if (pParam->BSIM4a2 < 0.01) { wl_append_word(&wl, &wl, tprintf("Warning: A2 = %g is too small. Set to 0.01.\n", - pParam->BSIM4a2)); + pParam->BSIM4a2)); pParam->BSIM4a2 = 0.01; } else if (pParam->BSIM4a2 > 1.0) { wl_append_word(&wl, &wl, tprintf("Warning: A2 = %g is larger than 1. A2 is set to 1 and A1 is set to 0.\n", - pParam->BSIM4a2)); + pParam->BSIM4a2)); pParam->BSIM4a2 = 1.0; pParam->BSIM4a1 = 0.0; } @@ -535,14 +531,14 @@ CKTcircuit *ckt) if (pParam->BSIM4prwg < 0.0) { wl_append_word(&wl, &wl, tprintf("Warning: Prwg = %g is negative. Set to zero.\n", - pParam->BSIM4prwg)); + pParam->BSIM4prwg)); pParam->BSIM4prwg = 0.0; } if (pParam->BSIM4rdsw < 0.0) { wl_append_word(&wl, &wl, tprintf("Warning: Rdsw = %g is negative. Set to zero.\n", - pParam->BSIM4rdsw)); + pParam->BSIM4rdsw)); pParam->BSIM4rdsw = 0.0; pParam->BSIM4rds0 = 0.0; } @@ -550,14 +546,14 @@ CKTcircuit *ckt) if (pParam->BSIM4rds0 < 0.0) { wl_append_word(&wl, &wl, tprintf("Warning: Rds at current temperature = %g is negative. Set to zero.\n", - pParam->BSIM4rds0)); + pParam->BSIM4rds0)); pParam->BSIM4rds0 = 0.0; } if (pParam->BSIM4rdswmin < 0.0) { wl_append_word(&wl, &wl, tprintf("Warning: Rdswmin at current temperature = %g is negative. Set to zero.\n", - pParam->BSIM4rdswmin)); + pParam->BSIM4rdswmin)); pParam->BSIM4rdswmin = 0.0; } @@ -568,22 +564,22 @@ CKTcircuit *ckt) if (pParam->BSIM4vsattemp < 1.0e3) { - wl_append_word(&wl, &wl, tprintf("Warning: Vsat at current temperature = %g may be too small.\n", pParam->BSIM4vsattemp)); + wl_append_word(&wl, &wl, tprintf("Warning: Vsat at current temperature = %g may be too small.\n", pParam->BSIM4vsattemp)); } - if ((model->BSIM4lambdaGiven) && (pParam->BSIM4lambda > 0.0)) + if((model->BSIM4lambdaGiven) && (pParam->BSIM4lambda > 0.0) ) { if (pParam->BSIM4lambda > 1.0e-9) { - wl_append_word(&wl, &wl, tprintf("Warning: Lambda = %g may be too large.\n", pParam->BSIM4lambda)); + wl_append_word(&wl, &wl, tprintf("Warning: Lambda = %g may be too large.\n", pParam->BSIM4lambda)); } } - if ((model->BSIM4vtlGiven) && (pParam->BSIM4vtl > 0.0)) + if((model->BSIM4vtlGiven) && (pParam->BSIM4vtl > 0.0) ) { if (pParam->BSIM4vtl < 6.0e4) { - wl_append_word(&wl, &wl, tprintf("Warning: Thermal velocity vtl = %g may be too small.\n", pParam->BSIM4vtl)); + wl_append_word(&wl, &wl, tprintf("Warning: Thermal velocity vtl = %g may be too small.\n", pParam->BSIM4vtl)); } if (pParam->BSIM4xn < 3.0) @@ -603,305 +599,316 @@ CKTcircuit *ckt) { wl_append_word(&wl, &wl, tprintf("Warning: Pdibl1 = %g is negative.\n", pParam->BSIM4pdibl1)); } - } - - if (pParam->BSIM4pdibl2 < 0.0) - { - wl_append_word(&wl, &wl, tprintf("Warning: Pdibl2 = %g is negative.\n", pParam->BSIM4pdibl2)); - } - - /* Check stress effect parameters */ - if ((here->BSIM4sa > 0.0) && (here->BSIM4sb > 0.0) && - ((here->BSIM4nf == 1.0) || ((here->BSIM4nf > 1.0) && (here->BSIM4sd > 0.0)))) - { - if (model->BSIM4lodk2 <= 0.0) + if (pParam->BSIM4pdibl2 < 0.0) { - wl_append_word(&wl, &wl, tprintf("Warning: LODK2 = %g is not positive.\n", model->BSIM4lodk2)); + wl_append_word(&wl, &wl, tprintf("Warning: Pdibl2 = %g is negative.\n", pParam->BSIM4pdibl2)); } - if (model->BSIM4lodeta0 <= 0.0) - { - wl_append_word(&wl, &wl, tprintf("Warning: LODETA0 = %g is not positive.\n", model->BSIM4lodeta0)); - } - } -/* Check gate resistance parameters */ - if (here->BSIM4rgateMod == 1) - { if (model->BSIM4rshg <= 0.0) - wl_append_word(&wl, &wl, tprintf("Warning: rshg should be positive for rgateMod = 1.\n")); - } - else if (here->BSIM4rgateMod == 2) - { if (model->BSIM4rshg <= 0.0) - wl_append_word(&wl, &wl, tprintf("Warning: rshg <= 0.0 for rgateMod = 2.\n")); - else if (pParam->BSIM4xrcrg1 <= 0.0) - wl_append_word(&wl, &wl, tprintf("Warning: xrcrg1 <= 0.0 for rgateMod = 2.\n")); - } - if (here->BSIM4rgateMod == 3) - { if (model->BSIM4rshg <= 0.0) - wl_append_word(&wl, &wl, tprintf("Warning: rshg should be positive for rgateMod = 3.\n")); - else if (pParam->BSIM4xrcrg1 <= 0.0) - wl_append_word(&wl, &wl, tprintf("Warning: xrcrg1 should be positive for rgateMod = 3.\n")); - } - - /* Check body resistance parameters */ - if (model->BSIM4rbps0 <= 0.0) - { wl_append_word(&wl, &wl, tprintf("Fatal: RBPS0 = %g is not positive.\n", model->BSIM4rbps0)); - Fatal_Flag = 1; - } - if (model->BSIM4rbpd0 <= 0.0) - { wl_append_word(&wl, &wl, tprintf("Fatal: RBPD0 = %g is not positive.\n", model->BSIM4rbpd0)); - Fatal_Flag = 1; - } - if (model->BSIM4rbpbx0 <= 0.0) - { wl_append_word(&wl, &wl, tprintf("Fatal: RBPBX0 = %g is not positive.\n", model->BSIM4rbpbx0)); - Fatal_Flag = 1; - } - if (model->BSIM4rbpby0 <= 0.0) - { wl_append_word(&wl, &wl, tprintf("Fatal: RBPBY0 = %g is not positive.\n", model->BSIM4rbpby0)); - Fatal_Flag = 1; - } - if (model->BSIM4rbdbx0 <= 0.0) - { wl_append_word(&wl, &wl, tprintf("Fatal: RBDBX0 = %g is not positive.\n", model->BSIM4rbdbx0)); - Fatal_Flag = 1; - } - if (model->BSIM4rbdby0 <= 0.0) - { wl_append_word(&wl, &wl, tprintf("Fatal: RBDBY0 = %g is not positive.\n", model->BSIM4rbdby0)); - Fatal_Flag = 1; - } - if (model->BSIM4rbsbx0 <= 0.0) - { wl_append_word(&wl, &wl, tprintf("Fatal: RBSBX0 = %g is not positive.\n", model->BSIM4rbsbx0)); - Fatal_Flag = 1; - } - if (model->BSIM4rbsby0 <= 0.0) - { wl_append_word(&wl, &wl, tprintf("Fatal: RBSBY0 = %g is not positive.\n", model->BSIM4rbsby0)); - Fatal_Flag = 1; - } - - /* Check capacitance parameters */ - if (pParam->BSIM4noff < 0.1) - { - wl_append_word(&wl, &wl, tprintf("Warning: Noff = %g is too small.\n", pParam->BSIM4noff)); - } - - if (pParam->BSIM4voffcv < -0.5) - { - wl_append_word(&wl, &wl, tprintf("Warning: Voffcv = %g is too small.\n", pParam->BSIM4voffcv)); - } - - if (pParam->BSIM4moin < 5.0) - { - wl_append_word(&wl, &wl, tprintf("Warning: Moin = %g is too small.\n", pParam->BSIM4moin)); - } - if (pParam->BSIM4moin > 25.0) - { - wl_append_word(&wl, &wl, tprintf("Warning: Moin = %g is too large.\n", pParam->BSIM4moin)); - } - if (model->BSIM4capMod == 2) { - if (pParam->BSIM4acde < 0.1) - { - wl_append_word(&wl, &wl, tprintf("Warning: Acde = %g is too small.\n", pParam->BSIM4acde)); - } - if (pParam->BSIM4acde > 1.6) - { - wl_append_word(&wl, &wl, tprintf("Warning: Acde = %g is too large.\n", pParam->BSIM4acde)); - } - } - - /* Check overlap capacitance parameters */ - if (model->BSIM4cgdo < 0.0) - { - wl_append_word(&wl, &wl, tprintf("Warning: cgdo = %g is negative. Set to zero.\n", model->BSIM4cgdo)); - model->BSIM4cgdo = 0.0; - } - if (model->BSIM4cgso < 0.0) - { - wl_append_word(&wl, &wl, tprintf("Warning: cgso = %g is negative. Set to zero.\n", model->BSIM4cgso)); - model->BSIM4cgso = 0.0; - } - if (model->BSIM4cgbo < 0.0) - { - wl_append_word(&wl, &wl, tprintf("Warning: cgbo = %g is negative. Set to zero.\n", model->BSIM4cgbo)); - model->BSIM4cgbo = 0.0; - } - if (model->BSIM4tnoiMod == 1){ - wl_append_word(&wl, &wl, tprintf("Warning: TNOIMOD=1 is not supported and may be removed from future version.\n")); - } - if (model->BSIM4idovvdsc <= 0.0) - { - wl_append_word(&wl, &wl, tprintf("Warning: idovvdsc = %g is zero or negative.\n", model->BSIM4idovvdsc)); - } - - 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))) - { /* checking for version <= 4.8 */ - /* v4.7 */ - if (model->BSIM4tnoiMod == 1 || model->BSIM4tnoiMod == 2) { - if (model->BSIM4tnoia < 0.0) + /* Check stress effect parameters */ + if((here->BSIM4sa > 0.0) && (here->BSIM4sb > 0.0) && + ((here->BSIM4nf == 1.0) || ((here->BSIM4nf > 1.0) && (here->BSIM4sd > 0.0))) ) + { if (model->BSIM4lodk2 <= 0.0) { + wl_append_word(&wl, &wl, tprintf("Warning: LODK2 = %g is not positive.\n",model->BSIM4lodk2)); + } + if (model->BSIM4lodeta0 <= 0.0) + { + wl_append_word(&wl, &wl, tprintf("Warning: LODETA0 = %g is not positive.\n",model->BSIM4lodeta0)); + } + } + + /* Check gate resistance parameters */ + if (here->BSIM4rgateMod == 1) + { if (model->BSIM4rshg <= 0.0) + wl_append_word(&wl, &wl, tprintf("Warning: rshg should be positive for rgateMod = 1.\n")); + } + else if (here->BSIM4rgateMod == 2) + { if (model->BSIM4rshg <= 0.0) + wl_append_word(&wl, &wl, tprintf("Warning: rshg <= 0.0 for rgateMod = 2.\n")); + else if (pParam->BSIM4xrcrg1 <= 0.0) + wl_append_word(&wl, &wl, tprintf("Warning: xrcrg1 <= 0.0 for rgateMod = 2.\n")); + } + if (here->BSIM4rgateMod == 3) + { if (model->BSIM4rshg <= 0.0) + wl_append_word(&wl, &wl, tprintf("Warning: rshg should be positive for rgateMod = 3.\n")); + else if (pParam->BSIM4xrcrg1 <= 0.0) + wl_append_word(&wl, &wl, tprintf("Warning: xrcrg1 should be positive for rgateMod = 3.\n")); + } + + /* Check body resistance parameters */ + + if (model->BSIM4rbps0 <= 0.0) + { + wl_append_word(&wl, &wl, tprintf("Fatal: RBPS0 = %g is not positive.\n", model->BSIM4rbps0)); + Fatal_Flag = 1; + } + if (model->BSIM4rbpd0 <= 0.0) + { + wl_append_word(&wl, &wl, tprintf("Fatal: RBPD0 = %g is not positive.\n", model->BSIM4rbpd0)); + Fatal_Flag = 1; + } + if (model->BSIM4rbpbx0 <= 0.0) + { + wl_append_word(&wl, &wl, tprintf("Fatal: RBPBX0 = %g is not positive.\n", model->BSIM4rbpbx0)); + Fatal_Flag = 1; + } + if (model->BSIM4rbpby0 <= 0.0) + { + wl_append_word(&wl, &wl, tprintf("Fatal: RBPBY0 = %g is not positive.\n", model->BSIM4rbpby0)); + Fatal_Flag = 1; + } + if (model->BSIM4rbdbx0 <= 0.0) + { + wl_append_word(&wl, &wl, tprintf("Fatal: RBDBX0 = %g is not positive.\n", model->BSIM4rbdbx0)); + Fatal_Flag = 1; + } + if (model->BSIM4rbdby0 <= 0.0) + { + wl_append_word(&wl, &wl, tprintf("Fatal: RBDBY0 = %g is not positive.\n", model->BSIM4rbdby0)); + Fatal_Flag = 1; + } + if (model->BSIM4rbsbx0 <= 0.0) + { + wl_append_word(&wl, &wl, tprintf("Fatal: RBSBX0 = %g is not positive.\n", model->BSIM4rbsbx0)); + Fatal_Flag = 1; + } + if (model->BSIM4rbsby0 <= 0.0) + { + wl_append_word(&wl, &wl, tprintf("Fatal: RBSBY0 = %g is not positive.\n", model->BSIM4rbsby0)); + Fatal_Flag = 1; + } + + /* Check capacitance parameters */ + if (pParam->BSIM4noff < 0.1) + { + wl_append_word(&wl, &wl, tprintf("Warning: Noff = %g is too small.\n", pParam->BSIM4noff)); + } + + if (pParam->BSIM4voffcv < -0.5) + { + wl_append_word(&wl, &wl, tprintf("Warning: Voffcv = %g is too small.\n", pParam->BSIM4voffcv)); + } + if (pParam->BSIM4moin < 5.0) + { + wl_append_word(&wl, &wl, tprintf("Warning: Moin = %g is too small.\n", pParam->BSIM4moin)); + } + if (pParam->BSIM4moin > 25.0) + { + wl_append_word(&wl, &wl, tprintf("Warning: Moin = %g is too large.\n", pParam->BSIM4moin)); + } + if(model->BSIM4capMod ==2) { + if (pParam->BSIM4acde < 0.1) + { + wl_append_word(&wl, &wl, tprintf("Warning: Acde = %g is too small.\n", pParam->BSIM4acde)); + } + if (pParam->BSIM4acde > 1.6) + { + wl_append_word(&wl, &wl, tprintf("Warning: Acde = %g is too large.\n", pParam->BSIM4acde)); + } + } + + /* Check overlap capacitance parameters */ + if (model->BSIM4cgdo < 0.0) + { + wl_append_word(&wl, &wl, tprintf("Warning: cgdo = %g is negative. Set to zero.\n", model->BSIM4cgdo)); + model->BSIM4cgdo = 0.0; + } + if (model->BSIM4cgso < 0.0) + { + wl_append_word(&wl, &wl, tprintf("Warning: cgso = %g is negative. Set to zero.\n", model->BSIM4cgso)); + model->BSIM4cgso = 0.0; + } + if (model->BSIM4cgbo < 0.0) + { + wl_append_word(&wl, &wl, tprintf("Warning: cgbo = %g is negative. Set to zero.\n", model->BSIM4cgbo)); + model->BSIM4cgbo = 0.0; + } + if (model->BSIM4tnoiMod == 1){ + wl_append_word(&wl, &wl, tprintf("Warning: TNOIMOD=%d is not supported and may be removed from future version.\n", model->BSIM4tnoiMod)); + } + if (model->BSIM4idovvdsc <= 0.0) + { + wl_append_word(&wl, &wl, tprintf("Warning: idovvdsc = %g is zero or negative.\n", model->BSIM4idovvdsc)); + } + 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))) + { + /* v4.7 */ + if (model->BSIM4tnoiMod == 1 || model->BSIM4tnoiMod == 2) { + if (model->BSIM4tnoia < 0.0) { wl_append_word(&wl, &wl, tprintf("Warning: tnoia = %g is negative. Set to zero.\n", model->BSIM4tnoia)); model->BSIM4tnoia = 0.0; - } - if (model->BSIM4tnoib < 0.0) - { + } + if (model->BSIM4tnoib < 0.0) { wl_append_word(&wl, &wl, tprintf("Warning: tnoib = %g is negative. Set to zero.\n", model->BSIM4tnoib)); model->BSIM4tnoib = 0.0; - } - - if (model->BSIM4rnoia < 0.0) - { + } + if (model->BSIM4rnoia < 0.0) { wl_append_word(&wl, &wl, tprintf("Warning: rnoia = %g is negative. Set to zero.\n", model->BSIM4rnoia)); model->BSIM4rnoia = 0.0; - } - if (model->BSIM4rnoib < 0.0) - { + } + if (model->BSIM4rnoib < 0.0) { wl_append_word(&wl, &wl, tprintf("Warning: rnoib = %g is negative. Set to zero.\n", model->BSIM4rnoib)); model->BSIM4rnoib = 0.0; + } } - } - /* v4.7 */ - if (model->BSIM4tnoiMod == 2) { - if (model->BSIM4tnoic < 0.0) { + /* v4.7 */ + if (model->BSIM4tnoiMod == 2) { + if (model->BSIM4tnoic < 0.0) { + wl_append_word(&wl, &wl, tprintf("Warning: tnoic = %g is negative. Set to zero.\n", model->BSIM4tnoic)); model->BSIM4tnoic = 0.0; - } - if (model->BSIM4rnoic < 0.0) { + } + if (model->BSIM4rnoic < 0.0) { + wl_append_word(&wl, &wl, tprintf("Warning: rnoic = %g is negative. Set to zero.\n", model->BSIM4rnoic)); model->BSIM4rnoic = 0.0; + } } } - } - else - { - if (model->BSIM4tnoiMod == 1){ - if (model->BSIM4tnoia < 0.0) { - wl_append_word(&wl, &wl, tprintf("Warning: tnoia = %g is negative. Set to zero.\n", model->BSIM4tnoia)); - model->BSIM4tnoia = 0.0; - } - if (model->BSIM4tnoib < 0.0) { - wl_append_word(&wl, &wl, tprintf("Warning: tnoib = %g is negative. Set to zero.\n", model->BSIM4tnoib)); - model->BSIM4tnoib = 0.0; - } - if (model->BSIM4rnoia < 0.0) { - wl_append_word(&wl, &wl, tprintf("Warning: rnoia = %g is negative. Set to zero.\n", model->BSIM4rnoia)); - model->BSIM4rnoia = 0.0; - } - if (model->BSIM4rnoib < 0.0) { - wl_append_word(&wl, &wl, tprintf("Warning: rnoib = %g is negative. Set to zero.\n", model->BSIM4rnoib)); - model->BSIM4rnoib = 0.0; - } - } - } + else + { + if (model->BSIM4tnoiMod == 1){ + if (model->BSIM4tnoia < 0.0) { - /* Limits of Njs and Njd modified in BSIM4.7 */ - if (model->BSIM4SjctEmissionCoeff < 0.1) { - wl_append_word(&wl, &wl, tprintf("Warning: Njs = %g is less than 0.1. Setting Njs to 0.1.\n", model->BSIM4SjctEmissionCoeff)); + wl_append_word(&wl, &wl, tprintf("Warning: tnoia = %g is negative. Set to zero.\n", model->BSIM4tnoia)); + model->BSIM4tnoia = 0.0; + } + if (model->BSIM4tnoib < 0.0) { + + wl_append_word(&wl, &wl, tprintf("Warning: tnoib = %g is negative. Set to zero.\n", model->BSIM4tnoib)); + model->BSIM4tnoib = 0.0; + } + if (model->BSIM4rnoia < 0.0) { + + wl_append_word(&wl, &wl, tprintf("Warning: rnoia = %g is negative. Set to zero.\n", model->BSIM4rnoia)); + model->BSIM4rnoia = 0.0; + } + if (model->BSIM4rnoib < 0.0) { + + wl_append_word(&wl, &wl, tprintf("Warning: rnoib = %g is negative. Set to zero.\n", model->BSIM4rnoib)); + model->BSIM4rnoib = 0.0; + } + } + } + /* Limits of Njs and Njd modified in BSIM4.7 */ + if (model->BSIM4SjctEmissionCoeff < 0.1) { + wl_append_word(&wl, &wl, tprintf("Warning: Njs = %g is less than 0.1. Setting Njs to 0.1.\n", model->BSIM4SjctEmissionCoeff)); model->BSIM4SjctEmissionCoeff = 0.1; - } - else if (model->BSIM4SjctEmissionCoeff < 0.7) { - wl_append_word(&wl, &wl, tprintf("Warning: Njs = %g is less than 0.7.\n", model->BSIM4SjctEmissionCoeff)); - } - if (model->BSIM4DjctEmissionCoeff < 0.1) - { - wl_append_word(&wl, &wl, tprintf("Warning: Njd = %g is less than 0.1. Setting Njd to 0.1.\n", model->BSIM4DjctEmissionCoeff)); - model->BSIM4DjctEmissionCoeff = 0.1; - } - else if (model->BSIM4DjctEmissionCoeff < 0.7) { - wl_append_word(&wl, &wl, tprintf("Warning: Njd = %g is less than 0.7.\n", model->BSIM4DjctEmissionCoeff)); - } + } + else if (model->BSIM4SjctEmissionCoeff < 0.7) { + wl_append_word(&wl, &wl, tprintf("Warning: Njs = %g is less than 0.7.\n", model->BSIM4SjctEmissionCoeff)); + } + if (model->BSIM4DjctEmissionCoeff < 0.1) { + wl_append_word(&wl, &wl, tprintf("Warning: Njd = %g is less than 0.1. Setting Njd to 0.1.\n", model->BSIM4DjctEmissionCoeff)); + model->BSIM4DjctEmissionCoeff = 0.1; + } + else if (model->BSIM4DjctEmissionCoeff < 0.7) { + wl_append_word(&wl, &wl, tprintf("Warning: Njd = %g is less than 0.7.\n", model->BSIM4DjctEmissionCoeff)); + } - if (model->BSIM4njtsstemp < 0.0) { - wl_append_word(&wl, &wl, tprintf("Warning: Njts = %g is negative at temperature = %g.\n", - model->BSIM4njtsstemp, ckt->CKTtemp)); - } - if (model->BSIM4njtsswstemp < 0.0) { - wl_append_word(&wl, &wl, tprintf("Warning: Njtssw = %g is negative at temperature = %g.\n", + if (model->BSIM4njtsstemp < 0.0) + { + wl_append_word(&wl, &wl, tprintf("Warning: Njts = %g is negative at temperature = %g.\n", + model->BSIM4njtsstemp, ckt->CKTtemp)); + } + if (model->BSIM4njtsswstemp < 0.0) + { + wl_append_word(&wl, &wl, tprintf("Warning: Njtssw = %g is negative at temperature = %g.\n", model->BSIM4njtsswstemp, ckt->CKTtemp)); - } - if (model->BSIM4njtsswgstemp < 0.0) { - wl_append_word(&wl, &wl, tprintf("Warning: Njtsswg = %g is negative at temperature = %g.\n", + } + if (model->BSIM4njtsswgstemp < 0.0) + { + wl_append_word(&wl, &wl, tprintf("Warning: Njtsswg = %g is negative at temperature = %g.\n", model->BSIM4njtsswgstemp, ckt->CKTtemp)); - } - - if (model->BSIM4njtsdGiven && model->BSIM4njtsdtemp < 0.0) - { - wl_append_word(&wl, &wl, tprintf("Warning: Njtsd = %g is negative at temperature = %g.\n", - model->BSIM4njtsdtemp, ckt->CKTtemp)); - } - if (model->BSIM4njtsswdGiven && model->BSIM4njtsswdtemp < 0.0) - { - wl_append_word(&wl, &wl, tprintf("Warning: Njtsswd = %g is negative at temperature = %g.\n", - model->BSIM4njtsswdtemp, ckt->CKTtemp)); - } - if (model->BSIM4njtsswgdGiven && model->BSIM4njtsswgdtemp < 0.0) - { - wl_append_word(&wl, &wl, tprintf("Warning: Njtsswgd = %g is negative at temperature = %g.\n", - model->BSIM4njtsswgdtemp, ckt->CKTtemp)); - } - - if (model->BSIM4ntnoi < 0.0) - { - wl_append_word(&wl, &wl, tprintf("Warning: ntnoi = %g is negative. Set to zero.\n", model->BSIM4ntnoi)); - model->BSIM4ntnoi = 0.0; - } - - /* diode model */ - if (model->BSIM4SbulkJctBotGradingCoeff >= 0.99) - { - wl_append_word(&wl, &wl, tprintf("Warning: MJS = %g is too big. Set to 0.99.\n", model->BSIM4SbulkJctBotGradingCoeff)); - model->BSIM4SbulkJctBotGradingCoeff = 0.99; - } - if (model->BSIM4SbulkJctSideGradingCoeff >= 0.99) - { - wl_append_word(&wl, &wl, tprintf("Warning: MJSWS = %g is too big. Set to 0.99.\n", model->BSIM4SbulkJctSideGradingCoeff)); - model->BSIM4SbulkJctSideGradingCoeff = 0.99; - } - if (model->BSIM4SbulkJctGateSideGradingCoeff >= 0.99) - { - wl_append_word(&wl, &wl, tprintf("Warning: MJSWGS = %g is too big. Set to 0.99.\n", model->BSIM4SbulkJctGateSideGradingCoeff)); - model->BSIM4SbulkJctGateSideGradingCoeff = 0.99; - } - - if (model->BSIM4DbulkJctBotGradingCoeff >= 0.99) - { - wl_append_word(&wl, &wl, tprintf("Warning: MJD = %g is too big. Set to 0.99.\n", model->BSIM4DbulkJctBotGradingCoeff)); - model->BSIM4DbulkJctBotGradingCoeff = 0.99; - } - if (model->BSIM4DbulkJctSideGradingCoeff >= 0.99) - { - wl_append_word(&wl, &wl, tprintf("Warning: MJSWD = %g is too big. Set to 0.99.\n", model->BSIM4DbulkJctSideGradingCoeff)); - model->BSIM4DbulkJctSideGradingCoeff = 0.99; - } - if (model->BSIM4DbulkJctGateSideGradingCoeff >= 0.99) - { - wl_append_word(&wl, &wl, tprintf("Warning: MJSWGD = %g is too big. Set to 0.99.\n", model->BSIM4DbulkJctGateSideGradingCoeff)); - model->BSIM4DbulkJctGateSideGradingCoeff = 0.99; - } - if (model->BSIM4wpemod == 1) - { - if (model->BSIM4scref <= 0.0) - { - wl_append_word(&wl, &wl, tprintf("Warning: SCREF = %g is not positive. Set to 1e-6.\n", model->BSIM4scref)); - model->BSIM4scref = 1e-6; } - if (here->BSIM4sca < 0.0) + + if (model->BSIM4njtsdGiven && model->BSIM4njtsdtemp < 0.0) { - wl_append_word(&wl, &wl, tprintf("Warning: SCA = %g is negative. Set to 0.0.\n", here->BSIM4sca)); - here->BSIM4sca = 0.0; + wl_append_word(&wl, &wl, tprintf("Warning: Njtsd = %g is negative at temperature = %g.\n", + model->BSIM4njtsdtemp, ckt->CKTtemp)); } - if (here->BSIM4scb < 0.0) + if (model->BSIM4njtsswdGiven && model->BSIM4njtsswdtemp < 0.0) { - wl_append_word(&wl, &wl, tprintf("Warning: SCB = %g is negative. Set to 0.0.\n", here->BSIM4scb)); - here->BSIM4scb = 0.0; + wl_append_word(&wl, &wl, tprintf("Warning: Njtsswd = %g is negative at temperature = %g.\n", + model->BSIM4njtsswdtemp, ckt->CKTtemp)); } - if (here->BSIM4scc < 0.0) + if (model->BSIM4njtsswgdGiven && model->BSIM4njtsswgdtemp < 0.0) { - wl_append_word(&wl, &wl, tprintf("Warning: SCC = %g is negative. Set to 0.0.\n", here->BSIM4scc)); - here->BSIM4scc = 0.0; + wl_append_word(&wl, &wl, tprintf("Warning: Njtsswgd = %g is negative at temperature = %g.\n", + model->BSIM4njtsswgdtemp, ckt->CKTtemp)); } - if (here->BSIM4sc < 0.0) + + if (model->BSIM4ntnoi < 0.0) { - wl_append_word(&wl, &wl, tprintf("Warning: SC = %g is negative. Set to 0.0.\n", here->BSIM4sc)); - here->BSIM4sc = 0.0; + wl_append_word(&wl, &wl, tprintf("Warning: ntnoi = %g is negative. Set to zero.\n", model->BSIM4ntnoi)); + model->BSIM4ntnoi = 0.0; + } + + /* diode model */ + if (model->BSIM4SbulkJctBotGradingCoeff >= 0.99) + { + wl_append_word(&wl, &wl, tprintf("Warning: MJS = %g is too big. Set to 0.99.\n", model->BSIM4SbulkJctBotGradingCoeff)); + model->BSIM4SbulkJctBotGradingCoeff = 0.99; + } + if (model->BSIM4SbulkJctSideGradingCoeff >= 0.99) + { + wl_append_word(&wl, &wl, tprintf("Warning: MJSWS = %g is too big. Set to 0.99.\n", model->BSIM4SbulkJctSideGradingCoeff)); + model->BSIM4SbulkJctSideGradingCoeff = 0.99; + } + if (model->BSIM4SbulkJctGateSideGradingCoeff >= 0.99) + { + wl_append_word(&wl, &wl, tprintf("Warning: MJSWGS = %g is too big. Set to 0.99.\n", model->BSIM4SbulkJctGateSideGradingCoeff)); + model->BSIM4SbulkJctGateSideGradingCoeff = 0.99; + } + + if (model->BSIM4DbulkJctBotGradingCoeff >= 0.99) + { + wl_append_word(&wl, &wl, tprintf("Warning: MJD = %g is too big. Set to 0.99.\n", model->BSIM4DbulkJctBotGradingCoeff)); + model->BSIM4DbulkJctBotGradingCoeff = 0.99; + } + if (model->BSIM4DbulkJctSideGradingCoeff >= 0.99) + { + wl_append_word(&wl, &wl, tprintf("Warning: MJSWD = %g is too big. Set to 0.99.\n", model->BSIM4DbulkJctSideGradingCoeff)); + model->BSIM4DbulkJctSideGradingCoeff = 0.99; + } + if (model->BSIM4DbulkJctGateSideGradingCoeff >= 0.99) + { + wl_append_word(&wl, &wl, tprintf("Warning: MJSWGD = %g is too big. Set to 0.99.\n", model->BSIM4DbulkJctGateSideGradingCoeff)); + model->BSIM4DbulkJctGateSideGradingCoeff = 0.99; + } + if (model->BSIM4wpemod == 1) + { + if (model->BSIM4scref <= 0.0) + { + wl_append_word(&wl, &wl, tprintf("Warning: SCREF = %g is not positive. Set to 1e-6.\n", model->BSIM4scref)); + model->BSIM4scref = 1e-6; + } + /*Move these checks to temp.c for sceff calculation*/ + /* + if (here->BSIM4sca < 0.0) + { + wl_append_word(&wl, &wl, tprintf("Warning: SCA = %g is negative. Set to 0.0.\n", here->BSIM4sca); + here->BSIM4sca = 0.0; + } + if (here->BSIM4scb < 0.0) + { + wl_append_word(&wl, &wl, tprintf("Warning: SCB = %g is negative. Set to 0.0.\n", here->BSIM4scb); + here->BSIM4scb = 0.0; + } + if (here->BSIM4scc < 0.0) + { + wl_append_word(&wl, &wl, tprintf("Warning: SCC = %g is negative. Set to 0.0.\n", here->BSIM4scc); + here->BSIM4scc = 0.0; + } + if (here->BSIM4sc < 0.0) + { + wl_append_word(&wl, &wl, tprintf("Warning: SC = %g is negative. Set to 0.0.\n", here->BSIM4sc); + here->BSIM4sc = 0.0; + } + */ } } @@ -923,7 +930,6 @@ CKTcircuit *ckt) } wl_free(wlstart); - return(Fatal_Flag); } diff --git a/src/spicelib/devices/bsim4/b4cvtest.c b/src/spicelib/devices/bsim4/b4cvtest.c index 1b31adc64..7ca6856d7 100644 --- a/src/spicelib/devices/bsim4/b4cvtest.c +++ b/src/spicelib/devices/bsim4/b4cvtest.c @@ -1,31 +1,28 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* Licensed under Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the license at http://opensource.org/licenses/ECL-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc */ + #include "ngspice/ngspice.h" #include "ngspice/cktdefs.h" #include "bsim4def.h" @@ -35,7 +32,6 @@ under the License. #include "ngspice/sperror.h" #include "ngspice/suffix.h" - int BSIM4convTest( GENmodel *inModel, @@ -44,7 +40,7 @@ CKTcircuit *ckt) BSIM4model *model = (BSIM4model*)inModel; BSIM4instance *here; double delvbd, delvbs, delvds, delvgd, delvgs; -double delvdbd, delvsbs; +double delvdbd, delvsbs; double delvbd_jct, delvbs_jct; double vds, vgs, vgd, vgdo, vbs, vbd; double vdbd, vdbs, vsbs; @@ -57,8 +53,7 @@ double tol0, tol1, tol2, tol3, tol4, tol5, tol6; for (; model != NULL; model = BSIM4nextModel(model)) { for (here = BSIM4instances(model); here != NULL ; here=BSIM4nextInstance(here)) - { - vds = model->BSIM4type + { vds = model->BSIM4type * (*(ckt->CKTrhsOld + here->BSIM4dNodePrime) - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); vgs = model->BSIM4type @@ -72,14 +67,14 @@ double tol0, tol1, tol2, tol3, tol4, tol5, tol6; - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); vsbs = model->BSIM4type * (*(ckt->CKTrhsOld + here->BSIM4sbNode) - - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); + - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); vses = model->BSIM4type * (*(ckt->CKTrhsOld + here->BSIM4sNode) - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); vdes = model->BSIM4type * (*(ckt->CKTrhsOld + here->BSIM4dNode) - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); - + vgdo = *(ckt->CKTstate0 + here->BSIM4vgs) - *(ckt->CKTstate0 + here->BSIM4vds); vbd = vbs - vds; @@ -125,11 +120,11 @@ double tol0, tol1, tol2, tol3, tol4, tol5, tol6; * delvds + here->BSIM4gIgbb * delvbs; } else - { Idtot = here->BSIM4cd + here->BSIM4cbd - here->BSIM4Igidl; /* bugfix */ - cdhat = Idtot + here->BSIM4gbd * delvbd_jct + here->BSIM4gmbs - * delvbd + here->BSIM4gm * delvgd - - (here->BSIM4gds + here->BSIM4ggidls) * delvds - - here->BSIM4ggidlg * delvgs - here->BSIM4ggidlb * delvbs; + { Idtot = here->BSIM4cd + here->BSIM4cbd - here->BSIM4Igidl; /* bugfix */ + cdhat = Idtot + here->BSIM4gbd * delvbd_jct + here->BSIM4gmbs + * delvbd + here->BSIM4gm * delvgd + - (here->BSIM4gds + here->BSIM4ggidls) * delvds + - here->BSIM4ggidlg * delvgs - here->BSIM4ggidlb * delvbs; Igstot = here->BSIM4Igs + here->BSIM4Igcd; cgshat = Igstot + here->BSIM4gIgsg * delvgs + here->BSIM4gIgcdg * delvgd @@ -176,7 +171,7 @@ double tol0, tol1, tol2, tol3, tol4, tol5, tol6; || (fabs(cdedhat - Idedtot) >= tol2)) { ckt->CKTnoncon++; return(OK); - } + } if ((fabs(cgshat - Igstot) >= tol3) || (fabs(cgdhat - Igdtot) >= tol4) || (fabs(cgbhat - Igbtot) >= tol5)) @@ -194,15 +189,15 @@ double tol0, tol1, tol2, tol3, tol4, tol5, tol6; - here->BSIM4ggislg * delvgd - here->BSIM4ggislb* delvbd + here->BSIM4ggisls * delvds ; } else - { cbhat = Ibtot + here->BSIM4gbs * delvbs_jct + here->BSIM4gbd - * delvbd_jct - (here->BSIM4gbbs + here->BSIM4ggislb) * delvbd - - (here->BSIM4gbgs + here->BSIM4ggislg) * delvgd - + (here->BSIM4gbds + here->BSIM4ggisld - here->BSIM4ggidls) * delvds - - here->BSIM4ggidlg * delvgs - here->BSIM4ggidlb * delvbs; + { cbhat = Ibtot + here->BSIM4gbs * delvbs_jct + here->BSIM4gbd + * delvbd_jct - (here->BSIM4gbbs + here->BSIM4ggislb) * delvbd + - (here->BSIM4gbgs + here->BSIM4ggislg) * delvgd + + (here->BSIM4gbds + here->BSIM4ggisld - here->BSIM4ggidls) * delvds + - here->BSIM4ggidlg * delvgs - here->BSIM4ggidlb * delvbs; } - tol6 = ckt->CKTreltol * MAX(fabs(cbhat), - fabs(Ibtot)) + ckt->CKTabstol; - if (fabs(cbhat - Ibtot) > tol6) + tol6 = ckt->CKTreltol * MAX(fabs(cbhat), + fabs(Ibtot)) + ckt->CKTabstol; + if (fabs(cbhat - Ibtot) > tol6) { ckt->CKTnoncon++; return(OK); } diff --git a/src/spicelib/devices/bsim4/b4geo.c b/src/spicelib/devices/bsim4/b4geo.c index 35d94af16..ac2cb98ac 100644 --- a/src/spicelib/devices/bsim4/b4geo.c +++ b/src/spicelib/devices/bsim4/b4geo.c @@ -1,35 +1,30 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* Licensed under Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the license at http://opensource.org/licenses/ECL-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc */ #include "ngspice/ngspice.h" #include "bsim4def.h" - static int BSIM4NumFingerDiff( double nf, @@ -38,32 +33,30 @@ double *nuIntD, double *nuEndD, double *nuIntS, double *nuEndS) { int NF; NF = (int)nf; - if ((NF%2) != 0) - { *nuEndD = *nuEndS = 1.0; - *nuIntD = *nuIntS = 2.0 * MAX((nf - 1.0) / 2.0, 0.0); - } - else - { if (minSD == 1) /* minimize # of source */ - { *nuEndD = 2.0; - *nuIntD = 2.0 * MAX((nf / 2.0 - 1.0), 0.0); - *nuEndS = 0.0; - *nuIntS = nf; - } - else - { *nuEndD = 0.0; + if ((NF%2) != 0) + { *nuEndD = *nuEndS = 1.0; + *nuIntD = *nuIntS = 2.0 * MAX((nf - 1.0) / 2.0, 0.0); + } + else + { if (minSD == 1) /* minimize # of source */ + { *nuEndD = 2.0; + *nuIntD = 2.0 * MAX((nf / 2.0 - 1.0), 0.0); + *nuEndS = 0.0; + *nuIntS = nf; + } + else + { *nuEndD = 0.0; *nuIntD = nf; *nuEndS = 2.0; *nuIntS = 2.0 * MAX((nf / 2.0 - 1.0), 0.0); - } - } + } + } return 0; } - int BSIM4PAeffGeo( -double nf, -int geo, int minSD, +double nf, int geo, int minSD, double Weffcj, double DMCG, double DMCI, double DMDG, double *Ps, double *Pd, double *As, double *Ad) { @@ -72,29 +65,29 @@ double ADiso, ADsha, ADmer, ASiso, ASsha, ASmer; double PDiso, PDsha, PDmer, PSiso, PSsha, PSmer; double nuIntD = 0.0, nuEndD = 0.0, nuIntS = 0.0, nuEndS = 0.0; - if (geo < 9) /* For geo = 9 and 10, the numbers of S/D diffusions already known */ - BSIM4NumFingerDiff(nf, minSD, &nuIntD, &nuEndD, &nuIntS, &nuEndS); + if (geo < 9) /* For geo = 9 and 10, the numbers of S/D diffusions already known */ + BSIM4NumFingerDiff(nf, minSD, &nuIntD, &nuEndD, &nuIntS, &nuEndS); - T0 = DMCG + DMCI; - T1 = DMCG + DMCG; - T2 = DMDG + DMDG; + T0 = DMCG + DMCI; + T1 = DMCG + DMCG; + T2 = DMDG + DMDG; - PSiso = PDiso = T0 + T0 + Weffcj; - PSsha = PDsha = T1; - PSmer = PDmer = T2; + PSiso = PDiso = T0 + T0 + Weffcj; + PSsha = PDsha = T1; + PSmer = PDmer = T2; - ASiso = ADiso = T0 * Weffcj; - ASsha = ADsha = DMCG * Weffcj; - ASmer = ADmer = DMDG * Weffcj; + ASiso = ADiso = T0 * Weffcj; + ASsha = ADsha = DMCG * Weffcj; + ASmer = ADmer = DMDG * Weffcj; - switch(geo) - { case 0: - *Ps = nuEndS * PSiso + nuIntS * PSsha; - *Pd = nuEndD * PDiso + nuIntD * PDsha; - *As = nuEndS * ASiso + nuIntS * ASsha; - *Ad = nuEndD * ADiso + nuIntD * ADsha; - break; - case 1: + switch(geo) + { case 0: + *Ps = nuEndS * PSiso + nuIntS * PSsha; + *Pd = nuEndD * PDiso + nuIntD * PDsha; + *As = nuEndS * ASiso + nuIntS * ASsha; + *Ad = nuEndD * ADiso + nuIntD * ADsha; + break; + case 1: *Ps = nuEndS * PSiso + nuIntS * PSsha; *Pd = (nuEndD + nuIntD) * PDsha; *As = nuEndS * ASiso + nuIntS * ASsha; @@ -154,61 +147,59 @@ double nuIntD = 0.0, nuEndD = 0.0, nuIntS = 0.0, nuEndS = 0.0; *As = nf * ASsha; *Ad = ADiso + (nf - 1.0) * ADsha; break; - default: - printf("Warning: Specified GEO = %d not matched\n", geo); - } + default: + printf("Warning: Specified GEO = %d not matched\n", geo); + } return 0; } int BSIM4RdseffGeo( -double nf, -int geo, int rgeo, int minSD, -double Weffcj, double Rsh, double DMCG, double DMCI, double DMDG, -int Type, +double nf, int geo, int rgeo, int minSD, +double Weffcj, double Rsh, double DMCG, double DMCI, double DMDG, int Type, double *Rtot) { -double Rint=0.0, Rend = 0.0; +double Rint = 0.0, Rend = 0.0; double nuIntD = 0.0, nuEndD = 0.0, nuIntS = 0.0, nuEndS = 0.0; if (geo < 9) /* since geo = 9 and 10 only happen when nf = even */ { BSIM4NumFingerDiff(nf, minSD, &nuIntD, &nuEndD, &nuIntS, &nuEndS); /* Internal S/D resistance -- assume shared S or D and all wide contacts */ - if (Type == 1) - { if (nuIntS == 0.0) - Rint = 0.0; - else - Rint = Rsh * DMCG / ( Weffcj * nuIntS); - } - else - { if (nuIntD == 0.0) + if (Type == 1) + { if (nuIntS == 0.0) + Rint = 0.0; + else + Rint = Rsh * DMCG / ( Weffcj * nuIntS); + } + else + { if (nuIntD == 0.0) Rint = 0.0; - else + else Rint = Rsh * DMCG / ( Weffcj * nuIntD); - } - } + } + } /* End S/D resistance -- geo dependent */ switch(geo) { case 0: - if (Type == 1) BSIM4RdsEndIso(Weffcj, Rsh, DMCG, DMCI, DMDG, - nuEndS, rgeo, 1, &Rend); - else BSIM4RdsEndIso(Weffcj, Rsh, DMCG, DMCI, DMDG, - nuEndD, rgeo, 0, &Rend); + if (Type == 1) BSIM4RdsEndIso(Weffcj, Rsh, DMCG, DMCI, DMDG, + nuEndS, rgeo, 1, &Rend); + else BSIM4RdsEndIso(Weffcj, Rsh, DMCG, DMCI, DMDG, + nuEndD, rgeo, 0, &Rend); break; case 1: if (Type == 1) BSIM4RdsEndIso(Weffcj, Rsh, DMCG, DMCI, DMDG, nuEndS, rgeo, 1, &Rend); else BSIM4RdsEndSha(Weffcj, Rsh, DMCG, DMCI, DMDG, - nuEndD, rgeo, 0, &Rend); + nuEndD, rgeo, 0, &Rend); break; case 2: if (Type == 1) BSIM4RdsEndSha(Weffcj, Rsh, DMCG, DMCI, DMDG, - nuEndS, rgeo, 1, &Rend); + nuEndS, rgeo, 1, &Rend); else BSIM4RdsEndIso(Weffcj, Rsh, DMCG, DMCI, DMDG, - nuEndD, rgeo, 0, &Rend); + nuEndD, rgeo, 0, &Rend); break; case 3: if (Type == 1) BSIM4RdsEndSha(Weffcj, Rsh, DMCG, DMCI, DMDG, @@ -237,20 +228,20 @@ double nuIntD = 0.0, nuEndD = 0.0, nuIntS = 0.0, nuEndS = 0.0; nuEndD, rgeo, 0, &Rend); break; case 8: - Rend = Rsh * DMDG / Weffcj; + Rend = Rsh * DMDG / Weffcj; break; case 9: /* all wide contacts assumed for geo = 9 and 10 */ - if (Type == 1) - { Rend = 0.5 * Rsh * DMCG / Weffcj; - if (nf == 2.0) - Rint = 0.0; - else - Rint = Rsh * DMCG / (Weffcj * (nf - 2.0)); - } - else - { Rend = 0.0; + if (Type == 1) + { Rend = 0.5 * Rsh * DMCG / Weffcj; + if (nf == 2.0) + Rint = 0.0; + else + Rint = Rsh * DMCG / (Weffcj * (nf - 2.0)); + } + else + { Rend = 0.0; Rint = Rsh * DMCG / (Weffcj * nf); - } + } break; case 10: if (Type == 1) @@ -269,14 +260,14 @@ double nuIntD = 0.0, nuEndD = 0.0, nuIntS = 0.0, nuEndS = 0.0; printf("Warning: Specified GEO = %d not matched\n", geo); } - if (Rint <= 0.0) - *Rtot = Rend; - else if (Rend <= 0.0) - *Rtot = Rint; - else - *Rtot = Rint * Rend / (Rint + Rend); + if (Rint <= 0.0) + *Rtot = Rend; + else if (Rend <= 0.0) + *Rtot = Rint; + else + *Rtot = Rint * Rend / (Rint + Rend); if(*Rtot==0.0) - printf("Warning: Zero resistance returned from RdseffGeo\n"); + printf("Warning: Zero resistance returned from RdseffGeo\n"); return 0; } @@ -284,38 +275,35 @@ return 0; int BSIM4RdsEndIso( double Weffcj, double Rsh, double DMCG, double DMCI, double DMDG, -double nuEnd, -int rgeo, int Type, -double *Rend) -{ - NG_IGNORE(DMDG); - - if (Type == 1) - { switch(rgeo) - { case 1: - case 2: - case 5: - if (nuEnd == 0.0) - *Rend = 0.0; - else +double nuEnd, int rgeo, int Type, double *Rend) +{ + NG_IGNORE(DMDG); + if (Type == 1) + { switch(rgeo) + { case 1: + case 2: + case 5: + if (nuEnd == 0.0) + *Rend = 0.0; + else *Rend = Rsh * DMCG / (Weffcj * nuEnd); - break; + break; case 3: case 4: case 6: - if ((DMCG + DMCI) == 0.0) + if ((DMCG + DMCI) == 0.0) printf("(DMCG + DMCI) can not be equal to zero\n"); if ((nuEnd == 0.0)||((DMCG+DMCI)==0.0)) *Rend = 0.0; else *Rend = Rsh * Weffcj / (3.0 * nuEnd * (DMCG + DMCI)); break; - default: - printf("Warning: Specified RGEO = %d not matched\n", rgeo); + default: + printf("Warning: Specified RGEO = %d not matched\n", rgeo); } - } - else - { switch(rgeo) + } + else + { switch(rgeo) { case 1: case 3: case 7: @@ -337,7 +325,7 @@ double *Rend) default: printf("Warning: Specified RGEO = %d not matched\n", rgeo); } - } + } return 0; } @@ -345,9 +333,7 @@ return 0; int BSIM4RdsEndSha( double Weffcj, double Rsh, double DMCG, double DMCI, double DMDG, -double nuEnd, -int rgeo, int Type, -double *Rend) +double nuEnd, int rgeo, int Type, double *Rend) { NG_IGNORE(DMCI); NG_IGNORE(DMDG); diff --git a/src/spicelib/devices/bsim4/b4getic.c b/src/spicelib/devices/bsim4/b4getic.c index 7a21add2a..b8ba34b25 100644 --- a/src/spicelib/devices/bsim4/b4getic.c +++ b/src/spicelib/devices/bsim4/b4getic.c @@ -1,20 +1,13 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* @@ -24,6 +17,9 @@ http://opensource.org/licenses/ECL-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc */ #include "ngspice/ngspice.h" @@ -32,7 +28,6 @@ under the License. #include "ngspice/sperror.h" #include "ngspice/suffix.h" - int BSIM4getic( GENmodel *inModel, @@ -43,20 +38,20 @@ BSIM4instance *here; for (; model ; model = BSIM4nextModel(model)) { for (here = BSIM4instances(model); here; here = BSIM4nextInstance(here)) - { - if (!here->BSIM4icVDSGiven) - { here->BSIM4icVDS = *(ckt->CKTrhs + here->BSIM4dNode) - - *(ckt->CKTrhs + here->BSIM4sNode); - } - if (!here->BSIM4icVGSGiven) - { here->BSIM4icVGS = *(ckt->CKTrhs + here->BSIM4gNodeExt) - - *(ckt->CKTrhs + here->BSIM4sNode); - } - if(!here->BSIM4icVBSGiven) - { here->BSIM4icVBS = *(ckt->CKTrhs + here->BSIM4bNode) - - *(ckt->CKTrhs + here->BSIM4sNode); - } - } + { + if (!here->BSIM4icVDSGiven) + { here->BSIM4icVDS = *(ckt->CKTrhs + here->BSIM4dNode) + - *(ckt->CKTrhs + here->BSIM4sNode); + } + if (!here->BSIM4icVGSGiven) + { here->BSIM4icVGS = *(ckt->CKTrhs + here->BSIM4gNodeExt) + - *(ckt->CKTrhs + here->BSIM4sNode); + } + if(!here->BSIM4icVBSGiven) + { here->BSIM4icVBS = *(ckt->CKTrhs + here->BSIM4bNode) + - *(ckt->CKTrhs + here->BSIM4sNode); + } + } } return(OK); } diff --git a/src/spicelib/devices/bsim4/b4ld.c b/src/spicelib/devices/bsim4/b4ld.c index 5e6500e2c..0c1d10bf4 100644 --- a/src/spicelib/devices/bsim4/b4ld.c +++ b/src/spicelib/devices/bsim4/b4ld.c @@ -1,32 +1,26 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* Licensed under Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the license at http://opensource.org/licenses/ECL-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -*/ -/**** OpenMP support ngspice 06/28/2010 ****/ +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc +*/ #include "ngspice/ngspice.h" #include "ngspice/cktdefs.h" @@ -93,17 +87,17 @@ CKTcircuit *ckt) } BSIM4LoadRhsMat(inModel, ckt); - + return error; } - int BSIM4LoadOMP(BSIM4instance *here, CKTcircuit *ckt) { BSIM4model *model = BSIM4modPtr(here); #else BSIM4model *model = (BSIM4model*)inModel; BSIM4instance *here; #endif + double ceqgstot, dgstot_dvd, dgstot_dvg, dgstot_dvs, dgstot_dvb; double ceqgdtot, dgdtot_dvd, dgdtot_dvg, dgdtot_dvs, dgdtot_dvb; double gstot, gstotd, gstotg, gstots, gstotb, gspr, Rs, Rd; @@ -113,9 +107,6 @@ double dRs_dvg, dRd_dvg, dRs_dvb, dRd_dvb; double dT0_dvg, dT1_dvb, dT3_dvg, dT3_dvb; double vses, vdes, vdedo, delvses, delvded, delvdes; double Isestot, cseshat, Idedtot, cdedhat; -#ifndef NEWCONV -double tol0, tol1, tol2, tol3, tol4, tol5, tol6; -#endif double geltd, gcrg, gcrgg, gcrgd, gcrgs, gcrgb, ceqgcrg; double vges, vgms, vgedo, vgmdo, vged, vgmd, delvged, delvgmd; @@ -123,10 +114,7 @@ double delvges, delvgms, vgmb; double gcgmgmb=0.0, gcgmdb=0.0, gcgmsb=0.0, gcdgmb, gcsgmb; double gcgmbb=0.0, gcbgmb, qgmb, qgmid=0.0, ceqqgmid; -double vbd, vbs, vds, vgb, vgd, vgs, vgdo; -#ifndef PREDICTOR -double xfact; -#endif +double vbd, vbs, vds, vgb, vgd, vgs, vgdo, xfact; double vdbs, vdbd, vsbs, vsbdo, vsbd; double delvdbs, delvdbd, delvsbs; double delvbd_jct, delvbs_jct, vbs_jct, vbd_jct; @@ -161,7 +149,7 @@ double Ibtoteq, gIbtotg, gIbtotd, gIbtots, gIbtotb; double Igtoteq, gIgtotg, gIgtotd, gIgtots, gIgtotb; double Igstot, cgshat, Igdtot, cgdhat, Igbtot, cgbhat; double Vgs_eff, Vfb=0.0, Vth_NarrowW; -/* double Vgd_eff, dVgd_eff_dVg; v4.7.0 */ +/* double Vgd_eff, dVgd_eff_dVg; v4.7.0 */ double Phis, dPhis_dVb, sqrtPhis, dsqrtPhis_dVb, Vth, dVth_dVb, dVth_dVd; double Vgst, dVgst_dVg, dVgst_dVb, dVgs_eff_dVg, Nvtms, Nvtmd; double Vtm, Vtm0; @@ -171,14 +159,14 @@ double DeltaPhi, dDeltaPhi_dVg, VgDP, dVgDP_dVg; double Cox, Tox, Tcen, dTcen_dVg, dTcen_dVd, dTcen_dVb; double Ccen, Coxeff, dCoxeff_dVd, dCoxeff_dVg, dCoxeff_dVb; double Denomi, dDenomi_dVg, dDenomi_dVd, dDenomi_dVb; -double ueff, dueff_dVg, dueff_dVd, dueff_dVb; +double ueff, dueff_dVg, dueff_dVd, dueff_dVb; double Esat, Vdsat; double EsatL, dEsatL_dVg, dEsatL_dVd, dEsatL_dVb; -double dVdsat_dVg, dVdsat_dVb, dVdsat_dVd, Vasat, dAlphaz_dVg, dAlphaz_dVb; -double dVasat_dVg, dVasat_dVb, dVasat_dVd, Va, dVa_dVd, dVa_dVg, dVa_dVb; -double Vbseff, dVbseff_dVb, VbseffCV, dVbseffCV_dVb; +double dVdsat_dVg, dVdsat_dVb, dVdsat_dVd, Vasat, dAlphaz_dVg, dAlphaz_dVb; +double dVasat_dVg, dVasat_dVb, dVasat_dVd, Va, dVa_dVd, dVa_dVg, dVa_dVb; +double Vbseff, dVbseff_dVb, VbseffCV, dVbseffCV_dVb; double VgsteffVth, dT11_dVg; -double Arg1, One_Third_CoxWL, Two_Third_CoxWL, Alphaz, CoxWL; +double Arg1, One_Third_CoxWL, Two_Third_CoxWL, Alphaz, CoxWL; double T0=0.0, dT0_dVg, dT0_dVd, dT0_dVb; double T1, dT1_dVg, dT1_dVd, dT1_dVb; double T2, dT2_dVg, dT2_dVd, dT2_dVb; @@ -189,14 +177,14 @@ double T6, dT6_dVg, dT6_dVd, dT6_dVb; double T7, dT7_dVg, dT7_dVd, dT7_dVb; double T8, dT8_dVg, dT8_dVd, dT8_dVb; double T9, dT9_dVg, dT9_dVd, dT9_dVb; -double T10, dT10_dVg, dT10_dVb, dT10_dVd; +double T10, dT10_dVg, dT10_dVb, dT10_dVd; double T11, T12, T13, T14; -double tmp, Abulk, dAbulk_dVb, Abulk0, dAbulk0_dVb; +double tmp, Abulk, dAbulk_dVb, Abulk0, Abulk0_Q, dAbulk0_dVb, dAbulk0_Q_dVb; double Cclm, dCclm_dVg, dCclm_dVd, dCclm_dVb; double FP, dFP_dVg, PvagTerm, dPvagTerm_dVg, dPvagTerm_dVd, dPvagTerm_dVb; double VADITS, dVADITS_dVg, dVADITS_dVd; double Lpe_Vb, dDITS_Sft_dVb, dDITS_Sft_dVd; -double DITS_Sft2, dDITS_Sft2_dVd; /* v4.7 New DITS */ +double DITS_Sft2, dDITS_Sft2_dVd; /* v4.7 New DITS */ double VACLM, dVACLM_dVg, dVACLM_dVd, dVACLM_dVb; double VADIBL, dVADIBL_dVg, dVADIBL_dVd, dVADIBL_dVb; double Xdep, dXdep_dVb, lt1, dlt1_dVb, ltw, dltw_dVb, Delt_vth, dDelt_vth_dVb; @@ -205,9 +193,9 @@ double TempRatio, tmp1, tmp2, tmp3, tmp4; double DIBL_Sft, dDIBL_Sft_dVd, Lambda, dLambda_dVg; double Idtot, Ibtot, a1, ScalingFactor; -double Vgsteff, dVgsteff_dVg, dVgsteff_dVd, dVgsteff_dVb; -double Vdseff, dVdseff_dVg, dVdseff_dVd, dVdseff_dVb; -double VdseffCV, dVdseffCV_dVg, dVdseffCV_dVd, dVdseffCV_dVb; +double Vgsteff, dVgsteff_dVg, dVgsteff_dVd, dVgsteff_dVb; +double Vdseff, dVdseff_dVg, dVdseff_dVd, dVdseff_dVb; +double VdseffCV, dVdseffCV_dVg, dVdseffCV_dVd, dVdseffCV_dVb; double diffVds, dAbulk_dVg; double beta, dbeta_dVg, dbeta_dVd, dbeta_dVb; double gche, dgche_dVg, dgche_dVd, dgche_dVb; @@ -228,12 +216,12 @@ double gcqdb=0.0, gcqsb=0.0, gcqgb=0.0, gcqbb=0.0; double dxpart, sxpart, ggtg, ggtd, ggts, ggtb; double ddxpart_dVd, ddxpart_dVg, ddxpart_dVb, ddxpart_dVs; double dsxpart_dVd, dsxpart_dVg, dsxpart_dVb, dsxpart_dVs; -double gbspsp, gbbdp, gbbsp, gbspg, gbspb, gbspdp; -double gbdpdp, gbdpg, gbdpb, gbdpsp; +double gbspsp, gbbdp, gbbsp, gbspg, gbspb, gbspdp; +double gbdpdp, gbdpg, gbdpb, gbdpsp; double qgdo, qgso, cgdo, cgso; double Cgg, Cgd, Cgb, Cdg, Cdd, Cds; double Csg, Csd, Css, Csb, Cbg, Cbd, Cbb; -double Cgg1, Cgd1, Cgb1, Cbg1, Cbb1, Cbd1, Qac0, Qsub0; +double Cgg1, Cgb1, Cgd1, Cbg1, Cbb1, Cbd1, Qac0, Qsub0; double dQac0_dVg, dQac0_dVb, dQsub0_dVg, dQsub0_dVd, dQsub0_dVb; double ggidld, ggidlg, ggidlb, ggislg, ggislb, ggisls; double Igisl, Ggislg, Ggislb, Ggisls; @@ -244,18 +232,18 @@ double vs, Fsevl, dvs_dVg, dvs_dVd, dvs_dVb, dFsevl_dVg, dFsevl_dVd, dFsevl_dVb; double vgdx, vgsx, epssub, toxe, epsrox; struct bsim4SizeDependParam *pParam; int ByPass, ChargeComputationNeeded, error, Check, Check1, Check2; - -double m; +double m, mult_i, mult_q; ScalingFactor = 1.0e-9; -ChargeComputationNeeded = +/* no integration, if dc sweep, but keep evaluating capacitances */ +ChargeComputationNeeded = ((ckt->CKTmode & (MODEDCTRANCURVE | MODEAC | MODETRAN | MODEINITSMSIG)) || ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) ? 1 : 0; #ifndef USE_OMP for (; model != NULL; model = BSIM4nextModel(model)) -{ for (here = BSIM4instances(model); here != NULL; +{ for (here = BSIM4instances(model); here != NULL; here = BSIM4nextInstance(here)) { #endif @@ -312,14 +300,14 @@ for (; model != NULL; model = BSIM4nextModel(model)) MODEDCTRANCURVE)) || (!(ckt->CKTmode & MODEUIC)))) { vds = 0.1; vdes = 0.11; - vses = -0.01; - vgs = vges = vgms = model->BSIM4type + vses = -0.01; + vgs = vges = vgms = model->BSIM4type * here->BSIM4vth0 + 0.1; vbs = vdbs = vsbs = 0.0; } } - else if ((ckt->CKTmode & (MODEINITJCT | MODEINITFIX)) && - (here->BSIM4off)) + else if ((ckt->CKTmode & (MODEINITJCT | MODEINITFIX)) && + (here->BSIM4off)) { vds = vgs = vbs = vges = vgms = 0.0; vdbs = vsbs = vdes = vses = qdef = 0.0; } @@ -328,11 +316,11 @@ for (; model != NULL; model = BSIM4nextModel(model)) #ifndef PREDICTOR if ((ckt->CKTmode & MODEINITPRED)) { xfact = ckt->CKTdelta / ckt->CKTdeltaOld[1]; - *(ckt->CKTstate0 + here->BSIM4vds) = + *(ckt->CKTstate0 + here->BSIM4vds) = *(ckt->CKTstate1 + here->BSIM4vds); vds = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM4vds)) - (xfact * (*(ckt->CKTstate2 + here->BSIM4vds))); - *(ckt->CKTstate0 + here->BSIM4vgs) = + *(ckt->CKTstate0 + here->BSIM4vgs) = *(ckt->CKTstate1 + here->BSIM4vgs); vgs = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM4vgs)) - (xfact * (*(ckt->CKTstate2 + here->BSIM4vgs))); @@ -344,11 +332,11 @@ for (; model != NULL; model = BSIM4nextModel(model)) *(ckt->CKTstate1 + here->BSIM4vgms); vgms = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM4vgms)) - (xfact * (*(ckt->CKTstate2 + here->BSIM4vgms))); - *(ckt->CKTstate0 + here->BSIM4vbs) = + *(ckt->CKTstate0 + here->BSIM4vbs) = *(ckt->CKTstate1 + here->BSIM4vbs); vbs = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM4vbs)) - (xfact * (*(ckt->CKTstate2 + here->BSIM4vbs))); - *(ckt->CKTstate0 + here->BSIM4vbd) = + *(ckt->CKTstate0 + here->BSIM4vbd) = *(ckt->CKTstate0 + here->BSIM4vbs) - *(ckt->CKTstate0 + here->BSIM4vds); *(ckt->CKTstate0 + here->BSIM4vdbs) = @@ -376,14 +364,14 @@ for (; model != NULL; model = BSIM4nextModel(model)) qdef = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM4qdef)) -(xfact * (*(ckt->CKTstate2 + here->BSIM4qdef))); } - else - { + else + { #endif /* PREDICTOR */ vds = model->BSIM4type * (*(ckt->CKTrhsOld + here->BSIM4dNodePrime) - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); vgs = model->BSIM4type - * (*(ckt->CKTrhsOld + here->BSIM4gNodePrime) + * (*(ckt->CKTrhsOld + here->BSIM4gNodePrime) - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); vbs = model->BSIM4type * (*(ckt->CKTrhsOld + here->BSIM4bNodePrime) @@ -414,27 +402,27 @@ for (; model != NULL; model = BSIM4nextModel(model)) vgdo = *(ckt->CKTstate0 + here->BSIM4vgs) - *(ckt->CKTstate0 + here->BSIM4vds); - vgedo = *(ckt->CKTstate0 + here->BSIM4vges) + vgedo = *(ckt->CKTstate0 + here->BSIM4vges) - *(ckt->CKTstate0 + here->BSIM4vds); - vgmdo = *(ckt->CKTstate0 + here->BSIM4vgms) + vgmdo = *(ckt->CKTstate0 + here->BSIM4vgms) - *(ckt->CKTstate0 + here->BSIM4vds); vbd = vbs - vds; vdbd = vdbs - vds; vgd = vgs - vds; - vged = vges - vds; - vgmd = vgms - vds; + vged = vges - vds; + vgmd = vgms - vds; delvbd = vbd - *(ckt->CKTstate0 + here->BSIM4vbd); delvdbd = vdbd - *(ckt->CKTstate0 + here->BSIM4vdbd); delvgd = vgd - vgdo; - delvged = vged - vgedo; - delvgmd = vgmd - vgmdo; + delvged = vged - vgedo; + delvgmd = vgmd - vgmdo; delvds = vds - *(ckt->CKTstate0 + here->BSIM4vds); delvgs = vgs - *(ckt->CKTstate0 + here->BSIM4vgs); - delvges = vges - *(ckt->CKTstate0 + here->BSIM4vges); - delvgms = vgms - *(ckt->CKTstate0 + here->BSIM4vgms); + delvges = vges - *(ckt->CKTstate0 + here->BSIM4vges); + delvgms = vgms - *(ckt->CKTstate0 + here->BSIM4vgms); delvbs = vbs - *(ckt->CKTstate0 + here->BSIM4vbs); delvdbs = vdbs - *(ckt->CKTstate0 + here->BSIM4vdbs); delvsbs = vsbs - *(ckt->CKTstate0 + here->BSIM4vsbs); @@ -442,51 +430,51 @@ for (; model != NULL; model = BSIM4nextModel(model)) delvses = vses - (*(ckt->CKTstate0 + here->BSIM4vses)); vdedo = *(ckt->CKTstate0 + here->BSIM4vdes) - *(ckt->CKTstate0 + here->BSIM4vds); - delvdes = vdes - *(ckt->CKTstate0 + here->BSIM4vdes); + delvdes = vdes - *(ckt->CKTstate0 + here->BSIM4vdes); delvded = vdes - vds - vdedo; delvbd_jct = (!here->BSIM4rbodyMod) ? delvbd : delvdbd; delvbs_jct = (!here->BSIM4rbodyMod) ? delvbs : delvsbs; if (here->BSIM4mode >= 0) { Idtot = here->BSIM4cd + here->BSIM4csub - here->BSIM4cbd - + here->BSIM4Igidl; + + here->BSIM4Igidl; cdhat = Idtot - here->BSIM4gbd * delvbd_jct + (here->BSIM4gmbs + here->BSIM4gbbs + here->BSIM4ggidlb) * delvbs - + (here->BSIM4gm + here->BSIM4gbgs + here->BSIM4ggidlg) * delvgs + + (here->BSIM4gm + here->BSIM4gbgs + here->BSIM4ggidlg) * delvgs + (here->BSIM4gds + here->BSIM4gbds + here->BSIM4ggidld) * delvds; - Ibtot = here->BSIM4cbs + here->BSIM4cbd - - here->BSIM4Igidl - here->BSIM4Igisl - here->BSIM4csub; + Ibtot = here->BSIM4cbs + here->BSIM4cbd + - here->BSIM4Igidl - here->BSIM4Igisl - here->BSIM4csub; cbhat = Ibtot + here->BSIM4gbd * delvbd_jct + here->BSIM4gbs * delvbs_jct - (here->BSIM4gbbs + here->BSIM4ggidlb) * delvbs - (here->BSIM4gbgs + here->BSIM4ggidlg) * delvgs - - (here->BSIM4gbds + here->BSIM4ggidld - here->BSIM4ggisls) * delvds - - here->BSIM4ggislg * delvgd - here->BSIM4ggislb* delvbd; + - (here->BSIM4gbds + here->BSIM4ggidld - here->BSIM4ggisls) * delvds + - here->BSIM4ggislg * delvgd - here->BSIM4ggislb* delvbd; - Igstot = here->BSIM4Igs + here->BSIM4Igcs; - cgshat = Igstot + (here->BSIM4gIgsg + here->BSIM4gIgcsg) * delvgs - + here->BSIM4gIgcsd * delvds + here->BSIM4gIgcsb * delvbs; + Igstot = here->BSIM4Igs + here->BSIM4Igcs; + cgshat = Igstot + (here->BSIM4gIgsg + here->BSIM4gIgcsg) * delvgs + + here->BSIM4gIgcsd * delvds + here->BSIM4gIgcsb * delvbs; - Igdtot = here->BSIM4Igd + here->BSIM4Igcd; - cgdhat = Igdtot + here->BSIM4gIgdg * delvgd + here->BSIM4gIgcdg * delvgs + Igdtot = here->BSIM4Igd + here->BSIM4Igcd; + cgdhat = Igdtot + here->BSIM4gIgdg * delvgd + here->BSIM4gIgcdg * delvgs + here->BSIM4gIgcdd * delvds + here->BSIM4gIgcdb * delvbs; - Igbtot = here->BSIM4Igb; - cgbhat = here->BSIM4Igb + here->BSIM4gIgbg * delvgs + here->BSIM4gIgbd - * delvds + here->BSIM4gIgbb * delvbs; + Igbtot = here->BSIM4Igb; + cgbhat = here->BSIM4Igb + here->BSIM4gIgbg * delvgs + here->BSIM4gIgbd + * delvds + here->BSIM4gIgbb * delvbs; } else { Idtot = here->BSIM4cd + here->BSIM4cbd - here->BSIM4Igidl; /* bugfix */ - cdhat = Idtot + here->BSIM4gbd * delvbd_jct + here->BSIM4gmbs - * delvbd + here->BSIM4gm * delvgd - - (here->BSIM4gds + here->BSIM4ggidls) * delvds + cdhat = Idtot + here->BSIM4gbd * delvbd_jct + here->BSIM4gmbs + * delvbd + here->BSIM4gm * delvgd + - (here->BSIM4gds + here->BSIM4ggidls) * delvds - here->BSIM4ggidlg * delvgs - here->BSIM4ggidlb * delvbs; - Ibtot = here->BSIM4cbs + here->BSIM4cbd - - here->BSIM4Igidl - here->BSIM4Igisl - here->BSIM4csub; - cbhat = Ibtot + here->BSIM4gbs * delvbs_jct + here->BSIM4gbd + Ibtot = here->BSIM4cbs + here->BSIM4cbd + - here->BSIM4Igidl - here->BSIM4Igisl - here->BSIM4csub; + cbhat = Ibtot + here->BSIM4gbs * delvbs_jct + here->BSIM4gbd * delvbd_jct - (here->BSIM4gbbs + here->BSIM4ggislb) * delvbd - (here->BSIM4gbgs + here->BSIM4ggislg) * delvgd - + (here->BSIM4gbds + here->BSIM4ggisld - here->BSIM4ggidls) * delvds - - here->BSIM4ggidlg * delvgs - here->BSIM4ggidlb * delvbs; + + (here->BSIM4gbds + here->BSIM4ggisld - here->BSIM4ggidls) * delvds + - here->BSIM4ggidlg * delvgs - here->BSIM4ggidlb * delvbs; Igstot = here->BSIM4Igs + here->BSIM4Igcd; cgshat = Igstot + here->BSIM4gIgsg * delvgs + here->BSIM4gIgcdg * delvgd @@ -513,7 +501,7 @@ for (; model != NULL; model = BSIM4nextModel(model)) #ifndef NOBYPASS - /* Following should be one IF statement, but some C compilers + /* Following should be one IF statement, but some C compilers * can't handle that all at once, so we split it into several * successive IF's */ @@ -526,10 +514,10 @@ for (; model != NULL; model = BSIM4nextModel(model)) fabs(*(ckt->CKTstate0 + here->BSIM4vbs))) + ckt->CKTvoltTol))) if ((fabs(delvbd) < (ckt->CKTreltol * MAX(fabs(vbd), fabs(*(ckt->CKTstate0 + here->BSIM4vbd))) + ckt->CKTvoltTol))) - if ((here->BSIM4rgateMod == 0) || (here->BSIM4rgateMod == 1) - || (fabs(delvges) < (ckt->CKTreltol * MAX(fabs(vges), - fabs(*(ckt->CKTstate0 + here->BSIM4vges))) + ckt->CKTvoltTol))) - if ((here->BSIM4rgateMod != 3) || (fabs(delvgms) < (ckt->CKTreltol + if ((here->BSIM4rgateMod == 0) || (here->BSIM4rgateMod == 1) + || (fabs(delvges) < (ckt->CKTreltol * MAX(fabs(vges), + fabs(*(ckt->CKTstate0 + here->BSIM4vges))) + ckt->CKTvoltTol))) + if ((here->BSIM4rgateMod != 3) || (fabs(delvgms) < (ckt->CKTreltol * MAX(fabs(vgms), fabs(*(ckt->CKTstate0 + here->BSIM4vgms))) + ckt->CKTvoltTol))) if ((!here->BSIM4rbodyMod) || (fabs(delvdbs) < (ckt->CKTreltol @@ -564,8 +552,8 @@ for (; model != NULL; model = BSIM4nextModel(model)) { vds = *(ckt->CKTstate0 + here->BSIM4vds); vgs = *(ckt->CKTstate0 + here->BSIM4vgs); vbs = *(ckt->CKTstate0 + here->BSIM4vbs); - vges = *(ckt->CKTstate0 + here->BSIM4vges); - vgms = *(ckt->CKTstate0 + here->BSIM4vgms); + vges = *(ckt->CKTstate0 + here->BSIM4vges); + vgms = *(ckt->CKTstate0 + here->BSIM4vgms); vbd = *(ckt->CKTstate0 + here->BSIM4vbd); vdbs = *(ckt->CKTstate0 + here->BSIM4vdbs); @@ -576,41 +564,41 @@ for (; model != NULL; model = BSIM4nextModel(model)) vgd = vgs - vds; vgb = vgs - vbs; - vged = vges - vds; - vgmd = vgms - vds; - vgmb = vgms - vbs; + vged = vges - vds; + vgmd = vgms - vds; + vgmb = vgms - vbs; vbs_jct = (!here->BSIM4rbodyMod) ? vbs : vsbs; vbd_jct = (!here->BSIM4rbodyMod) ? vbd : vdbd; -/*** qdef should not be kept fixed even if vgs, vds & vbs has converged -**** qdef = *(ckt->CKTstate0 + here->BSIM4qdef); +/*** qdef should not be kept fixed even if vgs, vds & vbs has converged +**** qdef = *(ckt->CKTstate0 + here->BSIM4qdef); ***/ cdrain = here->BSIM4cd; - if ((ckt->CKTmode & (MODETRAN | MODEAC)) || - ((ckt->CKTmode & MODETRANOP) && + if ((ckt->CKTmode & (MODETRAN | MODEAC)) || + ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) - { ByPass = 1; + { ByPass = 1; qgate = here->BSIM4qgate; qbulk = here->BSIM4qbulk; qdrn = here->BSIM4qdrn; - cgdo = here->BSIM4cgdo; - qgdo = here->BSIM4qgdo; + cgdo = here->BSIM4cgdo; + qgdo = here->BSIM4qgdo; cgso = here->BSIM4cgso; qgso = here->BSIM4qgso; - goto line755; + goto line755; } - else - goto line850; + else + goto line850; } #endif /*NOBYPASS*/ von = here->BSIM4von; if (*(ckt->CKTstate0 + here->BSIM4vds) >= 0.0) - { vgs = DEVfetlim(vgs, *(ckt->CKTstate0 + here->BSIM4vgs), von); + { vgs = DEVfetlim(vgs, *(ckt->CKTstate0 + here->BSIM4vgs), von); vds = vgs - vgd; vds = DEVlimvds(vds, *(ckt->CKTstate0 + here->BSIM4vds)); vgd = vgs - vds; @@ -626,18 +614,18 @@ for (; model != NULL; model = BSIM4nextModel(model)) } if (model->BSIM4rdsMod) - { vdes = DEVlimvds(vdes, *(ckt->CKTstate0 + here->BSIM4vdes)); - vses = -DEVlimvds(-vses, -(*(ckt->CKTstate0 + here->BSIM4vses))); - } + { vdes = DEVlimvds(vdes, *(ckt->CKTstate0 + here->BSIM4vdes)); + vses = -DEVlimvds(-vses, -(*(ckt->CKTstate0 + here->BSIM4vses))); + } } - else - { vgd = DEVfetlim(vgd, vgdo, von); + else + { vgd = DEVfetlim(vgd, vgdo, von); vds = vgs - vgd; vds = -DEVlimvds(-vds, -(*(ckt->CKTstate0 + here->BSIM4vds))); vgs = vgd + vds; - if (here->BSIM4rgateMod == 3) + if (here->BSIM4rgateMod == 3) { vged = DEVfetlim(vged, vgedo, von); vges = vged + vds; vgmd = DEVfetlim(vgmd, vgmdo, von); @@ -655,7 +643,7 @@ for (; model != NULL; model = BSIM4nextModel(model)) } if (vds >= 0.0) - { vbs = DEVpnjlim(vbs, *(ckt->CKTstate0 + here->BSIM4vbs), + { vbs = DEVpnjlim(vbs, *(ckt->CKTstate0 + here->BSIM4vbs), CONSTvt0, model->BSIM4vcrit, &Check); vbd = vbs - vds; if (here->BSIM4rbodyMod) @@ -666,13 +654,13 @@ for (; model != NULL; model = BSIM4nextModel(model)) CONSTvt0, model->BSIM4vcrit, &Check2); if ((Check1 == 0) && (Check2 == 0)) Check = 0; - else + else Check = 1; } } - else + else { vbd = DEVpnjlim(vbd, *(ckt->CKTstate0 + here->BSIM4vbd), - CONSTvt0, model->BSIM4vcrit, &Check); + CONSTvt0, model->BSIM4vcrit, &Check); vbs = vbd + vds; if (here->BSIM4rbodyMod) { vdbd = DEVpnjlim(vdbd, *(ckt->CKTstate0 + here->BSIM4vdbd), @@ -695,9 +683,9 @@ for (; model != NULL; model = BSIM4nextModel(model)) vbd = vbs - vds; vgd = vgs - vds; vgb = vgs - vbs; - vged = vges - vds; - vgmd = vgms - vds; - vgmb = vgms - vbs; + vged = vges - vds; + vgmd = vgms - vds; + vgmb = vgms - vbs; vdbd = vdbs - vds; vbs_jct = (!here->BSIM4rbodyMod) ? vbs : vsbs; @@ -705,12 +693,12 @@ for (; model != NULL; model = BSIM4nextModel(model)) /* Source/drain junction diode DC model begins */ Nvtms = model->BSIM4vtm * model->BSIM4SjctEmissionCoeff; -/* if ((here->BSIM4Aseff <= 0.0) && (here->BSIM4Pseff <= 0.0)) - { SourceSatCurrent = 1.0e-14; - } v4.7 */ +/* if ((here->BSIM4Aseff <= 0.0) && (here->BSIM4Pseff <= 0.0)) + { SourceSatCurrent = 1.0e-14; + } v4.7 */ if ((here->BSIM4Aseff <= 0.0) && (here->BSIM4Pseff <= 0.0)) - { SourceSatCurrent = 0.0; - } + { SourceSatCurrent = 0.0; + } else { SourceSatCurrent = here->BSIM4Aseff * model->BSIM4SjctTempSatCurDensity + here->BSIM4Pseff * model->BSIM4SjctSidewallTempSatCurDensity @@ -718,58 +706,58 @@ for (; model != NULL; model = BSIM4nextModel(model)) * model->BSIM4SjctGateSidewallTempSatCurDensity; } - if (SourceSatCurrent <= 0.0) - { here->BSIM4gbs = ckt->CKTgmin; + if (SourceSatCurrent <= 0.0) + { here->BSIM4gbs = ckt->CKTgmin; here->BSIM4cbs = here->BSIM4gbs * vbs_jct; } else - { switch(model->BSIM4dioMod) + { switch(model->BSIM4dioMod) { case 0: evbs = exp(vbs_jct / Nvtms); T1 = model->BSIM4xjbvs * exp(-(model->BSIM4bvs + vbs_jct) / Nvtms); - /* WDLiu: Magic T1 in this form; different from BSIM4 beta. */ - here->BSIM4gbs = SourceSatCurrent * (evbs + T1) / Nvtms + ckt->CKTgmin; - here->BSIM4cbs = SourceSatCurrent * (evbs + here->BSIM4XExpBVS - - T1 - 1.0) + ckt->CKTgmin * vbs_jct; - break; + /* WDLiu: Magic T1 in this form; different from BSIM4 beta. */ + here->BSIM4gbs = SourceSatCurrent * (evbs + T1) / Nvtms + ckt->CKTgmin; + here->BSIM4cbs = SourceSatCurrent * (evbs + here->BSIM4XExpBVS + - T1 - 1.0) + ckt->CKTgmin * vbs_jct; + break; case 1: - T2 = vbs_jct / Nvtms; - if (T2 < -EXP_THRESHOLD) - { here->BSIM4gbs = ckt->CKTgmin; + T2 = vbs_jct / Nvtms; + if (T2 < -EXP_THRESHOLD) + { here->BSIM4gbs = ckt->CKTgmin; here->BSIM4cbs = SourceSatCurrent * (MIN_EXP - 1.0) + ckt->CKTgmin * vbs_jct; } - else if (vbs_jct <= here->BSIM4vjsmFwd) - { evbs = exp(T2); - here->BSIM4gbs = SourceSatCurrent * evbs / Nvtms + ckt->CKTgmin; + else if (vbs_jct <= here->BSIM4vjsmFwd) + { evbs = exp(T2); + here->BSIM4gbs = SourceSatCurrent * evbs / Nvtms + ckt->CKTgmin; here->BSIM4cbs = SourceSatCurrent * (evbs - 1.0) + ckt->CKTgmin * vbs_jct; - } - else - { T0 = here->BSIM4IVjsmFwd / Nvtms; + } + else + { T0 = here->BSIM4IVjsmFwd / Nvtms; here->BSIM4gbs = T0 + ckt->CKTgmin; - here->BSIM4cbs = here->BSIM4IVjsmFwd - SourceSatCurrent + T0 - * (vbs_jct - here->BSIM4vjsmFwd) + ckt->CKTgmin * vbs_jct; - } + here->BSIM4cbs = here->BSIM4IVjsmFwd - SourceSatCurrent + T0 + * (vbs_jct - here->BSIM4vjsmFwd) + ckt->CKTgmin * vbs_jct; + } break; case 2: if (vbs_jct < here->BSIM4vjsmRev) { T0 = vbs_jct / Nvtms; if (T0 < -EXP_THRESHOLD) { evbs = MIN_EXP; - devbs_dvb = 0.0; - } + devbs_dvb = 0.0; + } else - { evbs = exp(T0); + { evbs = exp(T0); devbs_dvb = evbs / Nvtms; - } + } - T1 = evbs - 1.0; - T2 = here->BSIM4IVjsmRev + here->BSIM4SslpRev - * (vbs_jct - here->BSIM4vjsmRev); - here->BSIM4gbs = devbs_dvb * T2 + T1 * here->BSIM4SslpRev + ckt->CKTgmin; + T1 = evbs - 1.0; + T2 = here->BSIM4IVjsmRev + here->BSIM4SslpRev + * (vbs_jct - here->BSIM4vjsmRev); + here->BSIM4gbs = devbs_dvb * T2 + T1 * here->BSIM4SslpRev + ckt->CKTgmin; here->BSIM4cbs = T1 * T2 + ckt->CKTgmin * vbs_jct; - } + } else if (vbs_jct <= here->BSIM4vjsmFwd) { T0 = vbs_jct / Nvtms; if (T0 < -EXP_THRESHOLD) @@ -781,37 +769,37 @@ for (; model != NULL; model = BSIM4nextModel(model)) devbs_dvb = evbs / Nvtms; } - T1 = (model->BSIM4bvs + vbs_jct) / Nvtms; + T1 = (model->BSIM4bvs + vbs_jct) / Nvtms; if (T1 > EXP_THRESHOLD) { T2 = MIN_EXP; - T3 = 0.0; - } + T3 = 0.0; + } else - { T2 = exp(-T1); - T3 = -T2 /Nvtms; - } + { T2 = exp(-T1); + T3 = -T2 /Nvtms; + } here->BSIM4gbs = SourceSatCurrent * (devbs_dvb - model->BSIM4xjbvs * T3) - + ckt->CKTgmin; - here->BSIM4cbs = SourceSatCurrent * (evbs + here->BSIM4XExpBVS - 1.0 - - model->BSIM4xjbvs * T2) + ckt->CKTgmin * vbs_jct; + + ckt->CKTgmin; + here->BSIM4cbs = SourceSatCurrent * (evbs + here->BSIM4XExpBVS - 1.0 + - model->BSIM4xjbvs * T2) + ckt->CKTgmin * vbs_jct; } - else - { here->BSIM4gbs = here->BSIM4SslpFwd + ckt->CKTgmin; + else + { here->BSIM4gbs = here->BSIM4SslpFwd + ckt->CKTgmin; here->BSIM4cbs = here->BSIM4IVjsmFwd + here->BSIM4SslpFwd * (vbs_jct - - here->BSIM4vjsmFwd) + ckt->CKTgmin * vbs_jct; - } + - here->BSIM4vjsmFwd) + ckt->CKTgmin * vbs_jct; + } break; default: break; } - } + } Nvtmd = model->BSIM4vtm * model->BSIM4DjctEmissionCoeff; -/* if ((here->BSIM4Adeff <= 0.0) && (here->BSIM4Pdeff <= 0.0)) - { DrainSatCurrent = 1.0e-14; - } v4.7 */ - if ((here->BSIM4Adeff <= 0.0) && (here->BSIM4Pdeff <= 0.0)) - { DrainSatCurrent = 0.0; - } +/* if ((here->BSIM4Adeff <= 0.0) && (here->BSIM4Pdeff <= 0.0)) + { DrainSatCurrent = 1.0e-14; + } v4.7 */ + if ((here->BSIM4Adeff <= 0.0) && (here->BSIM4Pdeff <= 0.0)) + { DrainSatCurrent = 0.0; + } else { DrainSatCurrent = here->BSIM4Adeff * model->BSIM4DjctTempSatCurDensity + here->BSIM4Pdeff * model->BSIM4DjctSidewallTempSatCurDensity @@ -819,8 +807,8 @@ for (; model != NULL; model = BSIM4nextModel(model)) * model->BSIM4DjctGateSidewallTempSatCurDensity; } - if (DrainSatCurrent <= 0.0) - { here->BSIM4gbd = ckt->CKTgmin; + if (DrainSatCurrent <= 0.0) + { here->BSIM4gbd = ckt->CKTgmin; here->BSIM4cbd = here->BSIM4gbd * vbd_jct; } else @@ -834,7 +822,7 @@ for (; model != NULL; model = BSIM4nextModel(model)) - T1 - 1.0) + ckt->CKTgmin * vbd_jct; break; case 1: - T2 = vbd_jct / Nvtmd; + T2 = vbd_jct / Nvtmd; if (T2 < -EXP_THRESHOLD) { here->BSIM4gbd = ckt->CKTgmin; here->BSIM4cbd = DrainSatCurrent * (MIN_EXP - 1.0) @@ -890,7 +878,7 @@ for (; model != NULL; model = BSIM4nextModel(model)) else { T2 = exp(-T1); T3 = -T2 /Nvtmd; - } + } here->BSIM4gbd = DrainSatCurrent * (devbd_dvb - model->BSIM4xjbvd * T3) + ckt->CKTgmin; here->BSIM4cbd = DrainSatCurrent * (evbd + here->BSIM4XExpBVD - 1.0 @@ -904,9 +892,9 @@ for (; model != NULL; model = BSIM4nextModel(model)) break; default: break; } - } + } - /* trap-assisted tunneling and recombination current for reverse bias */ + /* trap-assisted tunneling and recombination current for reverse bias */ Nvtmrssws = model->BSIM4vtm0 * model->BSIM4njtsswstemp; Nvtmrsswgs = model->BSIM4vtm0 * model->BSIM4njtsswgstemp; Nvtmrss = model->BSIM4vtm0 * model->BSIM4njtsstemp; @@ -915,10 +903,10 @@ for (; model != NULL; model = BSIM4nextModel(model)) Nvtmrsd = model->BSIM4vtm0 * model->BSIM4njtsdtemp; if ((model->BSIM4vtss - vbs_jct) < (model->BSIM4vtss * 1e-3)) - { T9 = 1.0e3; + { T9 = 1.0e3; T0 = - vbs_jct / Nvtmrss * T9; DEXP(T0, T1, T10); - dT1_dVb = T10 / Nvtmrss * T9; + dT1_dVb = T10 / Nvtmrss * T9; } else { T9 = 1.0 / (model->BSIM4vtss - vbs_jct); T0 = -vbs_jct / Nvtmrss * model->BSIM4vtss * T9; @@ -931,7 +919,7 @@ for (; model != NULL; model = BSIM4nextModel(model)) { T9 = 1.0e3; T0 = -vbd_jct / Nvtmrsd * T9; DEXP(T0, T2, T10); - dT2_dVb = T10 / Nvtmrsd * T9; + dT2_dVb = T10 / Nvtmrsd * T9; } else { T9 = 1.0 / (model->BSIM4vtsd - vbd_jct); T0 = -vbd_jct / Nvtmrsd * model->BSIM4vtsd * T9; @@ -941,10 +929,10 @@ for (; model != NULL; model = BSIM4nextModel(model)) } if ((model->BSIM4vtssws - vbs_jct) < (model->BSIM4vtssws * 1e-3) ) - { T9 = 1.0e3; + { T9 = 1.0e3; T0 = -vbs_jct / Nvtmrssws * T9; DEXP(T0, T3, T10); - dT3_dVb = T10 / Nvtmrssws * T9; + dT3_dVb = T10 / Nvtmrssws * T9; } else { T9 = 1.0 / (model->BSIM4vtssws - vbs_jct); T0 = -vbs_jct / Nvtmrssws * model->BSIM4vtssws * T9; @@ -954,10 +942,10 @@ for (; model != NULL; model = BSIM4nextModel(model)) } if ((model->BSIM4vtsswd - vbd_jct) < (model->BSIM4vtsswd * 1e-3) ) - { T9 = 1.0e3; + { T9 = 1.0e3; T0 = -vbd_jct / Nvtmrsswd * T9; DEXP(T0, T4, T10); - dT4_dVb = T10 / Nvtmrsswd * T9; + dT4_dVb = T10 / Nvtmrsswd * T9; } else { T9 = 1.0 / (model->BSIM4vtsswd - vbd_jct); T0 = -vbd_jct / Nvtmrsswd * model->BSIM4vtsswd * T9; @@ -967,10 +955,10 @@ for (; model != NULL; model = BSIM4nextModel(model)) } if ((model->BSIM4vtsswgs - vbs_jct) < (model->BSIM4vtsswgs * 1e-3) ) - { T9 = 1.0e3; + { T9 = 1.0e3; T0 = -vbs_jct / Nvtmrsswgs * T9; DEXP(T0, T5, T10); - dT5_dVb = T10 / Nvtmrsswgs * T9; + dT5_dVb = T10 / Nvtmrsswgs * T9; } else { T9 = 1.0 / (model->BSIM4vtsswgs - vbs_jct); T0 = -vbs_jct / Nvtmrsswgs * model->BSIM4vtsswgs * T9; @@ -980,10 +968,10 @@ for (; model != NULL; model = BSIM4nextModel(model)) } if ((model->BSIM4vtsswgd - vbd_jct) < (model->BSIM4vtsswgd * 1e-3) ) - { T9 = 1.0e3; + { T9 = 1.0e3; T0 = -vbd_jct / Nvtmrsswgd * T9; DEXP(T0, T6, T10); - dT6_dVb = T10 / Nvtmrsswgd * T9; + dT6_dVb = T10 / Nvtmrsswgd * T9; } else { T9 = 1.0 / (model->BSIM4vtsswgd - vbd_jct); T0 = -vbd_jct / Nvtmrsswgd * model->BSIM4vtsswgd * T9; @@ -992,79 +980,79 @@ for (; model != NULL; model = BSIM4nextModel(model)) dT6_dVb = T10 * dT0_dVb; } - here->BSIM4gbs += here->BSIM4SjctTempRevSatCur * dT1_dVb - + here->BSIM4SswTempRevSatCur * dT3_dVb - + here->BSIM4SswgTempRevSatCur * dT5_dVb; - here->BSIM4cbs -= here->BSIM4SjctTempRevSatCur * (T1 - 1.0) - + here->BSIM4SswTempRevSatCur * (T3 - 1.0) - + here->BSIM4SswgTempRevSatCur * (T5 - 1.0); - here->BSIM4gbd += here->BSIM4DjctTempRevSatCur * dT2_dVb - + here->BSIM4DswTempRevSatCur * dT4_dVb - + here->BSIM4DswgTempRevSatCur * dT6_dVb; - here->BSIM4cbd -= here->BSIM4DjctTempRevSatCur * (T2 - 1.0) - + here->BSIM4DswTempRevSatCur * (T4 - 1.0) - + here->BSIM4DswgTempRevSatCur * (T6 - 1.0); + here->BSIM4gbs += here->BSIM4SjctTempRevSatCur * dT1_dVb + + here->BSIM4SswTempRevSatCur * dT3_dVb + + here->BSIM4SswgTempRevSatCur * dT5_dVb; + here->BSIM4cbs -= here->BSIM4SjctTempRevSatCur * (T1 - 1.0) + + here->BSIM4SswTempRevSatCur * (T3 - 1.0) + + here->BSIM4SswgTempRevSatCur * (T5 - 1.0); + here->BSIM4gbd += here->BSIM4DjctTempRevSatCur * dT2_dVb + + here->BSIM4DswTempRevSatCur * dT4_dVb + + here->BSIM4DswgTempRevSatCur * dT6_dVb; + here->BSIM4cbd -= here->BSIM4DjctTempRevSatCur * (T2 - 1.0) + + here->BSIM4DswTempRevSatCur * (T4 - 1.0) + + here->BSIM4DswgTempRevSatCur * (T6 - 1.0); /* End of diode DC model */ if (vds >= 0.0) - { here->BSIM4mode = 1; + { here->BSIM4mode = 1; Vds = vds; Vgs = vgs; Vbs = vbs; - Vdb = vds - vbs; /* WDLiu: for GIDL */ + Vdb = vds - vbs; /* WDLiu: for GIDL */ } - else - { here->BSIM4mode = -1; + else + { here->BSIM4mode = -1; Vds = -vds; Vgs = vgd; Vbs = vbd; - Vdb = -vbs; + Vdb = -vbs; } - /* dunga */ - if(model->BSIM4mtrlMod) - { - epsrox = 3.9; - toxe = model->BSIM4eot; - epssub = EPS0 * model->BSIM4epsrsub; - } - else - { - epsrox = model->BSIM4epsrox; - toxe = model->BSIM4toxe; - epssub = EPSSI; - } + /* dunga */ + if(model->BSIM4mtrlMod) + { + epsrox = 3.9; + toxe = model->BSIM4eot; + epssub = EPS0 * model->BSIM4epsrsub; + } + else + { + epsrox = model->BSIM4epsrox; + toxe = model->BSIM4toxe; + epssub = EPSSI; + } - T0 = Vbs - here->BSIM4vbsc - 0.001; - T1 = sqrt(T0 * T0 - 0.004 * here->BSIM4vbsc); - if (T0 >= 0.0) - { Vbseff = here->BSIM4vbsc + 0.5 * (T0 + T1); + T0 = Vbs - here->BSIM4vbsc - 0.001; + T1 = sqrt(T0 * T0 - 0.004 * here->BSIM4vbsc); + if (T0 >= 0.0) + { Vbseff = here->BSIM4vbsc + 0.5 * (T0 + T1); dVbseff_dVb = 0.5 * (1.0 + T0 / T1); - } - else - { T2 = -0.002 / (T1 - T0); - Vbseff = here->BSIM4vbsc * (1.0 + T2); - dVbseff_dVb = T2 * here->BSIM4vbsc / T1; - } + } + else + { T2 = -0.002 / (T1 - T0); + Vbseff = here->BSIM4vbsc * (1.0 + T2); + dVbseff_dVb = T2 * here->BSIM4vbsc / T1; + } - /* JX: Correction to forward body bias */ - T9 = 0.95 * pParam->BSIM4phi; - T0 = T9 - Vbseff - 0.001; - T1 = sqrt(T0 * T0 + 0.004 * T9); - Vbseff = T9 - 0.5 * (T0 + T1); + /* JX: Correction to forward body bias */ + T9 = 0.95 * pParam->BSIM4phi; + T0 = T9 - Vbseff - 0.001; + T1 = sqrt(T0 * T0 + 0.004 * T9); + Vbseff = T9 - 0.5 * (T0 + T1); dVbseff_dVb *= 0.5 * (1.0 + T0 / T1); Phis = pParam->BSIM4phi - Vbseff; dPhis_dVb = -1.0; sqrtPhis = sqrt(Phis); - dsqrtPhis_dVb = -0.5 / sqrtPhis; + dsqrtPhis_dVb = -0.5 / sqrtPhis; Xdep = pParam->BSIM4Xdep0 * sqrtPhis / pParam->BSIM4sqrtPhi; dXdep_dVb = (pParam->BSIM4Xdep0 / pParam->BSIM4sqrtPhi) - * dsqrtPhis_dVb; + * dsqrtPhis_dVb; Leff = pParam->BSIM4leff; Vtm = model->BSIM4vtm; @@ -1076,27 +1064,27 @@ for (; model != NULL; model = BSIM4nextModel(model)) T0 = pParam->BSIM4dvt2 * Vbseff; if (T0 >= - 0.5) - { T1 = 1.0 + T0; - T2 = pParam->BSIM4dvt2; - } - else - { T4 = 1.0 / (3.0 + 8.0 * T0); - T1 = (1.0 + 3.0 * T0) * T4; - T2 = pParam->BSIM4dvt2 * T4 * T4; - } + { T1 = 1.0 + T0; + T2 = pParam->BSIM4dvt2; + } + else + { T4 = 1.0 / (3.0 + 8.0 * T0); + T1 = (1.0 + 3.0 * T0) * T4; + T2 = pParam->BSIM4dvt2 * T4 * T4; + } lt1 = model->BSIM4factor1 * T3 * T1; dlt1_dVb = model->BSIM4factor1 * (0.5 / T3 * T1 * dXdep_dVb + T3 * T2); T0 = pParam->BSIM4dvt2w * Vbseff; if (T0 >= - 0.5) - { T1 = 1.0 + T0; - T2 = pParam->BSIM4dvt2w; - } - else - { T4 = 1.0 / (3.0 + 8.0 * T0); - T1 = (1.0 + 3.0 * T0) * T4; - T2 = pParam->BSIM4dvt2w * T4 * T4; - } + { T1 = 1.0 + T0; + T2 = pParam->BSIM4dvt2w; + } + else + { T4 = 1.0 / (3.0 + 8.0 * T0); + T1 = (1.0 + 3.0 * T0) * T4; + T2 = pParam->BSIM4dvt2w * T4 * T4; + } ltw = model->BSIM4factor1 * T3 * T1; dltw_dVb = model->BSIM4factor1 * (0.5 / T3 * T1 * dXdep_dVb + T3 * T2); @@ -1125,7 +1113,7 @@ for (; model != NULL; model = BSIM4nextModel(model)) T3 = T2 * T2; T4 = T3 + 2.0 * T1 * MIN_EXP; T5 = T1 / T4; - dT1_dVb = -T0 * T1 * dltw_dVb / ltw; + dT1_dVb = -T0 * T1 * dltw_dVb / ltw; dT5_dVb = dT1_dVb * (T4 - 2.0 * T1 * (T2 + MIN_EXP)) / T4 / T4; } else @@ -1142,24 +1130,24 @@ for (; model != NULL; model = BSIM4nextModel(model)) + (pParam->BSIM4kt1 + pParam->BSIM4kt1l / Leff + pParam->BSIM4kt2 * Vbseff) * TempRatio; Vth_NarrowW = toxe * pParam->BSIM4phi - / (pParam->BSIM4weff + pParam->BSIM4w0); + / (pParam->BSIM4weff + pParam->BSIM4w0); - T3 = here->BSIM4eta0 + pParam->BSIM4etab * Vbseff; - if (T3 < 1.0e-4) - { T9 = 1.0 / (3.0 - 2.0e4 * T3); - T3 = (2.0e-4 - T3) * T9; - T4 = T9 * T9; - } - else - { T4 = 1.0; - } - dDIBL_Sft_dVd = T3 * pParam->BSIM4theta0vb0; + T3 = here->BSIM4eta0 + pParam->BSIM4etab * Vbseff; + if (T3 < 1.0e-4) + { T9 = 1.0 / (3.0 - 2.0e4 * T3); + T3 = (2.0e-4 - T3) * T9; + T4 = T9 * T9; + } + else + { T4 = 1.0; + } + dDIBL_Sft_dVd = T3 * pParam->BSIM4theta0vb0; DIBL_Sft = dDIBL_Sft_dVd * Vds; - Lpe_Vb = sqrt(1.0 + pParam->BSIM4lpeb / Leff); + Lpe_Vb = sqrt(1.0 + pParam->BSIM4lpeb / Leff); Vth = model->BSIM4type * here->BSIM4vth0 + (pParam->BSIM4k1ox * sqrtPhis - - pParam->BSIM4k1 * pParam->BSIM4sqrtPhi) * Lpe_Vb + - pParam->BSIM4k1 * pParam->BSIM4sqrtPhi) * Lpe_Vb - here->BSIM4k2ox * Vbseff - Delt_vth - T2 + (pParam->BSIM4k3 + pParam->BSIM4k3b * Vbseff) * Vth_NarrowW + T1 - DIBL_Sft; @@ -1172,30 +1160,30 @@ for (; model != NULL; model = BSIM4nextModel(model)) /* Calculate n */ tmp1 = epssub / Xdep; - here->BSIM4nstar = model->BSIM4vtm / Charge_q * (model->BSIM4coxe - + tmp1 + pParam->BSIM4cit); + here->BSIM4nstar = model->BSIM4vtm / Charge_q * (model->BSIM4coxe + + tmp1 + pParam->BSIM4cit); tmp2 = pParam->BSIM4nfactor * tmp1; tmp3 = pParam->BSIM4cdsc + pParam->BSIM4cdscb * Vbseff + pParam->BSIM4cdscd * Vds; - tmp4 = (tmp2 + tmp3 * Theta0 + pParam->BSIM4cit) / model->BSIM4coxe; - if (tmp4 >= -0.5) - { n = 1.0 + tmp4; - dn_dVb = (-tmp2 / Xdep * dXdep_dVb + tmp3 * dTheta0_dVb + tmp4 = (tmp2 + tmp3 * Theta0 + pParam->BSIM4cit) / model->BSIM4coxe; + if (tmp4 >= -0.5) + { n = 1.0 + tmp4; + dn_dVb = (-tmp2 / Xdep * dXdep_dVb + tmp3 * dTheta0_dVb + pParam->BSIM4cdscb * Theta0) / model->BSIM4coxe; dn_dVd = pParam->BSIM4cdscd * Theta0 / model->BSIM4coxe; - } - else - { T0 = 1.0 / (3.0 + 8.0 * tmp4); - n = (1.0 + 3.0 * tmp4) * T0; - T0 *= T0; - dn_dVb = (-tmp2 / Xdep * dXdep_dVb + tmp3 * dTheta0_dVb + } + else + { T0 = 1.0 / (3.0 + 8.0 * tmp4); + n = (1.0 + 3.0 * tmp4) * T0; + T0 *= T0; + dn_dVb = (-tmp2 / Xdep * dXdep_dVb + tmp3 * dTheta0_dVb + pParam->BSIM4cdscb * Theta0) / model->BSIM4coxe * T0; dn_dVd = pParam->BSIM4cdscd * Theta0 / model->BSIM4coxe * T0; - } + } /* Vth correction for Pocket implant */ - if (pParam->BSIM4dvtp0 > 0.0) + if (pParam->BSIM4dvtp0 > 0.0) { T0 = -pParam->BSIM4dvtp1 * Vds; if (T0 < -EXP_THRESHOLD) { T2 = MIN_EXP; @@ -1224,89 +1212,89 @@ for (; model != NULL; model = BSIM4nextModel(model)) Vth -= n * T4; dVth_dVd -= dDITS_Sft_dVd; dVth_dVb -= dDITS_Sft_dVb; - } - - /* v4.7 DITS_SFT2 */ - if ((pParam->BSIM4dvtp4 == 0.0) || (pParam->BSIM4dvtp2factor == 0.0)) { - T0 = 0.0; - DITS_Sft2 = 0.0; - } - else - { - //T0 = exp(2.0 * pParam->BSIM4dvtp4 * Vds); /* beta code */ - T1 = 2.0 * pParam->BSIM4dvtp4 * Vds; - DEXP(T1, T0, T10); - DITS_Sft2 = pParam->BSIM4dvtp2factor * (T0-1) / (T0+1); - //dDITS_Sft2_dVd = pParam->BSIM4dvtp2factor * pParam->BSIM4dvtp4 * 4.0 * T0 / ((T0+1) * (T0+1)); /* beta code */ - dDITS_Sft2_dVd = pParam->BSIM4dvtp2factor * pParam->BSIM4dvtp4 * 4.0 * T10 / ((T0+1) * (T0+1)); - Vth -= DITS_Sft2; - dVth_dVd -= dDITS_Sft2_dVd; - } - - + } + + /* v4.7 DITS_SFT2 */ + if ((pParam->BSIM4dvtp4 == 0.0) || (pParam->BSIM4dvtp2factor == 0.0)) { + T0 = 0.0; + DITS_Sft2 = 0.0; + } + else + { + //T0 = exp(2.0 * pParam->BSIM4dvtp4 * Vds); /* beta code */ + T1 = 2.0 * pParam->BSIM4dvtp4 * Vds; + DEXP(T1, T0, T10); + DITS_Sft2 = pParam->BSIM4dvtp2factor * (T0-1) / (T0+1); + //dDITS_Sft2_dVd = pParam->BSIM4dvtp2factor * pParam->BSIM4dvtp4 * 4.0 * T0 / ((T0+1) * (T0+1)); /* beta code */ + dDITS_Sft2_dVd = pParam->BSIM4dvtp2factor * pParam->BSIM4dvtp4 * 4.0 * T10 / ((T0+1) * (T0+1)); + Vth -= DITS_Sft2; + dVth_dVd -= dDITS_Sft2_dVd; + } + + here->BSIM4von = Vth; - + /* Poly Gate Si Depletion Effect */ - T0 = here->BSIM4vfb + pParam->BSIM4phi; - if(model->BSIM4mtrlMod == 0) - T1 = EPSSI; - else - T1 = model->BSIM4epsrgate * EPS0; + T0 = here->BSIM4vfb + pParam->BSIM4phi; + if(model->BSIM4mtrlMod == 0) + T1 = EPSSI; + else + T1 = model->BSIM4epsrgate * EPS0; - BSIM4polyDepletion(T0, pParam->BSIM4ngate, T1, model->BSIM4coxe, vgs, &vgs_eff, &dvgs_eff_dvg); + BSIM4polyDepletion(T0, pParam->BSIM4ngate, T1, model->BSIM4coxe, vgs, &vgs_eff, &dvgs_eff_dvg); - BSIM4polyDepletion(T0, pParam->BSIM4ngate, T1, model->BSIM4coxe, vgd, &vgd_eff, &dvgd_eff_dvg); - - if(here->BSIM4mode>0) { - Vgs_eff = vgs_eff; - dVgs_eff_dVg = dvgs_eff_dvg; - } else { - Vgs_eff = vgd_eff; - dVgs_eff_dVg = dvgd_eff_dvg; - } - here->BSIM4vgs_eff = vgs_eff; - here->BSIM4vgd_eff = vgd_eff; - here->BSIM4dvgs_eff_dvg = dvgs_eff_dvg; - here->BSIM4dvgd_eff_dvg = dvgd_eff_dvg; + BSIM4polyDepletion(T0, pParam->BSIM4ngate, T1, model->BSIM4coxe, vgd, &vgd_eff, &dvgd_eff_dvg); + + if(here->BSIM4mode>0) { + Vgs_eff = vgs_eff; + dVgs_eff_dVg = dvgs_eff_dvg; + } else { + Vgs_eff = vgd_eff; + dVgs_eff_dVg = dvgd_eff_dvg; + } + here->BSIM4vgs_eff = vgs_eff; + here->BSIM4vgd_eff = vgd_eff; + here->BSIM4dvgs_eff_dvg = dvgs_eff_dvg; + here->BSIM4dvgd_eff_dvg = dvgd_eff_dvg; Vgst = Vgs_eff - Vth; - /* Calculate Vgsteff */ - T0 = n * Vtm; - T1 = pParam->BSIM4mstar * Vgst; - T2 = T1 / T0; - if (T2 > EXP_THRESHOLD) - { T10 = T1; - dT10_dVg = pParam->BSIM4mstar * dVgs_eff_dVg; + /* Calculate Vgsteff */ + T0 = n * Vtm; + T1 = pParam->BSIM4mstar * Vgst; + T2 = T1 / T0; + if (T2 > EXP_THRESHOLD) + { T10 = T1; + dT10_dVg = pParam->BSIM4mstar * dVgs_eff_dVg; dT10_dVd = -dVth_dVd * pParam->BSIM4mstar; dT10_dVb = -dVth_dVb * pParam->BSIM4mstar; - } - else if (T2 < -EXP_THRESHOLD) - { T10 = Vtm * log(1.0 + MIN_EXP); + } + else if (T2 < -EXP_THRESHOLD) + { T10 = Vtm * log(1.0 + MIN_EXP); dT10_dVg = 0.0; dT10_dVd = T10 * dn_dVd; dT10_dVb = T10 * dn_dVb; - T10 *= n; - } - else - { ExpVgst = exp(T2); - T3 = Vtm * log(1.0 + ExpVgst); + T10 *= n; + } + else + { ExpVgst = exp(T2); + T3 = Vtm * log(1.0 + ExpVgst); T10 = n * T3; dT10_dVg = pParam->BSIM4mstar * ExpVgst / (1.0 + ExpVgst); dT10_dVb = T3 * dn_dVb - dT10_dVg * (dVth_dVb + Vgst * dn_dVb / n); dT10_dVd = T3 * dn_dVd - dT10_dVg * (dVth_dVd + Vgst * dn_dVd / n); - dT10_dVg *= dVgs_eff_dVg; - } + dT10_dVg *= dVgs_eff_dVg; + } - T1 = pParam->BSIM4voffcbn - (1.0 - pParam->BSIM4mstar) * Vgst; - T2 = T1 / T0; + T1 = pParam->BSIM4voffcbn - (1.0 - pParam->BSIM4mstar) * Vgst; + T2 = T1 / T0; if (T2 < -EXP_THRESHOLD) { T3 = model->BSIM4coxe * MIN_EXP / pParam->BSIM4cdep0; - T9 = pParam->BSIM4mstar + T3 * n; + T9 = pParam->BSIM4mstar + T3 * n; dT9_dVg = 0.0; dT9_dVd = dn_dVd * T3; dT9_dVb = dn_dVb * T3; @@ -1320,9 +1308,9 @@ for (; model != NULL; model = BSIM4nextModel(model)) } else { ExpVgst = exp(T2); - T3 = model->BSIM4coxe / pParam->BSIM4cdep0; - T4 = T3 * ExpVgst; - T5 = T1 * T4 / T0; + T3 = model->BSIM4coxe / pParam->BSIM4cdep0; + T4 = T3 * ExpVgst; + T5 = T1 * T4 / T0; T9 = pParam->BSIM4mstar + n * T4; dT9_dVg = T3 * (pParam->BSIM4mstar - 1.0) * ExpVgst / Vtm; dT9_dVb = T4 * dn_dVb - dT9_dVg * dVth_dVb - T5 * dn_dVb; @@ -1330,112 +1318,134 @@ for (; model != NULL; model = BSIM4nextModel(model)) dT9_dVg *= dVgs_eff_dVg; } here->BSIM4Vgsteff = Vgsteff = T10 / T9; - T11 = T9 * T9; + T11 = T9 * T9; dVgsteff_dVg = (T9 * dT10_dVg - T10 * dT9_dVg) / T11; dVgsteff_dVd = (T9 * dT10_dVd - T10 * dT9_dVd) / T11; dVgsteff_dVb = (T9 * dT10_dVb - T10 * dT9_dVb) / T11; /* Calculate Effective Channel Geometry */ T9 = sqrtPhis - pParam->BSIM4sqrtPhi; - Weff = pParam->BSIM4weff - 2.0 * (pParam->BSIM4dwg * Vgsteff - + pParam->BSIM4dwb * T9); + Weff = pParam->BSIM4weff - 2.0 * (pParam->BSIM4dwg * Vgsteff + + pParam->BSIM4dwb * T9); dWeff_dVg = -2.0 * pParam->BSIM4dwg; dWeff_dVb = -2.0 * pParam->BSIM4dwb * dsqrtPhis_dVb; if (Weff < 2.0e-8) /* to avoid the discontinuity problem due to Weff*/ - { T0 = 1.0 / (6.0e-8 - 2.0 * Weff); - Weff = 2.0e-8 * (4.0e-8 - Weff) * T0; - T0 *= T0 * 4.0e-16; + { T0 = 1.0 / (6.0e-8 - 2.0 * Weff); + Weff = 2.0e-8 * (4.0e-8 - Weff) * T0; + T0 *= T0 * 4.0e-16; dWeff_dVg *= T0; - dWeff_dVb *= T0; + dWeff_dVb *= T0; } - if (model->BSIM4rdsMod == 1) - Rds = dRds_dVg = dRds_dVb = 0.0; + if (model->BSIM4rdsMod == 1) + Rds = dRds_dVg = dRds_dVb = 0.0; else { T0 = 1.0 + pParam->BSIM4prwg * Vgsteff; - dT0_dVg = -pParam->BSIM4prwg / T0 / T0; - T1 = pParam->BSIM4prwb * T9; - dT1_dVb = pParam->BSIM4prwb * dsqrtPhis_dVb; + dT0_dVg = -pParam->BSIM4prwg / T0 / T0; + T1 = pParam->BSIM4prwb * T9; + dT1_dVb = pParam->BSIM4prwb * dsqrtPhis_dVb; - T2 = 1.0 / T0 + T1; - T3 = T2 + sqrt(T2 * T2 + 0.01); /* 0.01 = 4.0 * 0.05 * 0.05 */ - dT3_dVg = 1.0 + T2 / (T3 - T2); - dT3_dVb = dT3_dVg * dT1_dVb; - dT3_dVg *= dT0_dVg; + T2 = 1.0 / T0 + T1; + T3 = T2 + sqrt(T2 * T2 + 0.01); /* 0.01 = 4.0 * 0.05 * 0.05 */ + dT3_dVg = 1.0 + T2 / (T3 - T2); + dT3_dVb = dT3_dVg * dT1_dVb; + dT3_dVg *= dT0_dVg; - T4 = pParam->BSIM4rds0 * 0.5; - Rds = pParam->BSIM4rdswmin + T3 * T4; + T4 = pParam->BSIM4rds0 * 0.5; + Rds = pParam->BSIM4rdswmin + T3 * T4; dRds_dVg = T4 * dT3_dVg; dRds_dVb = T4 * dT3_dVb; - if (Rds > 0.0) - here->BSIM4grdsw = 1.0 / Rds* here->BSIM4nf; /*4.6.2*/ - else + if (Rds > 0.0) + here->BSIM4grdsw = 1.0 / Rds* here->BSIM4nf; /*4.6.2*/ + else here->BSIM4grdsw = 0.0; } - + /* Calculate Abulk */ - T9 = 0.5 * pParam->BSIM4k1ox * Lpe_Vb / sqrtPhis; + T9 = 0.5 * pParam->BSIM4k1ox * Lpe_Vb / sqrtPhis; T1 = T9 + here->BSIM4k2ox - pParam->BSIM4k3b * Vth_NarrowW; dT1_dVb = -T9 / sqrtPhis * dsqrtPhis_dVb; T9 = sqrt(pParam->BSIM4xj * Xdep); tmp1 = Leff + 2.0 * T9; - T5 = Leff / tmp1; + T5 = Leff / tmp1; tmp2 = pParam->BSIM4a0 * T5; - tmp3 = pParam->BSIM4weff + pParam->BSIM4b1; + tmp3 = pParam->BSIM4weff + pParam->BSIM4b1; tmp4 = pParam->BSIM4b0 / tmp3; T2 = tmp2 + tmp4; dT2_dVb = -T9 / tmp1 / Xdep * dXdep_dVb; T6 = T5 * T5; T7 = T5 * T6; - Abulk0 = 1.0 + T1 * T2; + Abulk0 = 1.0 + T1 * T2; dAbulk0_dVb = T1 * tmp2 * dT2_dVb + T2 * dT1_dVb; T8 = pParam->BSIM4ags * pParam->BSIM4a0 * T7; dAbulk_dVg = -T1 * T8; - Abulk = Abulk0 + dAbulk_dVg * Vgsteff; + Abulk = Abulk0 + dAbulk_dVg * Vgsteff; dAbulk_dVb = dAbulk0_dVb - T8 * Vgsteff * (dT1_dVb - + 3.0 * T1 * dT2_dVb); + + 3.0 * T1 * dT2_dVb); if (Abulk0 < 0.1) /* added to avoid the problems caused by Abulk0 */ - { T9 = 1.0 / (3.0 - 20.0 * Abulk0); - Abulk0 = (0.2 - Abulk0) * T9; - dAbulk0_dVb *= T9 * T9; - } + { T9 = 1.0 / (3.0 - 20.0 * Abulk0); + Abulk0 = (0.2 - Abulk0) * T9; + dAbulk0_dVb *= T9 * T9; + } if (Abulk < 0.1) - { T9 = 1.0 / (3.0 - 20.0 * Abulk); - Abulk = (0.2 - Abulk) * T9; + { T9 = 1.0 / (3.0 - 20.0 * Abulk); + Abulk = (0.2 - Abulk) * T9; T10 = T9 * T9; - dAbulk_dVb *= T10; + dAbulk_dVb *= T10; dAbulk_dVg *= T10; - } - here->BSIM4Abulk = Abulk; + } + here->BSIM4Abulk = Abulk; T2 = pParam->BSIM4keta * Vbseff; + if (T2 >= -0.9) + { T0 = 1.0 / (1.0 + T2); + dT0_dVb = -pParam->BSIM4keta * T0 * T0; + } + else + { T1 = 1.0 / (0.8 + T2); + T0 = (17.0 + 20.0 * T2) * T1; + dT0_dVb = -pParam->BSIM4keta * T1 * T1; + } + + dAbulk_dVg *= T0; + dAbulk_dVb = dAbulk_dVb * T0 + Abulk * dT0_dVb; + dAbulk0_Q_dVb = dAbulk0_dVb; // copy before scaling + dAbulk0_dVb = dAbulk0_dVb * T0 + Abulk0 * dT0_dVb; + Abulk *= T0; + Abulk0_Q = Abulk0; // copy before scaling + Abulk0 *= T0; + + /* Calculate Abulk0_Q */ + if (pParam->BSIM4ketac != pParam->BSIM4keta) { + T2 = pParam->BSIM4ketac * Vbseff; if (T2 >= -0.9) { T0 = 1.0 / (1.0 + T2); - dT0_dVb = -pParam->BSIM4keta * T0 * T0; + dT0_dVb = -pParam->BSIM4ketac * T0 * T0; } else { T1 = 1.0 / (0.8 + T2); T0 = (17.0 + 20.0 * T2) * T1; - dT0_dVb = -pParam->BSIM4keta * T1 * T1; + dT0_dVb = -pParam->BSIM4ketac * T1 * T1; } - dAbulk_dVg *= T0; - dAbulk_dVb = dAbulk_dVb * T0 + Abulk * dT0_dVb; - dAbulk0_dVb = dAbulk0_dVb * T0 + Abulk0 * dT0_dVb; - Abulk *= T0; - Abulk0 *= T0; + dAbulk0_Q_dVb = dAbulk0_Q_dVb * T0 + Abulk0_Q * dT0_dVb; + Abulk0_Q *= T0; + } else { + dAbulk0_Q_dVb = dAbulk0_dVb; + Abulk0_Q = Abulk0; + } /* Mobility calculation */ - if (model->BSIM4mtrlMod && model->BSIM4mtrlCompatMod == 0) - T14 = 2.0 * model->BSIM4type *(model->BSIM4phig - model->BSIM4easub - 0.5*model->BSIM4Eg0 + 0.45); - else - T14 = 0.0; + if (model->BSIM4mtrlMod && model->BSIM4mtrlCompatMod == 0) + T14 = 2.0 * model->BSIM4type *(model->BSIM4phig - model->BSIM4easub - 0.5*model->BSIM4Eg0 + 0.45); + else + T14 = 0.0; if (model->BSIM4mobMod == 0) { T0 = Vgsteff + Vth + Vth - T14; @@ -1493,8 +1503,8 @@ for (; model != NULL; model = BSIM4nextModel(model)) dDenomi_dVd = T13 * dVth_dVd; dDenomi_dVb = T13 * dVth_dVb + T1 * pParam->BSIM4uc; } - else if (model->BSIM4mobMod == 4) /* Synopsys 08/30/2013 add */ - { + else if (model->BSIM4mobMod == 4) /* Synopsys 08/30/2013 add */ + { T0 = Vgsteff + here->BSIM4vtfbphi1 - T14; T2 = pParam->BSIM4ua + pParam->BSIM4uc * Vbseff; T3 = T0 / toxe; @@ -1509,9 +1519,9 @@ for (; model != NULL; model = BSIM4nextModel(model)) dDenomi_dVd = 0.0; dDenomi_dVb = pParam->BSIM4uc * T3; dDenomi_dVg+= T7; - } - else if (model->BSIM4mobMod == 5) /* Synopsys 08/30/2013 add */ - { + } + else if (model->BSIM4mobMod == 5) /* Synopsys 08/30/2013 add */ + { T0 = Vgsteff + here->BSIM4vtfbphi1 - T14; T2 = 1.0 + pParam->BSIM4uc * Vbseff; T3 = T0 / toxe; @@ -1528,7 +1538,7 @@ for (; model != NULL; model = BSIM4nextModel(model)) dDenomi_dVd = 0.0; dDenomi_dVb = pParam->BSIM4uc * T4; dDenomi_dVg+= T7; - } + } else if (model->BSIM4mobMod == 6) /* Synopsys 08/30/2013 modify */ { T0 = (Vgsteff + here->BSIM4vtfbphi1) / toxe; T1 = exp(pParam->BSIM4eu * log(T0)); @@ -1547,57 +1557,57 @@ for (; model != NULL; model = BSIM4nextModel(model)) dDenomi_dVb = T1 * pParam->BSIM4uc; } - /*high K mobility*/ - else - { - - - /*univsersal mobility*/ - T0 = (Vgsteff + here->BSIM4vtfbphi1)* 1.0e-8 / toxe/6.0; - T1 = exp(pParam->BSIM4eu * log(T0)); - dT1_dVg = T1 * pParam->BSIM4eu * 1.0e-8/ T0 / toxe/6.0; - T2 = pParam->BSIM4ua + pParam->BSIM4uc * Vbseff; - - /*Coulombic*/ - VgsteffVth = pParam->BSIM4VgsteffVth; - - T10 = exp(pParam->BSIM4ucs * log(0.5 + 0.5 * Vgsteff/VgsteffVth)); - T11 = pParam->BSIM4ud/T10; - dT11_dVg = - 0.5 * pParam->BSIM4ucs * T11 /(0.5 + 0.5*Vgsteff/VgsteffVth)/VgsteffVth; - - dDenomi_dVg = T2 * dT1_dVg + dT11_dVg; - dDenomi_dVd = 0.0; - dDenomi_dVb = T1 * pParam->BSIM4uc; - - T5 = T1 * T2 + T11; - } + /*high K mobility*/ + else + { - - - - - if (T5 >= -0.8) - { Denomi = 1.0 + T5; - } - else - { T9 = 1.0 / (7.0 + 10.0 * T5); - Denomi = (0.6 + T5) * T9; - T9 *= T9; + + /*univsersal mobility*/ + T0 = (Vgsteff + here->BSIM4vtfbphi1)* 1.0e-8 / toxe/6.0; + T1 = exp(pParam->BSIM4eu * log(T0)); + dT1_dVg = T1 * pParam->BSIM4eu * 1.0e-8/ T0 / toxe/6.0; + T2 = pParam->BSIM4ua + pParam->BSIM4uc * Vbseff; + + /*Coulombic*/ + VgsteffVth = pParam->BSIM4VgsteffVth; + + T10 = exp(pParam->BSIM4ucs * log(0.5 + 0.5 * Vgsteff/VgsteffVth)); + T11 = pParam->BSIM4ud/T10; + dT11_dVg = - 0.5 * pParam->BSIM4ucs * T11 /(0.5 + 0.5*Vgsteff/VgsteffVth)/VgsteffVth; + + dDenomi_dVg = T2 * dT1_dVg + dT11_dVg; + dDenomi_dVd = 0.0; + dDenomi_dVb = T1 * pParam->BSIM4uc; + + T5 = T1 * T2 + T11; + } + + + + + + if (T5 >= -0.8) + { Denomi = 1.0 + T5; + } + else + { T9 = 1.0 / (7.0 + 10.0 * T5); + Denomi = (0.6 + T5) * T9; + T9 *= T9; dDenomi_dVg *= T9; dDenomi_dVd *= T9; dDenomi_dVb *= T9; - } - - + } + + here->BSIM4ueff = ueff = here->BSIM4u0temp / Denomi; - T9 = -ueff / Denomi; + T9 = -ueff / Denomi; dueff_dVg = T9 * dDenomi_dVg; dueff_dVd = T9 * dDenomi_dVd; dueff_dVb = T9 * dDenomi_dVb; /* Saturation Drain Voltage Vdsat */ WVCox = Weff * here->BSIM4vsattemp * model->BSIM4coxe; - WVCoxRds = WVCox * Rds; + WVCoxRds = WVCox * Rds; Esat = 2.0 * here->BSIM4vsattemp / ueff; here->BSIM4EsatL = EsatL = Esat * Leff; @@ -1605,26 +1615,26 @@ for (; model != NULL; model = BSIM4nextModel(model)) dEsatL_dVg = T0 * dueff_dVg; dEsatL_dVd = T0 * dueff_dVd; dEsatL_dVb = T0 * dueff_dVb; - - /* Sqrt() */ + + /* Sqrt() */ a1 = pParam->BSIM4a1; - if (a1 == 0.0) - { Lambda = pParam->BSIM4a2; - dLambda_dVg = 0.0; - } - else if (a1 > 0.0) - { T0 = 1.0 - pParam->BSIM4a2; - T1 = T0 - pParam->BSIM4a1 * Vgsteff - 0.0001; - T2 = sqrt(T1 * T1 + 0.0004 * T0); - Lambda = pParam->BSIM4a2 + T0 - 0.5 * (T1 + T2); - dLambda_dVg = 0.5 * pParam->BSIM4a1 * (1.0 + T1 / T2); - } - else - { T1 = pParam->BSIM4a2 + pParam->BSIM4a1 * Vgsteff - 0.0001; - T2 = sqrt(T1 * T1 + 0.0004 * pParam->BSIM4a2); - Lambda = 0.5 * (T1 + T2); - dLambda_dVg = 0.5 * pParam->BSIM4a1 * (1.0 + T1 / T2); - } + if (a1 == 0.0) + { Lambda = pParam->BSIM4a2; + dLambda_dVg = 0.0; + } + else if (a1 > 0.0) + { T0 = 1.0 - pParam->BSIM4a2; + T1 = T0 - pParam->BSIM4a1 * Vgsteff - 0.0001; + T2 = sqrt(T1 * T1 + 0.0004 * T0); + Lambda = pParam->BSIM4a2 + T0 - 0.5 * (T1 + T2); + dLambda_dVg = 0.5 * pParam->BSIM4a1 * (1.0 + T1 / T2); + } + else + { T1 = pParam->BSIM4a2 + pParam->BSIM4a1 * Vgsteff - 0.0001; + T2 = sqrt(T1 * T1 + 0.0004 * pParam->BSIM4a2); + Lambda = 0.5 * (T1 + T2); + dLambda_dVg = 0.5 * pParam->BSIM4a1 * (1.0 + T1 / T2); + } Vgst2Vtm = Vgsteff + 2.0 * Vtm; if (Rds > 0) @@ -1634,48 +1644,48 @@ for (; model != NULL; model = BSIM4nextModel(model)) else { tmp2 = dWeff_dVg / Weff; tmp3 = dWeff_dVb / Weff; - } + } if ((Rds == 0.0) && (Lambda == 1.0)) { T0 = 1.0 / (Abulk * EsatL + Vgst2Vtm); tmp1 = 0.0; - T1 = T0 * T0; - T2 = Vgst2Vtm * T0; + T1 = T0 * T0; + T2 = Vgst2Vtm * T0; T3 = EsatL * Vgst2Vtm; Vdsat = T3 * T0; - + dT0_dVg = -(Abulk * dEsatL_dVg + EsatL * dAbulk_dVg + 1.0) * T1; - dT0_dVd = -(Abulk * dEsatL_dVd) * T1; - dT0_dVb = -(Abulk * dEsatL_dVb + dAbulk_dVb * EsatL) * T1; + dT0_dVd = -(Abulk * dEsatL_dVd) * T1; + dT0_dVb = -(Abulk * dEsatL_dVb + dAbulk_dVb * EsatL) * T1; dVdsat_dVg = T3 * dT0_dVg + T2 * dEsatL_dVg + EsatL * T0; dVdsat_dVd = T3 * dT0_dVd + T2 * dEsatL_dVd; - dVdsat_dVb = T3 * dT0_dVb + T2 * dEsatL_dVb; + dVdsat_dVb = T3 * dT0_dVb + T2 * dEsatL_dVb; } else { tmp1 = dLambda_dVg / (Lambda * Lambda); T9 = Abulk * WVCoxRds; - T8 = Abulk * T9; - T7 = Vgst2Vtm * T9; + T8 = Abulk * T9; + T7 = Vgst2Vtm * T9; T6 = Vgst2Vtm * WVCoxRds; - T0 = 2.0 * Abulk * (T9 - 1.0 + 1.0 / Lambda); + T0 = 2.0 * Abulk * (T9 - 1.0 + 1.0 / Lambda); dT0_dVg = 2.0 * (T8 * tmp2 - Abulk * tmp1 - + (2.0 * T9 + 1.0 / Lambda - 1.0) * dAbulk_dVg); - + + (2.0 * T9 + 1.0 / Lambda - 1.0) * dAbulk_dVg); + dT0_dVb = 2.0 * (T8 * (2.0 / Abulk * dAbulk_dVb + tmp3) - + (1.0 / Lambda - 1.0) * dAbulk_dVb); - dT0_dVd = 0.0; + + (1.0 / Lambda - 1.0) * dAbulk_dVb); + dT0_dVd = 0.0; T1 = Vgst2Vtm * (2.0 / Lambda - 1.0) + Abulk * EsatL + 3.0 * T7; - + dT1_dVg = (2.0 / Lambda - 1.0) - 2.0 * Vgst2Vtm * tmp1 - + Abulk * dEsatL_dVg + EsatL * dAbulk_dVg + 3.0 * (T9 - + T7 * tmp2 + T6 * dAbulk_dVg); + + Abulk * dEsatL_dVg + EsatL * dAbulk_dVg + 3.0 * (T9 + + T7 * tmp2 + T6 * dAbulk_dVg); dT1_dVb = Abulk * dEsatL_dVb + EsatL * dAbulk_dVb - + 3.0 * (T6 * dAbulk_dVb + T7 * tmp3); + + 3.0 * (T6 * dAbulk_dVb + T7 * tmp3); dT1_dVd = Abulk * dEsatL_dVd; T2 = Vgst2Vtm * (EsatL + 2.0 * T6); dT2_dVg = EsatL + Vgst2Vtm * dEsatL_dVg - + T6 * (4.0 + 2.0 * Vgst2Vtm * tmp2); + + T6 * (4.0 + 2.0 * Vgst2Vtm * tmp2); dT2_dVb = Vgst2Vtm * (dEsatL_dVb + 2.0 * T6 * tmp3); dT2_dVd = Vgst2Vtm * dEsatL_dVd; @@ -1683,16 +1693,16 @@ for (; model != NULL; model = BSIM4nextModel(model)) Vdsat = (T1 - T3) / T0; dT3_dVg = (T1 * dT1_dVg - 2.0 * (T0 * dT2_dVg + T2 * dT0_dVg)) - / T3; + / T3; dT3_dVd = (T1 * dT1_dVd - 2.0 * (T0 * dT2_dVd + T2 * dT0_dVd)) - / T3; + / T3; dT3_dVb = (T1 * dT1_dVb - 2.0 * (T0 * dT2_dVb + T2 * dT0_dVb)) - / T3; + / T3; dVdsat_dVg = (dT1_dVg - (T1 * dT1_dVg - dT0_dVg * T2 - - T0 * dT2_dVg) / T3 - Vdsat * dT0_dVg) / T0; + - T0 * dT2_dVg) / T3 - Vdsat * dT0_dVg) / T0; dVdsat_dVb = (dT1_dVb - (T1 * dT1_dVb - dT0_dVb * T2 - - T0 * dT2_dVb) / T3 - Vdsat * dT0_dVb) / T0; + - T0 * dT2_dVb) / T3 - Vdsat * dT0_dVb) / T0; dVdsat_dVd = (dT1_dVd - (T1 * dT1_dVd - T0 * dT2_dVd) / T3) / T0; } here->BSIM4vdsat = Vdsat; @@ -1704,43 +1714,43 @@ for (; model != NULL; model = BSIM4nextModel(model)) dT1_dVb = dVdsat_dVb; T2 = sqrt(T1 * T1 + 4.0 * pParam->BSIM4delta * Vdsat); - T0 = T1 / T2; - T9 = 2.0 * pParam->BSIM4delta; - T3 = T9 / T2; + T0 = T1 / T2; + T9 = 2.0 * pParam->BSIM4delta; + T3 = T9 / T2; dT2_dVg = T0 * dT1_dVg + T3 * dVdsat_dVg; dT2_dVd = T0 * dT1_dVd + T3 * dVdsat_dVd; dT2_dVb = T0 * dT1_dVb + T3 * dVdsat_dVb; - if (T1 >= 0.0) - { Vdseff = Vdsat - 0.5 * (T1 + T2); - dVdseff_dVg = dVdsat_dVg - 0.5 * (dT1_dVg + dT2_dVg); + if (T1 >= 0.0) + { Vdseff = Vdsat - 0.5 * (T1 + T2); + dVdseff_dVg = dVdsat_dVg - 0.5 * (dT1_dVg + dT2_dVg); dVdseff_dVd = dVdsat_dVd - 0.5 * (dT1_dVd + dT2_dVd); dVdseff_dVb = dVdsat_dVb - 0.5 * (dT1_dVb + dT2_dVb); - } - else - { T4 = T9 / (T2 - T1); - T5 = 1.0 - T4; - T6 = Vdsat * T4 / (T2 - T1); - Vdseff = Vdsat * T5; + } + else + { T4 = T9 / (T2 - T1); + T5 = 1.0 - T4; + T6 = Vdsat * T4 / (T2 - T1); + Vdseff = Vdsat * T5; dVdseff_dVg = dVdsat_dVg * T5 + T6 * (dT2_dVg - dT1_dVg); dVdseff_dVd = dVdsat_dVd * T5 + T6 * (dT2_dVd - dT1_dVd); dVdseff_dVb = dVdsat_dVb * T5 + T6 * (dT2_dVb - dT1_dVb); - } + } if (Vds == 0.0) { Vdseff = 0.0; dVdseff_dVg = 0.0; - dVdseff_dVb = 0.0; + dVdseff_dVb = 0.0; } if (Vdseff > Vds) Vdseff = Vds; diffVds = Vds - Vdseff; here->BSIM4Vdseff = Vdseff; - + /* Velocity Overshoot */ if((model->BSIM4lambdaGiven) && (model->BSIM4lambda > 0.0) ) - { + { T1 = Leff * ueff; T2 = pParam->BSIM4lambda / T1; T3 = -T2 / T1 * Leff; @@ -1750,8 +1760,8 @@ for (; model != NULL; model = BSIM4nextModel(model)) T5 = 1.0 / (Esat * pParam->BSIM4litl); T4 = -T5 / EsatL; dT5_dVg = dEsatL_dVg * T4; - dT5_dVd = dEsatL_dVd * T4; - dT5_dVb = dEsatL_dVb * T4; + dT5_dVd = dEsatL_dVd * T4; + dT5_dVb = dEsatL_dVb * T4; T6 = 1.0 + diffVds * T5; dT6_dVg = dT5_dVg * diffVds - dVdseff_dVg * T5; dT6_dVd = dT5_dVd * diffVds + (1.0 - dVdseff_dVd) * T5; @@ -1783,20 +1793,20 @@ for (; model != NULL; model = BSIM4nextModel(model)) /* Calculate Vasat */ tmp4 = 1.0 - 0.5 * Abulk * Vdsat / Vgst2Vtm; T9 = WVCoxRds * Vgsteff; - T8 = T9 / Vgst2Vtm; + T8 = T9 / Vgst2Vtm; T0 = EsatL + Vdsat + 2.0 * T9 * tmp4; - + T7 = 2.0 * WVCoxRds * tmp4; dT0_dVg = dEsatL_dVg + dVdsat_dVg + T7 * (1.0 + tmp2 * Vgsteff) - - T8 * (Abulk * dVdsat_dVg - Abulk * Vdsat / Vgst2Vtm - + Vdsat * dAbulk_dVg); - + - T8 * (Abulk * dVdsat_dVg - Abulk * Vdsat / Vgst2Vtm + + Vdsat * dAbulk_dVg); + dT0_dVb = dEsatL_dVb + dVdsat_dVb + T7 * tmp3 * Vgsteff - - T8 * (dAbulk_dVb * Vdsat + Abulk * dVdsat_dVb); + - T8 * (dAbulk_dVb * Vdsat + Abulk * dVdsat_dVb); dT0_dVd = dEsatL_dVd + dVdsat_dVd - T8 * Abulk * dVdsat_dVd; - T9 = WVCoxRds * Abulk; - T1 = 2.0 / Lambda - 1.0 + T9; + T9 = WVCoxRds * Abulk; + T1 = 2.0 / Lambda - 1.0 + T9; dT1_dVg = -2.0 * tmp1 + WVCoxRds * (Abulk * tmp2 + dAbulk_dVg); dT1_dVb = dAbulk_dVb * WVCoxRds + T9 * tmp3; @@ -1805,8 +1815,8 @@ for (; model != NULL; model = BSIM4nextModel(model)) dVasat_dVb = (dT0_dVb - Vasat * dT1_dVb) / T1; dVasat_dVd = dT0_dVd / T1; - /* Calculate Idl first */ - + /* Calculate Idl first */ + tmp1 = here->BSIM4vtfbphi2; tmp2 = 2.0e8 * here->BSIM4toxp; dT0_dVg = 1.0 / tmp2; @@ -1820,7 +1830,7 @@ for (; model != NULL; model = BSIM4nextModel(model)) Coxeff = epssub * here->BSIM4coxp / (epssub + here->BSIM4coxp * Tcen); - here->BSIM4Coxeff = Coxeff; + here->BSIM4Coxeff = Coxeff; dCoxeff_dVg = -Coxeff * Coxeff * dTcen_dVg / epssub; CoxeffWovL = Coxeff * Weff / Leff; @@ -1868,15 +1878,15 @@ for (; model != NULL; model = BSIM4nextModel(model)) /* Calculate degradation factor due to pocket implant */ - if (pParam->BSIM4fprout <= 0.0) - { FP = 1.0; - dFP_dVg = 0.0; - } - else - { T9 = pParam->BSIM4fprout * sqrt(Leff) / Vgst2Vtm; + if (pParam->BSIM4fprout <= 0.0) + { FP = 1.0; + dFP_dVg = 0.0; + } + else + { T9 = pParam->BSIM4fprout * sqrt(Leff) / Vgst2Vtm; FP = 1.0 / (1.0 + T9); dFP_dVg = FP * FP * T9 / Vgst2Vtm; - } + } /* Calculate VACLM */ T8 = pParam->BSIM4pvag / EsatL; @@ -1898,13 +1908,13 @@ for (; model != NULL; model = BSIM4nextModel(model)) } if ((pParam->BSIM4pclm > MIN_EXP) && (diffVds > 1.0e-10)) - { T0 = 1.0 + Rds * Idl; + { T0 = 1.0 + Rds * Idl; dT0_dVg = dRds_dVg * Idl + Rds * dIdl_dVg; dT0_dVd = Rds * dIdl_dVd; dT0_dVb = dRds_dVb * Idl + Rds * dIdl_dVb; T2 = Vdsat / Esat; - T1 = Leff + T2; + T1 = Leff + T2; dT1_dVg = (dVdsat_dVg - T2 * dEsatL_dVg / Leff) / Esat; dT1_dVd = (dVdsat_dVd - T2 * dEsatL_dVd / Leff) / Esat; dT1_dVb = (dVdsat_dVb - T2 * dEsatL_dVb / Leff) / Esat; @@ -1930,10 +1940,10 @@ for (; model != NULL; model = BSIM4nextModel(model)) /* Calculate VADIBL */ if (pParam->BSIM4thetaRout > MIN_EXP) - { T8 = Abulk * Vdsat; - T0 = Vgst2Vtm * T8; + { T8 = Abulk * Vdsat; + T0 = Vgst2Vtm * T8; dT0_dVg = Vgst2Vtm * Abulk * dVdsat_dVg + T8 - + Vgst2Vtm * Vdsat * dAbulk_dVg; + + Vgst2Vtm * Vdsat * dAbulk_dVg; dT0_dVb = Vgst2Vtm * (dAbulk_dVb * Vdsat + Abulk * dVdsat_dVb); dT0_dVd = Vgst2Vtm * Abulk * dVdsat_dVd; @@ -1942,39 +1952,39 @@ for (; model != NULL; model = BSIM4nextModel(model)) dT1_dVb = Abulk * dVdsat_dVb + dAbulk_dVb * Vdsat; dT1_dVd = Abulk * dVdsat_dVd; - T9 = T1 * T1; - T2 = pParam->BSIM4thetaRout; + T9 = T1 * T1; + T2 = pParam->BSIM4thetaRout; VADIBL = (Vgst2Vtm - T0 / T1) / T2; dVADIBL_dVg = (1.0 - dT0_dVg / T1 + T0 * dT1_dVg / T9) / T2; dVADIBL_dVb = (-dT0_dVb / T1 + T0 * dT1_dVb / T9) / T2; dVADIBL_dVd = (-dT0_dVd / T1 + T0 * dT1_dVd / T9) / T2; - T7 = pParam->BSIM4pdiblb * Vbseff; - if (T7 >= -0.9) - { T3 = 1.0 / (1.0 + T7); + T7 = pParam->BSIM4pdiblb * Vbseff; + if (T7 >= -0.9) + { T3 = 1.0 / (1.0 + T7); VADIBL *= T3; dVADIBL_dVg *= T3; dVADIBL_dVb = (dVADIBL_dVb - VADIBL * pParam->BSIM4pdiblb) - * T3; + * T3; dVADIBL_dVd *= T3; - } - else - { T4 = 1.0 / (0.8 + T7); - T3 = (17.0 + 20.0 * T7) * T4; + } + else + { T4 = 1.0 / (0.8 + T7); + T3 = (17.0 + 20.0 * T7) * T4; dVADIBL_dVg *= T3; dVADIBL_dVb = dVADIBL_dVb * T3 - - VADIBL * pParam->BSIM4pdiblb * T4 * T4; + - VADIBL * pParam->BSIM4pdiblb * T4 * T4; dVADIBL_dVd *= T3; VADIBL *= T3; - } + } dVADIBL_dVg = dVADIBL_dVg * PvagTerm + VADIBL * dPvagTerm_dVg; dVADIBL_dVb = dVADIBL_dVb * PvagTerm + VADIBL * dPvagTerm_dVb; dVADIBL_dVd = dVADIBL_dVd * PvagTerm + VADIBL * dPvagTerm_dVd; VADIBL *= PvagTerm; } - else - { VADIBL = MAX_EXP; + else + { VADIBL = MAX_EXP; dVADIBL_dVd = dVADIBL_dVg = dVADIBL_dVb = 0.0; } @@ -1990,7 +2000,7 @@ for (; model != NULL; model = BSIM4nextModel(model)) { T1 = MAX_EXP; dT1_dVd = 0; } - else + else { T1 = exp(T0); dT1_dVd = T1 * pParam->BSIM4pditsd; } @@ -2000,35 +2010,35 @@ for (; model != NULL; model = BSIM4nextModel(model)) VADITS = (1.0 + T2 * T1) / pParam->BSIM4pdits; dVADITS_dVg = VADITS * dFP_dVg; dVADITS_dVd = FP * T2 * dT1_dVd / pParam->BSIM4pdits; - VADITS *= FP; + VADITS *= FP; } - else + else { VADITS = MAX_EXP; dVADITS_dVg = dVADITS_dVd = 0; } /* Calculate VASCBE */ - if ((pParam->BSIM4pscbe2 > 0.0)&&(pParam->BSIM4pscbe1>=0.0)) /*4.6.2*/ - { if (diffVds > pParam->BSIM4pscbe1 * pParam->BSIM4litl - / EXP_THRESHOLD) - { T0 = pParam->BSIM4pscbe1 * pParam->BSIM4litl / diffVds; - VASCBE = Leff * exp(T0) / pParam->BSIM4pscbe2; + if ((pParam->BSIM4pscbe2 > 0.0)&&(pParam->BSIM4pscbe1>=0.0)) /*4.6.2*/ + { if (diffVds > pParam->BSIM4pscbe1 * pParam->BSIM4litl + / EXP_THRESHOLD) + { T0 = pParam->BSIM4pscbe1 * pParam->BSIM4litl / diffVds; + VASCBE = Leff * exp(T0) / pParam->BSIM4pscbe2; T1 = T0 * VASCBE / diffVds; dVASCBE_dVg = T1 * dVdseff_dVg; dVASCBE_dVd = -T1 * (1.0 - dVdseff_dVd); dVASCBE_dVb = T1 * dVdseff_dVb; } - else - { VASCBE = MAX_EXP * Leff/pParam->BSIM4pscbe2; + else + { VASCBE = MAX_EXP * Leff/pParam->BSIM4pscbe2; dVASCBE_dVg = dVASCBE_dVd = dVASCBE_dVb = 0.0; } - } - else - { VASCBE = MAX_EXP; + } + else + { VASCBE = MAX_EXP; dVASCBE_dVg = dVASCBE_dVd = dVASCBE_dVb = 0.0; - } + } - /* Add DIBL to Ids */ + /* Add DIBL to Ids */ T9 = diffVds / VADIBL; T0 = 1.0 + T9; Idsa = Idl * T0; @@ -2041,8 +2051,8 @@ for (; model != NULL; model = BSIM4nextModel(model)) T9 = diffVds / VADITS; T0 = 1.0 + T9; dIdsa_dVg = T0 * dIdsa_dVg - Idsa * (dVdseff_dVg + T9 * dVADITS_dVg) / VADITS; - dIdsa_dVd = T0 * dIdsa_dVd + Idsa - * (1.0 - dVdseff_dVd - T9 * dVADITS_dVd) / VADITS; + dIdsa_dVd = T0 * dIdsa_dVd + Idsa + * (1.0 - dVdseff_dVd - T9 * dVADITS_dVd) / VADITS; dIdsa_dVb = T0 * dIdsa_dVb - Idsa * dVdseff_dVb / VADITS; Idsa *= T0; @@ -2108,23 +2118,23 @@ for (; model != NULL; model = BSIM4nextModel(model)) T0 = 1.0 + T9; Ids = Idsa * T0; - Gm = T0 * dIdsa_dVg - Idsa - * (dVdseff_dVg + T9 * dVASCBE_dVg) / VASCBE; - Gds = T0 * dIdsa_dVd + Idsa - * (1.0 - dVdseff_dVd - T9 * dVASCBE_dVd) / VASCBE; + Gm = T0 * dIdsa_dVg - Idsa + * (dVdseff_dVg + T9 * dVASCBE_dVg) / VASCBE; + Gds = T0 * dIdsa_dVd + Idsa + * (1.0 - dVdseff_dVd - T9 * dVASCBE_dVd) / VASCBE; Gmb = T0 * dIdsa_dVb - Idsa - * (dVdseff_dVb + T9 * dVASCBE_dVb) / VASCBE; + * (dVdseff_dVb + T9 * dVASCBE_dVb) / VASCBE; - tmp1 = Gds + Gm * dVgsteff_dVd; - tmp2 = Gmb + Gm * dVgsteff_dVb; - tmp3 = Gm; + tmp1 = Gds + Gm * dVgsteff_dVd; + tmp2 = Gmb + Gm * dVgsteff_dVb; + tmp3 = Gm; Gm = (Ids * dVdseff_dVg + Vdseff * tmp3) * dVgsteff_dVg; Gds = Ids * (dVdseff_dVd + dVdseff_dVg * dVgsteff_dVd) - + Vdseff * tmp1; + + Vdseff * tmp1; Gmb = (Ids * (dVdseff_dVb + dVdseff_dVg * dVgsteff_dVb) - + Vdseff * tmp2) * dVbseff_dVb; + + Vdseff * tmp2) * dVbseff_dVb; cdrain = Ids * Vdseff; @@ -2139,22 +2149,22 @@ for (; model != NULL; model = BSIM4nextModel(model)) dvs_dVb = Gmb * T11 + cdrain * T10 * dVgsteff_dVb; T0 = 2 * MM; T1 = vs / (pParam->BSIM4vtl * pParam->BSIM4tfactor); - if(T1 > 0.0) - { T2 = 1.0 + exp(T0 * log(T1)); - T3 = (T2 - 1.0) * T0 / vs; - Fsevl = 1.0 / exp(log(T2)/ T0); - dT2_dVg = T3 * dvs_dVg; - dT2_dVd = T3 * dvs_dVd; - dT2_dVb = T3 * dvs_dVb; - T4 = -1.0 / T0 * Fsevl / T2; - dFsevl_dVg = T4 * dT2_dVg; - dFsevl_dVd = T4 * dT2_dVd; - dFsevl_dVb = T4 * dT2_dVb; + if(T1 > 0.0) + { T2 = 1.0 + exp(T0 * log(T1)); + T3 = (T2 - 1.0) * T0 / vs; + Fsevl = 1.0 / exp(log(T2)/ T0); + dT2_dVg = T3 * dvs_dVg; + dT2_dVd = T3 * dvs_dVd; + dT2_dVb = T3 * dvs_dVb; + T4 = -1.0 / T0 * Fsevl / T2; + dFsevl_dVg = T4 * dT2_dVg; + dFsevl_dVd = T4 * dT2_dVd; + dFsevl_dVb = T4 * dT2_dVb; } else { - Fsevl = 1.0; - dFsevl_dVg = 0.0; - dFsevl_dVd = 0.0; - dFsevl_dVb = 0.0; + Fsevl = 1.0; + dFsevl_dVg = 0.0; + dFsevl_dVd = 0.0; + dFsevl_dVb = 0.0; } Gm *=Fsevl; Gm += cdrain * dFsevl_dVg; @@ -2163,55 +2173,55 @@ for (; model != NULL; model = BSIM4nextModel(model)) Gds *=Fsevl; Gds += cdrain * dFsevl_dVd; - cdrain *= Fsevl; - } + cdrain *= Fsevl; + } here->BSIM4gds = Gds; here->BSIM4gm = Gm; here->BSIM4gmbs = Gmb; here->BSIM4IdovVds = Ids; - if( here->BSIM4IdovVds <= model->BSIM4idovvdsc) here->BSIM4IdovVds = model->BSIM4idovvdsc; + if( here->BSIM4IdovVds <= model->BSIM4idovvdsc) here->BSIM4IdovVds = model->BSIM4idovvdsc; /* Calculate Rg */ if ((here->BSIM4rgateMod > 1) || (here->BSIM4trnqsMod != 0) || (here->BSIM4acnqsMod != 0)) - { T9 = pParam->BSIM4xrcrg2 * model->BSIM4vtm; + { T9 = pParam->BSIM4xrcrg2 * model->BSIM4vtm; T0 = T9 * beta; dT0_dVd = (dbeta_dVd + dbeta_dVg * dVgsteff_dVd) * T9; dT0_dVb = (dbeta_dVb + dbeta_dVg * dVgsteff_dVb) * T9; dT0_dVg = dbeta_dVg * T9; - here->BSIM4gcrg = pParam->BSIM4xrcrg1 * ( T0 + Ids); - here->BSIM4gcrgd = pParam->BSIM4xrcrg1 * (dT0_dVd + tmp1); + here->BSIM4gcrg = pParam->BSIM4xrcrg1 * ( T0 + Ids); + here->BSIM4gcrgd = pParam->BSIM4xrcrg1 * (dT0_dVd + tmp1); here->BSIM4gcrgb = pParam->BSIM4xrcrg1 * (dT0_dVb + tmp2) - * dVbseff_dVb; + * dVbseff_dVb; here->BSIM4gcrgg = pParam->BSIM4xrcrg1 * (dT0_dVg + tmp3) - * dVgsteff_dVg; + * dVgsteff_dVg; - if (here->BSIM4nf != 1.0) - { here->BSIM4gcrg *= here->BSIM4nf; - here->BSIM4gcrgg *= here->BSIM4nf; - here->BSIM4gcrgd *= here->BSIM4nf; - here->BSIM4gcrgb *= here->BSIM4nf; - } + if (here->BSIM4nf != 1.0) + { here->BSIM4gcrg *= here->BSIM4nf; + here->BSIM4gcrgg *= here->BSIM4nf; + here->BSIM4gcrgd *= here->BSIM4nf; + here->BSIM4gcrgb *= here->BSIM4nf; + } if (here->BSIM4rgateMod == 2) { T10 = here->BSIM4grgeltd * here->BSIM4grgeltd; - T11 = here->BSIM4grgeltd + here->BSIM4gcrg; - here->BSIM4gcrg = here->BSIM4grgeltd * here->BSIM4gcrg / T11; + T11 = here->BSIM4grgeltd + here->BSIM4gcrg; + here->BSIM4gcrg = here->BSIM4grgeltd * here->BSIM4gcrg / T11; T12 = T10 / T11 / T11; here->BSIM4gcrgg *= T12; here->BSIM4gcrgd *= T12; here->BSIM4gcrgb *= T12; } here->BSIM4gcrgs = -(here->BSIM4gcrgg + here->BSIM4gcrgd - + here->BSIM4gcrgb); - } + + here->BSIM4gcrgb); + } - /* Calculate bias-dependent external S/D resistance */ + /* Calculate bias-dependent external S/D resistance */ if (model->BSIM4rdsMod) - { /* Rs(V) */ + { /* Rs(V) */ T0 = vgs - pParam->BSIM4vfbsd; T1 = sqrt(T0 * T0 + 1.0e-4); vgs_eff = 0.5 * (T0 + T1); @@ -2241,7 +2251,7 @@ for (; model != NULL; model = BSIM4nextModel(model)) dgstot_dvb = T0 * dRs_dvb; dgstot_dvs = -(dgstot_dvg + dgstot_dvb + dgstot_dvd); - /* Rd(V) */ + /* Rd(V) */ T0 = vgd - pParam->BSIM4vfbsd; T1 = sqrt(T0 * T0 + 1.0e-4); vgd_eff = 0.5 * (T0 + T1); @@ -2281,36 +2291,36 @@ for (; model != NULL; model = BSIM4nextModel(model)) here->BSIM4gdtotg = T2 * dgdtot_dvg; here->BSIM4gdtots = T2 * dgdtot_dvs; here->BSIM4gdtotb = T2 * dgdtot_dvb; - } - else /* WDLiu: for bypass */ - { here->BSIM4gstot = here->BSIM4gstotd = here->BSIM4gstotg = 0.0; - here->BSIM4gstots = here->BSIM4gstotb = 0.0; - here->BSIM4gdtot = here->BSIM4gdtotd = here->BSIM4gdtotg = 0.0; + } + else /* WDLiu: for bypass */ + { here->BSIM4gstot = here->BSIM4gstotd = here->BSIM4gstotg = 0.0; + here->BSIM4gstots = here->BSIM4gstotb = 0.0; + here->BSIM4gdtot = here->BSIM4gdtotd = here->BSIM4gdtotg = 0.0; here->BSIM4gdtots = here->BSIM4gdtotb = 0.0; - } + } - /* GIDL/GISL Models */ + /* GIDL/GISL Models */ - if(model->BSIM4mtrlMod == 0) - T0 = 3.0 * toxe; - else - T0 = model->BSIM4epsrsub * toxe / epsrox; - - /* Calculate GIDL current */ + if(model->BSIM4mtrlMod == 0) + T0 = 3.0 * toxe; + else + T0 = model->BSIM4epsrsub * toxe / epsrox; - vgs_eff = here->BSIM4vgs_eff; + /* Calculate GIDL current */ + + vgs_eff = here->BSIM4vgs_eff; dvgs_eff_dvg = here->BSIM4dvgs_eff_dvg; - vgd_eff = here->BSIM4vgd_eff; + vgd_eff = here->BSIM4vgd_eff; dvgd_eff_dvg = here->BSIM4dvgd_eff_dvg; - if (model->BSIM4gidlMod==0){ - - if(model->BSIM4mtrlMod ==0) - T1 = (vds - vgs_eff - pParam->BSIM4egidl ) / T0; - else - T1 = (vds - vgs_eff - pParam->BSIM4egidl + pParam->BSIM4vfbsd) / T0; - - if ((pParam->BSIM4agidl <= 0.0) || (pParam->BSIM4bgidl <= 0.0) + if (model->BSIM4gidlMod==0){ + + if(model->BSIM4mtrlMod ==0) + T1 = (vds - vgs_eff - pParam->BSIM4egidl ) / T0; + else + T1 = (vds - vgs_eff - pParam->BSIM4egidl + pParam->BSIM4vfbsd) / T0; + + if ((pParam->BSIM4agidl <= 0.0) || (pParam->BSIM4bgidl <= 0.0) || (T1 <= 0.0) || (pParam->BSIM4cgidl <= 0.0) || (vbd > 0.0)) Igidl = Ggidld = Ggidlg = Ggidlb = 0.0; else { @@ -2329,7 +2339,7 @@ for (; model != NULL; model = BSIM4nextModel(model)) Ggidlg = Igidl * dT1_dVg; Igidl *= T1; } - + T4 = vbd * vbd; T5 = -vbd * T4; T6 = pParam->BSIM4cgidl + T5; @@ -2345,32 +2355,32 @@ for (; model != NULL; model = BSIM4nextModel(model)) here->BSIM4ggidlg = Ggidlg; here->BSIM4ggidlb = Ggidlb; /* Calculate GISL current */ - + if(model->BSIM4mtrlMod ==0) - T1 = (-vds - vgd_eff - pParam->BSIM4egisl ) / T0; + T1 = (-vds - vgd_eff - pParam->BSIM4egisl ) / T0; else - T1 = (-vds - vgd_eff - pParam->BSIM4egisl + pParam->BSIM4vfbsd ) / T0; + T1 = (-vds - vgd_eff - pParam->BSIM4egisl + pParam->BSIM4vfbsd ) / T0; if ((pParam->BSIM4agisl <= 0.0) || (pParam->BSIM4bgisl <= 0.0) - || (T1 <= 0.0) || (pParam->BSIM4cgisl <= 0.0) || (vbs > 0.0)) + || (T1 <= 0.0) || (pParam->BSIM4cgisl <= 0.0) || (vbs > 0.0)) { Igisl = Ggisls = Ggislg = Ggislb = 0.0; - else { + } else { dT1_dVd = 1.0 / T0; dT1_dVg = -dvgd_eff_dvg * dT1_dVd; T2 = pParam->BSIM4bgisl / T1; - if (T2 < 100.0) + if (T2 < 100.0) { Igisl = pParam->BSIM4agisl * pParam->BSIM4weffCJ * T1 * exp(-T2); T3 = Igisl * (1.0 + T2) / T1; Ggisls = T3 * dT1_dVd; Ggislg = T3 * dT1_dVg; } - else + else { Igisl = pParam->BSIM4agisl * pParam->BSIM4weffCJ * 3.720075976e-44; Ggisls = Igisl * dT1_dVd; Ggislg = Igisl * dT1_dVg; Igisl *= T1; } - + T4 = vbs * vbs; T5 = -vbs * T4; T6 = pParam->BSIM4cgisl + T5; @@ -2385,23 +2395,23 @@ for (; model != NULL; model = BSIM4nextModel(model)) here->BSIM4ggisls = Ggisls; here->BSIM4ggislg = Ggislg; here->BSIM4ggislb = Ggislb; - } - else{ - /* v4.7 New Gidl/GISL model */ - - /* GISL */ - if (model->BSIM4mtrlMod==0) - T1 = (-vds - pParam->BSIM4rgisl * vgd_eff - pParam->BSIM4egisl) / T0; - else - T1 = (-vds - pParam->BSIM4rgisl * vgd_eff - pParam->BSIM4egisl + pParam->BSIM4vfbsd) / T0; - - if ((pParam->BSIM4agisl <= 0.0) || + } + else{ + /* v4.7 New Gidl/GISL model */ + + /* GISL */ + if (model->BSIM4mtrlMod==0) + T1 = (-vds - pParam->BSIM4rgisl * vgd_eff - pParam->BSIM4egisl) / T0; + else + T1 = (-vds - pParam->BSIM4rgisl * vgd_eff - pParam->BSIM4egisl + pParam->BSIM4vfbsd) / T0; + + if ((pParam->BSIM4agisl <= 0.0) || (pParam->BSIM4bgisl <= 0.0) || (T1 <= 0.0) || (pParam->BSIM4cgisl < 0.0) ) - Igisl = Ggisls = Ggislg = Ggislb = 0.0; + Igisl = Ggisls = Ggislg = Ggislb = 0.0; else { - dT1_dVd = 1 / T0; + dT1_dVd = 1 / T0; dT1_dVg = - pParam->BSIM4rgisl * dT1_dVd * dvgd_eff_dvg; T2 = pParam->BSIM4bgisl / T1; if (T2 < EXPL_THRESHOLD) @@ -2410,21 +2420,21 @@ for (; model != NULL; model = BSIM4nextModel(model)) T3 = Igisl / T1 * (T2 + 1); Ggisls = T3 * dT1_dVd; Ggislg = T3 * dT1_dVg; - } - else + } + else { T3 = pParam->BSIM4weffCJ * pParam->BSIM4agisl * MIN_EXPL; Igisl = T3 * T1 ; Ggisls = T3 * dT1_dVd; Ggislg = T3 * dT1_dVg; - + } T4 = vbs - pParam->BSIM4fgisl; - /*--chetan dabhi solution for clamping T4-*/ - if(T4 > model->BSIM4gidlclamp) - T4=model->BSIM4gidlclamp; - - if (T4==0) + /*--chetan dabhi solution for clamping T4-*/ + if(T4 > model->BSIM4gidlclamp) + T4=model->BSIM4gidlclamp; + + if (T4==0) T5 = EXPL_THRESHOLD; else T5 = pParam->BSIM4kgisl / T4; @@ -2441,24 +2451,24 @@ for (; model != NULL; model = BSIM4nextModel(model)) Igisl*=T6; } - here->BSIM4Igisl = Igisl; - here->BSIM4ggisls = Ggisls; - here->BSIM4ggislg = Ggislg; - here->BSIM4ggislb = Ggislb; + here->BSIM4Igisl = Igisl; + here->BSIM4ggisls = Ggisls; + here->BSIM4ggislg = Ggislg; + here->BSIM4ggislb = Ggislb; /* End of GISL */ - - /* GIDL */ - if (model->BSIM4mtrlMod==0) - T1 = (vds - pParam->BSIM4rgidl * vgs_eff - pParam->BSIM4egidl) / T0; - else + + /* GIDL */ + if (model->BSIM4mtrlMod==0) + T1 = (vds - pParam->BSIM4rgidl * vgs_eff - pParam->BSIM4egidl) / T0; + else T1 = (vds - pParam->BSIM4rgidl * vgs_eff - pParam->BSIM4egidl + pParam->BSIM4vfbsd) / T0; - - - + + + if ((pParam->BSIM4agidl <= 0.0) || (pParam->BSIM4bgidl <= 0.0) || (T1 <= 0.0) || (pParam->BSIM4cgidl < 0.0) ) - Igidl = Ggidld = Ggidlg = Ggidlb = 0.0; + Igidl = Ggidld = Ggidlg = Ggidlb = 0.0; else { dT1_dVd = 1 / T0; @@ -2470,7 +2480,7 @@ for (; model != NULL; model = BSIM4nextModel(model)) T3 = Igidl / T1 * (T2 + 1); Ggidld = T3 * dT1_dVd; Ggidlg = T3 * dT1_dVg; - + } else { T3 = pParam->BSIM4weffCJ * pParam->BSIM4agidl * MIN_EXPL; @@ -2479,9 +2489,9 @@ for (; model != NULL; model = BSIM4nextModel(model)) Ggidlg = T3 * dT1_dVg; } T4 = vbd - pParam->BSIM4fgidl; - /*--chetan dabhi solution for clamping T4-*/ - if(T4 > model->BSIM4gidlclamp) - T4=model->BSIM4gidlclamp; + /*--chetan dabhi solution for clamping T4-*/ + if(T4 > model->BSIM4gidlclamp) + T4=model->BSIM4gidlclamp; if (T4==0) T5 = EXPL_THRESHOLD; else @@ -2497,15 +2507,15 @@ for (; model != NULL; model = BSIM4nextModel(model)) Ggidld *= T6; Ggidlg *= T6; Igidl *= T6; - } - here->BSIM4Igidl = Igidl; - here->BSIM4ggidld = Ggidld; - here->BSIM4ggidlg = Ggidlg; - here->BSIM4ggidlb = Ggidlb; + } + here->BSIM4Igidl = Igidl; + here->BSIM4ggidld = Ggidld; + here->BSIM4ggidlg = Ggidlg; + here->BSIM4ggidlb = Ggidlb; /* End of New GIDL */ - } - /*End of Gidl*/ - + } + /*End of Gidl*/ + /* Calculate gate tunneling current */ @@ -2531,20 +2541,20 @@ for (; model != NULL; model = BSIM4nextModel(model)) T3 = Vgs_eff - Vfbeff - Vbseff - Vgsteff; if (pParam->BSIM4k1ox == 0.0) Voxdepinv = dVoxdepinv_dVg = dVoxdepinv_dVd - = dVoxdepinv_dVb = 0.0; + = dVoxdepinv_dVb = 0.0; else if (T3 < 0.0) { Voxdepinv = -T3; dVoxdepinv_dVg = -dVgs_eff_dVg + dVfbeff_dVg + dVgsteff_dVg; dVoxdepinv_dVd = dVgsteff_dVd; dVoxdepinv_dVb = dVfbeff_dVb + 1.0 + dVgsteff_dVb; - } + } else { T1 = sqrt(T0 * T0 + T3); T2 = T0 / T1; Voxdepinv = pParam->BSIM4k1ox * (T1 - T0); dVoxdepinv_dVg = T2 * (dVgs_eff_dVg - dVfbeff_dVg - - dVgsteff_dVg); + - dVgsteff_dVg); dVoxdepinv_dVd = -T2 * dVgsteff_dVd; dVoxdepinv_dVb = -T2 * (dVfbeff_dVb + 1.0 + dVgsteff_dVb); } @@ -2556,20 +2566,20 @@ for (; model != NULL; model = BSIM4nextModel(model)) } if(model->BSIM4tempMod < 2) - tmp = Vtm; + tmp = Vtm; else /* model->BSIM4tempMod = 2 , 3*/ - tmp = Vtm0; + tmp = Vtm0; if (model->BSIM4igcMod) { T0 = tmp * pParam->BSIM4nigc; - if(model->BSIM4igcMod == 1) { - VxNVt = (Vgs_eff - model->BSIM4type * here->BSIM4vth0) / T0; - if (VxNVt > EXP_THRESHOLD) - { Vaux = Vgs_eff - model->BSIM4type * here->BSIM4vth0; - dVaux_dVg = dVgs_eff_dVg; - dVaux_dVd = 0.0; + if(model->BSIM4igcMod == 1) { + VxNVt = (Vgs_eff - model->BSIM4type * here->BSIM4vth0) / T0; + if (VxNVt > EXP_THRESHOLD) + { Vaux = Vgs_eff - model->BSIM4type * here->BSIM4vth0; + dVaux_dVg = dVgs_eff_dVg; + dVaux_dVd = 0.0; dVaux_dVb = 0.0; - } - } else if (model->BSIM4igcMod == 2) { + } + } else if (model->BSIM4igcMod == 2) { VxNVt = (Vgs_eff - here->BSIM4von) / T0; if (VxNVt > EXP_THRESHOLD) { Vaux = Vgs_eff - here->BSIM4von; @@ -2577,7 +2587,7 @@ for (; model != NULL; model = BSIM4nextModel(model)) dVaux_dVd = -dVth_dVd; dVaux_dVb = -dVth_dVb; } - } + } if (VxNVt < -EXP_THRESHOLD) { Vaux = T0 * log(1.0 + MIN_EXP); dVaux_dVg = dVaux_dVd = dVaux_dVb = 0.0; @@ -2586,20 +2596,20 @@ for (; model != NULL; model = BSIM4nextModel(model)) { ExpVxNVt = exp(VxNVt); Vaux = T0 * log(1.0 + ExpVxNVt); dVaux_dVg = ExpVxNVt / (1.0 + ExpVxNVt); - if(model->BSIM4igcMod == 1) { - dVaux_dVd = 0.0; - dVaux_dVb = 0.0; + if(model->BSIM4igcMod == 1) { + dVaux_dVd = 0.0; + dVaux_dVb = 0.0; } else if (model->BSIM4igcMod == 2) { dVaux_dVd = -dVaux_dVg* dVth_dVd; /* Synopsys 08/30/2013 modify */ dVaux_dVb = -dVaux_dVg* dVth_dVb; /* Synopsys 08/30/2013 modify */ - } - dVaux_dVg *= dVgs_eff_dVg; + } + dVaux_dVg *= dVgs_eff_dVg; } - T2 = Vgs_eff * Vaux; - dT2_dVg = dVgs_eff_dVg * Vaux + Vgs_eff * dVaux_dVg; - dT2_dVd = Vgs_eff * dVaux_dVd; - dT2_dVb = Vgs_eff * dVaux_dVb; + T2 = Vgs * Vaux; + dT2_dVg = Vaux + Vgs * dVaux_dVg; + dT2_dVd = Vgs * dVaux_dVd; + dT2_dVb = Vgs * dVaux_dVb; T11 = pParam->BSIM4Aechvb; T12 = pParam->BSIM4Bechvb; @@ -2636,11 +2646,11 @@ for (; model != NULL; model = BSIM4nextModel(model)) } else { /* T11 = pParam->BSIM4Bechvb * toxe; v4.7 */ - T11 = -pParam->BSIM4Bechvb; + T11 = -pParam->BSIM4Bechvb; T12 = Vgsteff + 1.0e-20; T13 = T11 / T12 / T12; T14 = -T13 / T12; - Pigcd = T13 * (1.0 - 0.5 * Vdseff / T12); + Pigcd = T13 * (1.0 - 0.5 * Vdseff / T12); dPigcd_dVg = T14 * (2.0 + 0.5 * (dVdseff_dVg - 3.0 * Vdseff / T12)); dPigcd_dVd = 0.5 * T14 * dVdseff_dVd; @@ -2732,7 +2742,7 @@ for (; model != NULL; model = BSIM4nextModel(model)) else { T6 = exp(T5); dT6_dVg = T6 * T12 * (T3 - 2.0 * T4 * vgs_eff) - * dvgs_eff_dvg; + * dvgs_eff_dvg; } Igs = T11 * T2 * T6; dIgs_dVg = T11 * (T2 * dT6_dVg + T6 * dT2_dVg); @@ -2777,16 +2787,16 @@ for (; model != NULL; model = BSIM4nextModel(model)) } else { here->BSIM4Igcs = here->BSIM4gIgcsg = here->BSIM4gIgcsd - = here->BSIM4gIgcsb = 0.0; + = here->BSIM4gIgcsb = 0.0; here->BSIM4Igcd = here->BSIM4gIgcdg = here->BSIM4gIgcdd - = here->BSIM4gIgcdb = 0.0; + = here->BSIM4gIgcdb = 0.0; here->BSIM4Igs = here->BSIM4gIgsg = here->BSIM4gIgss = 0.0; here->BSIM4Igd = here->BSIM4gIgdg = here->BSIM4gIgdd = 0.0; } if (model->BSIM4igbMod) { T0 = tmp * pParam->BSIM4nigbacc; - T1 = -Vgs_eff + Vbseff + Vfb; + T1 = -Vgs_eff + Vbseff + Vfb; VxNVt = T1 / T0; if (VxNVt > EXP_THRESHOLD) { Vaux = T1; @@ -2800,22 +2810,22 @@ for (; model != NULL; model = BSIM4nextModel(model)) else { ExpVxNVt = exp(VxNVt); Vaux = T0 * log(1.0 + ExpVxNVt); - dVaux_dVb = ExpVxNVt / (1.0 + ExpVxNVt); + dVaux_dVb = ExpVxNVt / (1.0 + ExpVxNVt); dVaux_dVg = -dVaux_dVb * dVgs_eff_dVg; } - T2 = (Vgs_eff - Vbseff) * Vaux; - dT2_dVg = dVgs_eff_dVg * Vaux + (Vgs_eff - Vbseff) * dVaux_dVg; - dT2_dVb = -Vaux + (Vgs_eff - Vbseff) * dVaux_dVb; + T2 = (Vgs - Vbs) * Vaux; + dT2_dVg = Vaux + (Vgs - Vbs) * dVaux_dVg; + dT2_dVb = -Vaux + (Vgs - Vbs) * dVaux_dVb; T11 = 4.97232e-7 * pParam->BSIM4weff - * pParam->BSIM4leff * pParam->BSIM4ToxRatio; + * pParam->BSIM4leff * pParam->BSIM4ToxRatio; T12 = -7.45669e11 * toxe; - T3 = pParam->BSIM4aigbacc * pParam->BSIM4cigbacc + T3 = pParam->BSIM4aigbacc * pParam->BSIM4cigbacc - pParam->BSIM4bigbacc; T4 = pParam->BSIM4bigbacc * pParam->BSIM4cigbacc; - T5 = T12 * (pParam->BSIM4aigbacc + T3 * Voxacc - - T4 * Voxacc * Voxacc); + T5 = T12 * (pParam->BSIM4aigbacc + T3 * Voxacc + - T4 * Voxacc * Voxacc); if (T5 > EXP_THRESHOLD) { T6 = MAX_EXP; @@ -2853,16 +2863,16 @@ for (; model != NULL; model = BSIM4nextModel(model)) else { ExpVxNVt = exp(VxNVt); Vaux = T0 * log(1.0 + ExpVxNVt); - dVaux_dVg = ExpVxNVt / (1.0 + ExpVxNVt); + dVaux_dVg = ExpVxNVt / (1.0 + ExpVxNVt); dVaux_dVd = dVaux_dVg * dVoxdepinv_dVd; dVaux_dVb = dVaux_dVg * dVoxdepinv_dVb; dVaux_dVg *= dVoxdepinv_dVg; } - T2 = (Vgs_eff - Vbseff) * Vaux; - dT2_dVg = dVgs_eff_dVg * Vaux + (Vgs_eff - Vbseff) * dVaux_dVg; - dT2_dVd = (Vgs_eff - Vbseff) * dVaux_dVd; - dT2_dVb = -Vaux + (Vgs_eff - Vbseff) * dVaux_dVb; + T2 = (Vgs - Vbs) * Vaux; + dT2_dVg = Vaux + (Vgs - Vbs) * dVaux_dVg; + dT2_dVd = (Vgs - Vbs) * dVaux_dVd; + dT2_dVb = -Vaux + (Vgs - Vbs) * dVaux_dVb; T11 *= 0.75610; T12 *= 1.31724; @@ -2900,16 +2910,16 @@ for (; model != NULL; model = BSIM4nextModel(model)) } else { here->BSIM4Igb = here->BSIM4gIgbg = here->BSIM4gIgbd - = here->BSIM4gIgbs = here->BSIM4gIgbb = 0.0; + = here->BSIM4gIgbs = here->BSIM4gIgbb = 0.0; } /* End of Gate current */ - if (here->BSIM4nf != 1.0) + if (here->BSIM4nf != 1.0) { cdrain *= here->BSIM4nf; here->BSIM4gds *= here->BSIM4nf; here->BSIM4gm *= here->BSIM4nf; here->BSIM4gmbs *= here->BSIM4nf; - here->BSIM4IdovVds *= here->BSIM4nf; - + here->BSIM4IdovVds *= here->BSIM4nf; + here->BSIM4gbbs *= here->BSIM4nf; here->BSIM4gbgs *= here->BSIM4nf; here->BSIM4gbds *= here->BSIM4nf; @@ -2918,8 +2928,8 @@ for (; model != NULL; model = BSIM4nextModel(model)) here->BSIM4Igidl *= here->BSIM4nf; here->BSIM4ggidld *= here->BSIM4nf; here->BSIM4ggidlg *= here->BSIM4nf; - here->BSIM4ggidlb *= here->BSIM4nf; - + here->BSIM4ggidlb *= here->BSIM4nf; + here->BSIM4Igisl *= here->BSIM4nf; here->BSIM4ggisls *= here->BSIM4nf; here->BSIM4ggislg *= here->BSIM4nf; @@ -2945,25 +2955,25 @@ for (; model != NULL; model = BSIM4nextModel(model)) here->BSIM4gIgbg *= here->BSIM4nf; here->BSIM4gIgbd *= here->BSIM4nf; here->BSIM4gIgbb *= here->BSIM4nf; - } + } here->BSIM4ggidls = -(here->BSIM4ggidld + here->BSIM4ggidlg - + here->BSIM4ggidlb); + + here->BSIM4ggidlb); here->BSIM4ggisld = -(here->BSIM4ggisls + here->BSIM4ggislg - + here->BSIM4ggislb); + + here->BSIM4ggislb); here->BSIM4gIgbs = -(here->BSIM4gIgbg + here->BSIM4gIgbd + here->BSIM4gIgbb); here->BSIM4gIgcss = -(here->BSIM4gIgcsg + here->BSIM4gIgcsd + here->BSIM4gIgcsb); here->BSIM4gIgcds = -(here->BSIM4gIgcdg + here->BSIM4gIgcdd + here->BSIM4gIgcdb); - here->BSIM4cd = cdrain; + here->BSIM4cd = cdrain; - /* Calculations for noise analysis */ + /* Calculations for noise analysis */ if (model->BSIM4tnoiMod == 0) - { Abulk = Abulk0 * pParam->BSIM4abulkCVfactor; + { Abulk = Abulk0_Q * pParam->BSIM4abulkCVfactor; Vdsat = Vgsteff / Abulk; T0 = Vdsat - Vds - DELTA_4; T1 = sqrt(T0 * T0 + 4.0 * DELTA_4 * Vdsat); @@ -2986,51 +2996,51 @@ for (; model != NULL; model = BSIM4nextModel(model)) * pParam->BSIM4leffCV * (Vgsteff - 0.5 * T0 + Abulk * T3); } - else if(model->BSIM4tnoiMod == 2) - { + else if(model->BSIM4tnoiMod == 2) + { here->BSIM4noiGd0 = here->BSIM4nf * beta * Vgsteff / (1.0 + gche * Rds); - } + } - /* + /* * BSIM4 C-V begins - */ + */ if ((model->BSIM4xpart < 0) || (!ChargeComputationNeeded)) - { qgate = qdrn = qsrc = qbulk = 0.0; + { qgate = qdrn = qsrc = qbulk = 0.0; here->BSIM4cggb = here->BSIM4cgsb = here->BSIM4cgdb = 0.0; here->BSIM4cdgb = here->BSIM4cdsb = here->BSIM4cddb = 0.0; here->BSIM4cbgb = here->BSIM4cbsb = here->BSIM4cbdb = 0.0; here->BSIM4csgb = here->BSIM4cssb = here->BSIM4csdb = 0.0; here->BSIM4cgbb = here->BSIM4csbb = here->BSIM4cdbb = here->BSIM4cbbb = 0.0; - here->BSIM4cqdb = here->BSIM4cqsb = here->BSIM4cqgb + here->BSIM4cqdb = here->BSIM4cqsb = here->BSIM4cqgb = here->BSIM4cqbb = 0.0; here->BSIM4gtau = 0.0; goto finished; } - else if (model->BSIM4capMod == 0) - { + else if (model->BSIM4capMod == 0) + { if (Vbseff < 0.0) - { VbseffCV = Vbs; /*4.6.2*/ + { VbseffCV = Vbs; /*4.6.2*/ dVbseffCV_dVb = 1.0; } - else - { VbseffCV = pParam->BSIM4phi - Phis; + else + { VbseffCV = pParam->BSIM4phi - Phis; dVbseffCV_dVb = -dPhis_dVb * dVbseff_dVb; /*4.6.2*/ } Vfb = pParam->BSIM4vfbcv; - Vth = Vfb + pParam->BSIM4phi + pParam->BSIM4k1ox * sqrtPhis; + Vth = Vfb + pParam->BSIM4phi + pParam->BSIM4k1ox * sqrtPhis; Vgst = Vgs_eff - Vth; dVth_dVb = pParam->BSIM4k1ox * dsqrtPhis_dVb *dVbseff_dVb; /*4.6.2*/ dVgst_dVb = -dVth_dVb; - dVgst_dVg = dVgs_eff_dVg; + dVgst_dVg = dVgs_eff_dVg; CoxWL = model->BSIM4coxe * pParam->BSIM4weffCV * pParam->BSIM4leffCV * here->BSIM4nf; Arg1 = Vgs_eff - VbseffCV - Vfb; if (Arg1 <= 0.0) - { qgate = CoxWL * Arg1; + { qgate = CoxWL * Arg1; qbulk = -qgate; qdrn = 0.0; @@ -3046,18 +3056,18 @@ for (; model != NULL; model = BSIM4nextModel(model)) here->BSIM4cbdb = 0.0; here->BSIM4cbsb = -here->BSIM4cgsb; } /* Arg1 <= 0.0, end of accumulation */ - else if (Vgst <= 0.0) - { T1 = 0.5 * pParam->BSIM4k1ox; - T2 = sqrt(T1 * T1 + Arg1); - qgate = CoxWL * pParam->BSIM4k1ox * (T2 - T1); + else if (Vgst <= 0.0) + { T1 = 0.5 * pParam->BSIM4k1ox; + T2 = sqrt(T1 * T1 + Arg1); + qgate = CoxWL * pParam->BSIM4k1ox * (T2 - T1); qbulk = -qgate; qdrn = 0.0; - T0 = CoxWL * T1 / T2; - here->BSIM4cggb = T0 * dVgs_eff_dVg; - here->BSIM4cgdb = 0.0; + T0 = CoxWL * T1 / T2; + here->BSIM4cggb = T0 * dVgs_eff_dVg; + here->BSIM4cgdb = 0.0; here->BSIM4cgsb = T0 * (dVbseffCV_dVb - dVgs_eff_dVg); - + here->BSIM4cdgb = 0.0; here->BSIM4cddb = 0.0; here->BSIM4cdsb = 0.0; @@ -3066,63 +3076,63 @@ for (; model != NULL; model = BSIM4nextModel(model)) here->BSIM4cbdb = 0.0; here->BSIM4cbsb = -here->BSIM4cgsb; } /* Vgst <= 0.0, end of depletion */ - else - { One_Third_CoxWL = CoxWL / 3.0; + else + { One_Third_CoxWL = CoxWL / 3.0; Two_Third_CoxWL = 2.0 * One_Third_CoxWL; - AbulkCV = Abulk0 * pParam->BSIM4abulkCVfactor; - dAbulkCV_dVb = pParam->BSIM4abulkCVfactor * dAbulk0_dVb*dVbseff_dVb; - - dVdsat_dVg = 1.0 / AbulkCV; /*4.6.2*/ - Vdsat = Vgst * dVdsat_dVg; - dVdsat_dVb = - (Vdsat * dAbulkCV_dVb + dVth_dVb)* dVdsat_dVg; + AbulkCV = Abulk0_Q * pParam->BSIM4abulkCVfactor; + dAbulkCV_dVb = pParam->BSIM4abulkCVfactor * dAbulk0_Q_dVb*dVbseff_dVb; + + dVdsat_dVg = 1.0 / AbulkCV; /*4.6.2*/ + Vdsat = Vgst * dVdsat_dVg; + dVdsat_dVb = - (Vdsat * dAbulkCV_dVb + dVth_dVb)* dVdsat_dVg; if (model->BSIM4xpart > 0.5) - { /* 0/100 Charge partition model */ - if (Vdsat <= Vds) - { /* saturation region */ - T1 = Vdsat / 3.0; - qgate = CoxWL * (Vgs_eff - Vfb - - pParam->BSIM4phi - T1); - T2 = -Two_Third_CoxWL * Vgst; - qbulk = -(qgate + T2); - qdrn = 0.0; + { /* 0/100 Charge partition model */ + if (Vdsat <= Vds) + { /* saturation region */ + T1 = Vdsat / 3.0; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM4phi - T1); + T2 = -Two_Third_CoxWL * Vgst; + qbulk = -(qgate + T2); + qdrn = 0.0; - here->BSIM4cggb = One_Third_CoxWL * (3.0 - - dVdsat_dVg) * dVgs_eff_dVg; - T2 = -One_Third_CoxWL * dVdsat_dVb; - here->BSIM4cgsb = -(here->BSIM4cggb + T2); + here->BSIM4cggb = One_Third_CoxWL * (3.0 + - dVdsat_dVg) * dVgs_eff_dVg; + T2 = -One_Third_CoxWL * dVdsat_dVb; + here->BSIM4cgsb = -(here->BSIM4cggb + T2); here->BSIM4cgdb = 0.0; - + here->BSIM4cdgb = 0.0; here->BSIM4cddb = 0.0; here->BSIM4cdsb = 0.0; - here->BSIM4cbgb = -(here->BSIM4cggb - - Two_Third_CoxWL * dVgs_eff_dVg); - T3 = -(T2 + Two_Third_CoxWL * dVth_dVb); - here->BSIM4cbsb = -(here->BSIM4cbgb + T3); + here->BSIM4cbgb = -(here->BSIM4cggb + - Two_Third_CoxWL * dVgs_eff_dVg); + T3 = -(T2 + Two_Third_CoxWL * dVth_dVb); + here->BSIM4cbsb = -(here->BSIM4cbgb + T3); here->BSIM4cbdb = 0.0; - } - else - { /* linear region */ - Alphaz = Vgst / Vdsat; - T1 = 2.0 * Vdsat - Vds; - T2 = Vds / (3.0 * T1); - T3 = T2 * Vds; - T9 = 0.25 * CoxWL; - T4 = T9 * Alphaz; - T7 = 2.0 * Vds - T1 - 3.0 * T3; - T8 = T3 - T1 - 2.0 * Vds; - qgate = CoxWL * (Vgs_eff - Vfb - - pParam->BSIM4phi - 0.5 * (Vds - T3)); - T10 = T4 * T8; - qdrn = T4 * T7; - qbulk = -(qgate + qdrn + T10); - + } + else + { /* linear region */ + Alphaz = Vgst / Vdsat; + T1 = 2.0 * Vdsat - Vds; + T2 = Vds / (3.0 * T1); + T3 = T2 * Vds; + T9 = 0.25 * CoxWL; + T4 = T9 * Alphaz; + T7 = 2.0 * Vds - T1 - 3.0 * T3; + T8 = T3 - T1 - 2.0 * Vds; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM4phi - 0.5 * (Vds - T3)); + T10 = T4 * T8; + qdrn = T4 * T7; + qbulk = -(qgate + qdrn + T10); + T5 = T3 / T1; here->BSIM4cggb = CoxWL * (1.0 - T5 * dVdsat_dVg) - * dVgs_eff_dVg; + * dVgs_eff_dVg; T11 = -CoxWL * T5 * dVdsat_dVb; here->BSIM4cgdb = CoxWL * (T2 - 0.5 + 0.5 * T5); here->BSIM4cgsb = -(here->BSIM4cggb + T11 @@ -3134,7 +3144,7 @@ for (; model != NULL; model = BSIM4nextModel(model)) T8 = T9 * T8; T9 = 2.0 * T4 * (1.0 - 3.0 * T5); here->BSIM4cdgb = (T7 * dAlphaz_dVg - T9 - * dVdsat_dVg) * dVgs_eff_dVg; + * dVdsat_dVg) * dVgs_eff_dVg; T12 = T7 * dAlphaz_dVb - T9 * dVdsat_dVb; here->BSIM4cddb = T4 * (3.0 - 6.0 * T2 - 3.0 * T5); here->BSIM4cdsb = -(here->BSIM4cdgb + T12 @@ -3142,366 +3152,366 @@ for (; model != NULL; model = BSIM4nextModel(model)) T9 = 2.0 * T4 * (1.0 + T5); T10 = (T8 * dAlphaz_dVg - T9 * dVdsat_dVg) - * dVgs_eff_dVg; + * dVgs_eff_dVg; T11 = T8 * dAlphaz_dVb - T9 * dVdsat_dVb; - T12 = T4 * (2.0 * T2 + T5 - 1.0); + T12 = T4 * (2.0 * T2 + T5 - 1.0); T0 = -(T10 + T11 + T12); here->BSIM4cbgb = -(here->BSIM4cggb - + here->BSIM4cdgb + T10); - here->BSIM4cbdb = -(here->BSIM4cgdb - + here->BSIM4cddb + T12); + + here->BSIM4cdgb + T10); + here->BSIM4cbdb = -(here->BSIM4cgdb + + here->BSIM4cddb + T12); here->BSIM4cbsb = -(here->BSIM4cgsb - + here->BSIM4cdsb + T0); + + here->BSIM4cdsb + T0); } } - else if (model->BSIM4xpart < 0.5) - { /* 40/60 Charge partition model */ - if (Vds >= Vdsat) - { /* saturation region */ - T1 = Vdsat / 3.0; - qgate = CoxWL * (Vgs_eff - Vfb - - pParam->BSIM4phi - T1); - T2 = -Two_Third_CoxWL * Vgst; - qbulk = -(qgate + T2); - qdrn = 0.4 * T2; + else if (model->BSIM4xpart < 0.5) + { /* 40/60 Charge partition model */ + if (Vds >= Vdsat) + { /* saturation region */ + T1 = Vdsat / 3.0; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM4phi - T1); + T2 = -Two_Third_CoxWL * Vgst; + qbulk = -(qgate + T2); + qdrn = 0.4 * T2; - here->BSIM4cggb = One_Third_CoxWL * (3.0 - - dVdsat_dVg) * dVgs_eff_dVg; - T2 = -One_Third_CoxWL * dVdsat_dVb; - here->BSIM4cgsb = -(here->BSIM4cggb + T2); - here->BSIM4cgdb = 0.0; - - T3 = 0.4 * Two_Third_CoxWL; + here->BSIM4cggb = One_Third_CoxWL * (3.0 + - dVdsat_dVg) * dVgs_eff_dVg; + T2 = -One_Third_CoxWL * dVdsat_dVb; + here->BSIM4cgsb = -(here->BSIM4cggb + T2); + here->BSIM4cgdb = 0.0; + + T3 = 0.4 * Two_Third_CoxWL; here->BSIM4cdgb = -T3 * dVgs_eff_dVg; here->BSIM4cddb = 0.0; - T4 = T3 * dVth_dVb; + T4 = T3 * dVth_dVb; here->BSIM4cdsb = -(T4 + here->BSIM4cdgb); - here->BSIM4cbgb = -(here->BSIM4cggb - - Two_Third_CoxWL * dVgs_eff_dVg); - T3 = -(T2 + Two_Third_CoxWL * dVth_dVb); - here->BSIM4cbsb = -(here->BSIM4cbgb + T3); + here->BSIM4cbgb = -(here->BSIM4cggb + - Two_Third_CoxWL * dVgs_eff_dVg); + T3 = -(T2 + Two_Third_CoxWL * dVth_dVb); + here->BSIM4cbsb = -(here->BSIM4cbgb + T3); here->BSIM4cbdb = 0.0; - } - else - { /* linear region */ - Alphaz = Vgst / Vdsat; - T1 = 2.0 * Vdsat - Vds; - T2 = Vds / (3.0 * T1); - T3 = T2 * Vds; - T9 = 0.25 * CoxWL; - T4 = T9 * Alphaz; - qgate = CoxWL * (Vgs_eff - Vfb - pParam->BSIM4phi - - 0.5 * (Vds - T3)); + } + else + { /* linear region */ + Alphaz = Vgst / Vdsat; + T1 = 2.0 * Vdsat - Vds; + T2 = Vds / (3.0 * T1); + T3 = T2 * Vds; + T9 = 0.25 * CoxWL; + T4 = T9 * Alphaz; + qgate = CoxWL * (Vgs_eff - Vfb - pParam->BSIM4phi + - 0.5 * (Vds - T3)); - T5 = T3 / T1; + T5 = T3 / T1; here->BSIM4cggb = CoxWL * (1.0 - T5 * dVdsat_dVg) - * dVgs_eff_dVg; + * dVgs_eff_dVg; tmp = -CoxWL * T5 * dVdsat_dVb; here->BSIM4cgdb = CoxWL * (T2 - 0.5 + 0.5 * T5); - here->BSIM4cgsb = -(here->BSIM4cggb - + here->BSIM4cgdb + tmp); + here->BSIM4cgsb = -(here->BSIM4cggb + + here->BSIM4cgdb + tmp); - T6 = 1.0 / Vdsat; + T6 = 1.0 / Vdsat; dAlphaz_dVg = T6 * (1.0 - Alphaz * dVdsat_dVg); dAlphaz_dVb = -T6 * (dVth_dVb + Alphaz * dVdsat_dVb); - T6 = 8.0 * Vdsat * Vdsat - 6.0 * Vdsat * Vds - + 1.2 * Vds * Vds; - T8 = T2 / T1; - T7 = Vds - T1 - T8 * T6; - qdrn = T4 * T7; - T7 *= T9; - tmp = T8 / T1; - tmp1 = T4 * (2.0 - 4.0 * tmp * T6 - + T8 * (16.0 * Vdsat - 6.0 * Vds)); + T6 = 8.0 * Vdsat * Vdsat - 6.0 * Vdsat * Vds + + 1.2 * Vds * Vds; + T8 = T2 / T1; + T7 = Vds - T1 - T8 * T6; + qdrn = T4 * T7; + T7 *= T9; + tmp = T8 / T1; + tmp1 = T4 * (2.0 - 4.0 * tmp * T6 + + T8 * (16.0 * Vdsat - 6.0 * Vds)); here->BSIM4cdgb = (T7 * dAlphaz_dVg - tmp1 - * dVdsat_dVg) * dVgs_eff_dVg; + * dVdsat_dVg) * dVgs_eff_dVg; T10 = T7 * dAlphaz_dVb - tmp1 * dVdsat_dVb; here->BSIM4cddb = T4 * (2.0 - (1.0 / (3.0 * T1 - * T1) + 2.0 * tmp) * T6 + T8 - * (6.0 * Vdsat - 2.4 * Vds)); - here->BSIM4cdsb = -(here->BSIM4cdgb - + T10 + here->BSIM4cddb); + * T1) + 2.0 * tmp) * T6 + T8 + * (6.0 * Vdsat - 2.4 * Vds)); + here->BSIM4cdsb = -(here->BSIM4cdgb + + T10 + here->BSIM4cddb); - T7 = 2.0 * (T1 + T3); - qbulk = -(qgate - T4 * T7); - T7 *= T9; - T0 = 4.0 * T4 * (1.0 - T5); - T12 = (-T7 * dAlphaz_dVg - T0 * dVdsat_dVg) * dVgs_eff_dVg - - here->BSIM4cdgb; /*4.6.2*/ - T11 = -T7 * dAlphaz_dVb - T10 - T0 * dVdsat_dVb; - T10 = -4.0 * T4 * (T2 - 0.5 + 0.5 * T5) - - here->BSIM4cddb; + T7 = 2.0 * (T1 + T3); + qbulk = -(qgate - T4 * T7); + T7 *= T9; + T0 = 4.0 * T4 * (1.0 - T5); + T12 = (-T7 * dAlphaz_dVg - T0 * dVdsat_dVg) * dVgs_eff_dVg + - here->BSIM4cdgb; /*4.6.2*/ + T11 = -T7 * dAlphaz_dVb - T10 - T0 * dVdsat_dVb; + T10 = -4.0 * T4 * (T2 - 0.5 + 0.5 * T5) + - here->BSIM4cddb; tmp = -(T10 + T11 + T12); - here->BSIM4cbgb = -(here->BSIM4cggb - + here->BSIM4cdgb + T12); + here->BSIM4cbgb = -(here->BSIM4cggb + + here->BSIM4cdgb + T12); here->BSIM4cbdb = -(here->BSIM4cgdb - + here->BSIM4cddb + T10); + + here->BSIM4cddb + T10); here->BSIM4cbsb = -(here->BSIM4cgsb - + here->BSIM4cdsb + tmp); + + here->BSIM4cdsb + tmp); } } - else - { /* 50/50 partitioning */ - if (Vds >= Vdsat) - { /* saturation region */ - T1 = Vdsat / 3.0; - qgate = CoxWL * (Vgs_eff - Vfb - - pParam->BSIM4phi - T1); - T2 = -Two_Third_CoxWL * Vgst; - qbulk = -(qgate + T2); - qdrn = 0.5 * T2; + else + { /* 50/50 partitioning */ + if (Vds >= Vdsat) + { /* saturation region */ + T1 = Vdsat / 3.0; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM4phi - T1); + T2 = -Two_Third_CoxWL * Vgst; + qbulk = -(qgate + T2); + qdrn = 0.5 * T2; + + here->BSIM4cggb = One_Third_CoxWL * (3.0 + - dVdsat_dVg) * dVgs_eff_dVg; + T2 = -One_Third_CoxWL * dVdsat_dVb; + here->BSIM4cgsb = -(here->BSIM4cggb + T2); + here->BSIM4cgdb = 0.0; - here->BSIM4cggb = One_Third_CoxWL * (3.0 - - dVdsat_dVg) * dVgs_eff_dVg; - T2 = -One_Third_CoxWL * dVdsat_dVb; - here->BSIM4cgsb = -(here->BSIM4cggb + T2); - here->BSIM4cgdb = 0.0; - here->BSIM4cdgb = -One_Third_CoxWL * dVgs_eff_dVg; here->BSIM4cddb = 0.0; - T4 = One_Third_CoxWL * dVth_dVb; + T4 = One_Third_CoxWL * dVth_dVb; here->BSIM4cdsb = -(T4 + here->BSIM4cdgb); - here->BSIM4cbgb = -(here->BSIM4cggb - - Two_Third_CoxWL * dVgs_eff_dVg); - T3 = -(T2 + Two_Third_CoxWL * dVth_dVb); - here->BSIM4cbsb = -(here->BSIM4cbgb + T3); + here->BSIM4cbgb = -(here->BSIM4cggb + - Two_Third_CoxWL * dVgs_eff_dVg); + T3 = -(T2 + Two_Third_CoxWL * dVth_dVb); + here->BSIM4cbsb = -(here->BSIM4cbgb + T3); here->BSIM4cbdb = 0.0; - } - else - { /* linear region */ - Alphaz = Vgst / Vdsat; - T1 = 2.0 * Vdsat - Vds; - T2 = Vds / (3.0 * T1); - T3 = T2 * Vds; - T9 = 0.25 * CoxWL; - T4 = T9 * Alphaz; - qgate = CoxWL * (Vgs_eff - Vfb - pParam->BSIM4phi - - 0.5 * (Vds - T3)); + } + else + { /* linear region */ + Alphaz = Vgst / Vdsat; + T1 = 2.0 * Vdsat - Vds; + T2 = Vds / (3.0 * T1); + T3 = T2 * Vds; + T9 = 0.25 * CoxWL; + T4 = T9 * Alphaz; + qgate = CoxWL * (Vgs_eff - Vfb - pParam->BSIM4phi + - 0.5 * (Vds - T3)); - T5 = T3 / T1; + T5 = T3 / T1; here->BSIM4cggb = CoxWL * (1.0 - T5 * dVdsat_dVg) - * dVgs_eff_dVg; + * dVgs_eff_dVg; tmp = -CoxWL * T5 * dVdsat_dVb; here->BSIM4cgdb = CoxWL * (T2 - 0.5 + 0.5 * T5); - here->BSIM4cgsb = -(here->BSIM4cggb - + here->BSIM4cgdb + tmp); + here->BSIM4cgsb = -(here->BSIM4cggb + + here->BSIM4cgdb + tmp); - T6 = 1.0 / Vdsat; + T6 = 1.0 / Vdsat; dAlphaz_dVg = T6 * (1.0 - Alphaz * dVdsat_dVg); dAlphaz_dVb = -T6 * (dVth_dVb + Alphaz * dVdsat_dVb); - T7 = T1 + T3; - qdrn = -T4 * T7; - qbulk = - (qgate + qdrn + qdrn); - T7 *= T9; - T0 = T4 * (2.0 * T5 - 2.0); + T7 = T1 + T3; + qdrn = -T4 * T7; + qbulk = - (qgate + qdrn + qdrn); + T7 *= T9; + T0 = T4 * (2.0 * T5 - 2.0); here->BSIM4cdgb = (T0 * dVdsat_dVg - T7 - * dAlphaz_dVg) * dVgs_eff_dVg; - T12 = T0 * dVdsat_dVb - T7 * dAlphaz_dVb; + * dAlphaz_dVg) * dVgs_eff_dVg; + T12 = T0 * dVdsat_dVb - T7 * dAlphaz_dVb; here->BSIM4cddb = T4 * (1.0 - 2.0 * T2 - T5); here->BSIM4cdsb = -(here->BSIM4cdgb + T12 + here->BSIM4cddb); here->BSIM4cbgb = -(here->BSIM4cggb - + 2.0 * here->BSIM4cdgb); + + 2.0 * here->BSIM4cdgb); here->BSIM4cbdb = -(here->BSIM4cgdb - + 2.0 * here->BSIM4cddb); + + 2.0 * here->BSIM4cddb); here->BSIM4cbsb = -(here->BSIM4cgsb - + 2.0 * here->BSIM4cdsb); + + 2.0 * here->BSIM4cdsb); } /* end of linear region */ - } /* end of 50/50 partition */ - } /* end of inversion */ - } /* end of capMod=0 */ - else - { if (Vbseff < 0.0) - { VbseffCV = Vbseff; + } /* end of 50/50 partition */ + } /* end of inversion */ + } /* end of capMod=0 */ + else + { if (Vbseff < 0.0) + { VbseffCV = Vbseff; dVbseffCV_dVb = 1.0; } - else - { VbseffCV = pParam->BSIM4phi - Phis; + else + { VbseffCV = pParam->BSIM4phi - Phis; dVbseffCV_dVb = -dPhis_dVb; } CoxWL = model->BSIM4coxe * pParam->BSIM4weffCV - * pParam->BSIM4leffCV * here->BSIM4nf; + * pParam->BSIM4leffCV * here->BSIM4nf; - if(model->BSIM4cvchargeMod == 0) - { - /* Seperate VgsteffCV with noff and voffcv */ - noff = n * pParam->BSIM4noff; - dnoff_dVd = pParam->BSIM4noff * dn_dVd; - dnoff_dVb = pParam->BSIM4noff * dn_dVb; - T0 = Vtm * noff; - voffcv = pParam->BSIM4voffcv; - VgstNVt = (Vgst - voffcv) / T0; - - if (VgstNVt > EXP_THRESHOLD) - { - Vgsteff = Vgst - voffcv; - dVgsteff_dVg = dVgs_eff_dVg; - dVgsteff_dVd = -dVth_dVd; - dVgsteff_dVb = -dVth_dVb; - } - else if (VgstNVt < -EXP_THRESHOLD) - { - Vgsteff = T0 * log(1.0 + MIN_EXP); - dVgsteff_dVg = 0.0; - dVgsteff_dVd = Vgsteff / noff; - dVgsteff_dVb = dVgsteff_dVd * dnoff_dVb; - dVgsteff_dVd *= dnoff_dVd; - } - else - { - ExpVgst = exp(VgstNVt); - Vgsteff = T0 * log(1.0 + ExpVgst); - dVgsteff_dVg = ExpVgst / (1.0 + ExpVgst); - dVgsteff_dVd = -dVgsteff_dVg * (dVth_dVd + (Vgst - voffcv) - / noff * dnoff_dVd) + Vgsteff / noff * dnoff_dVd; - dVgsteff_dVb = -dVgsteff_dVg * (dVth_dVb + (Vgst - voffcv) - / noff * dnoff_dVb) + Vgsteff / noff * dnoff_dVb; - dVgsteff_dVg *= dVgs_eff_dVg; - } - /* End of VgsteffCV for cvchargeMod = 0 */ - } - else - { - T0 = n * Vtm; - T1 = pParam->BSIM4mstarcv * Vgst; - T2 = T1 / T0; - if (T2 > EXP_THRESHOLD) - { - T10 = T1; - dT10_dVg = pParam->BSIM4mstarcv * dVgs_eff_dVg; - dT10_dVd = -dVth_dVd * pParam->BSIM4mstarcv; - dT10_dVb = -dVth_dVb * pParam->BSIM4mstarcv; - } - else if (T2 < -EXP_THRESHOLD) - { - T10 = Vtm * log(1.0 + MIN_EXP); - dT10_dVg = 0.0; - dT10_dVd = T10 * dn_dVd; - dT10_dVb = T10 * dn_dVb; - T10 *= n; - } - else - { - ExpVgst = exp(T2); - T3 = Vtm * log(1.0 + ExpVgst); - T10 = n * T3; - dT10_dVg = pParam->BSIM4mstarcv * ExpVgst / (1.0 + ExpVgst); - dT10_dVb = T3 * dn_dVb - dT10_dVg * (dVth_dVb + Vgst * dn_dVb / n); - dT10_dVd = T3 * dn_dVd - dT10_dVg * (dVth_dVd + Vgst * dn_dVd / n); - dT10_dVg *= dVgs_eff_dVg; - } - - T1 = pParam->BSIM4voffcbncv - (1.0 - pParam->BSIM4mstarcv) * Vgst; - T2 = T1 / T0; - if (T2 < -EXP_THRESHOLD) - { - T3 = model->BSIM4coxe * MIN_EXP / pParam->BSIM4cdep0; - T9 = pParam->BSIM4mstarcv + T3 * n; - dT9_dVg = 0.0; - dT9_dVd = dn_dVd * T3; - dT9_dVb = dn_dVb * T3; - } - else if (T2 > EXP_THRESHOLD) - { - T3 = model->BSIM4coxe * MAX_EXP / pParam->BSIM4cdep0; - T9 = pParam->BSIM4mstarcv + T3 * n; - dT9_dVg = 0.0; - dT9_dVd = dn_dVd * T3; - dT9_dVb = dn_dVb * T3; - } - else - { - ExpVgst = exp(T2); - T3 = model->BSIM4coxe / pParam->BSIM4cdep0; - T4 = T3 * ExpVgst; - T5 = T1 * T4 / T0; - T9 = pParam->BSIM4mstarcv + n * T4; - dT9_dVg = T3 * (pParam->BSIM4mstarcv - 1.0) * ExpVgst / Vtm; - dT9_dVb = T4 * dn_dVb - dT9_dVg * dVth_dVb - T5 * dn_dVb; - dT9_dVd = T4 * dn_dVd - dT9_dVg * dVth_dVd - T5 * dn_dVd; - dT9_dVg *= dVgs_eff_dVg; - } - - Vgsteff = T10 / T9; - T11 = T9 * T9; - dVgsteff_dVg = (T9 * dT10_dVg - T10 * dT9_dVg) / T11; - dVgsteff_dVd = (T9 * dT10_dVd - T10 * dT9_dVd) / T11; - dVgsteff_dVb = (T9 * dT10_dVb - T10 * dT9_dVb) / T11; - /* End of VgsteffCV for cvchargeMod = 1 */ - } - + if(model->BSIM4cvchargeMod == 0) + { + /* Seperate VgsteffCV with noff and voffcv */ + noff = n * pParam->BSIM4noff; + dnoff_dVd = pParam->BSIM4noff * dn_dVd; + dnoff_dVb = pParam->BSIM4noff * dn_dVb; + T0 = Vtm * noff; + voffcv = pParam->BSIM4voffcv; + VgstNVt = (Vgst - voffcv) / T0; - if (model->BSIM4capMod == 1) - { Vfb = here->BSIM4vfbzb; + if (VgstNVt > EXP_THRESHOLD) + { + Vgsteff = Vgst - voffcv; + dVgsteff_dVg = dVgs_eff_dVg; + dVgsteff_dVd = -dVth_dVd; + dVgsteff_dVb = -dVth_dVb; + } + else if (VgstNVt < -EXP_THRESHOLD) + { + Vgsteff = T0 * log(1.0 + MIN_EXP); + dVgsteff_dVg = 0.0; + dVgsteff_dVd = Vgsteff / noff; + dVgsteff_dVb = dVgsteff_dVd * dnoff_dVb; + dVgsteff_dVd *= dnoff_dVd; + } + else + { + ExpVgst = exp(VgstNVt); + Vgsteff = T0 * log(1.0 + ExpVgst); + dVgsteff_dVg = ExpVgst / (1.0 + ExpVgst); + dVgsteff_dVd = -dVgsteff_dVg * (dVth_dVd + (Vgst - voffcv) + / noff * dnoff_dVd) + Vgsteff / noff * dnoff_dVd; + dVgsteff_dVb = -dVgsteff_dVg * (dVth_dVb + (Vgst - voffcv) + / noff * dnoff_dVb) + Vgsteff / noff * dnoff_dVb; + dVgsteff_dVg *= dVgs_eff_dVg; + } + /* End of VgsteffCV for cvchargeMod = 0 */ + } + else + { + T0 = n * Vtm; + T1 = pParam->BSIM4mstarcv * Vgst; + T2 = T1 / T0; + if (T2 > EXP_THRESHOLD) + { + T10 = T1; + dT10_dVg = pParam->BSIM4mstarcv * dVgs_eff_dVg; + dT10_dVd = -dVth_dVd * pParam->BSIM4mstarcv; + dT10_dVb = -dVth_dVb * pParam->BSIM4mstarcv; + } + else if (T2 < -EXP_THRESHOLD) + { + T10 = Vtm * log(1.0 + MIN_EXP); + dT10_dVg = 0.0; + dT10_dVd = T10 * dn_dVd; + dT10_dVb = T10 * dn_dVb; + T10 *= n; + } + else + { + ExpVgst = exp(T2); + T3 = Vtm * log(1.0 + ExpVgst); + T10 = n * T3; + dT10_dVg = pParam->BSIM4mstarcv * ExpVgst / (1.0 + ExpVgst); + dT10_dVb = T3 * dn_dVb - dT10_dVg * (dVth_dVb + Vgst * dn_dVb / n); + dT10_dVd = T3 * dn_dVd - dT10_dVg * (dVth_dVd + Vgst * dn_dVd / n); + dT10_dVg *= dVgs_eff_dVg; + } + + T1 = pParam->BSIM4voffcbncv - (1.0 - pParam->BSIM4mstarcv) * Vgst; + T2 = T1 / T0; + if (T2 < -EXP_THRESHOLD) + { + T3 = model->BSIM4coxe * MIN_EXP / pParam->BSIM4cdep0; + T9 = pParam->BSIM4mstarcv + T3 * n; + dT9_dVg = 0.0; + dT9_dVd = dn_dVd * T3; + dT9_dVb = dn_dVb * T3; + } + else if (T2 > EXP_THRESHOLD) + { + T3 = model->BSIM4coxe * MAX_EXP / pParam->BSIM4cdep0; + T9 = pParam->BSIM4mstarcv + T3 * n; + dT9_dVg = 0.0; + dT9_dVd = dn_dVd * T3; + dT9_dVb = dn_dVb * T3; + } + else + { + ExpVgst = exp(T2); + T3 = model->BSIM4coxe / pParam->BSIM4cdep0; + T4 = T3 * ExpVgst; + T5 = T1 * T4 / T0; + T9 = pParam->BSIM4mstarcv + n * T4; + dT9_dVg = T3 * (pParam->BSIM4mstarcv - 1.0) * ExpVgst / Vtm; + dT9_dVb = T4 * dn_dVb - dT9_dVg * dVth_dVb - T5 * dn_dVb; + dT9_dVd = T4 * dn_dVd - dT9_dVg * dVth_dVd - T5 * dn_dVd; + dT9_dVg *= dVgs_eff_dVg; + } + + Vgsteff = T10 / T9; + T11 = T9 * T9; + dVgsteff_dVg = (T9 * dT10_dVg - T10 * dT9_dVg) / T11; + dVgsteff_dVd = (T9 * dT10_dVd - T10 * dT9_dVd) / T11; + dVgsteff_dVb = (T9 * dT10_dVb - T10 * dT9_dVb) / T11; + /* End of VgsteffCV for cvchargeMod = 1 */ + } + + + if (model->BSIM4capMod == 1) + { Vfb = here->BSIM4vfbzb; V3 = Vfb - Vgs_eff + VbseffCV - DELTA_3; - if (Vfb <= 0.0) - T0 = sqrt(V3 * V3 - 4.0 * DELTA_3 * Vfb); - else - T0 = sqrt(V3 * V3 + 4.0 * DELTA_3 * Vfb); + if (Vfb <= 0.0) + T0 = sqrt(V3 * V3 - 4.0 * DELTA_3 * Vfb); + else + T0 = sqrt(V3 * V3 + 4.0 * DELTA_3 * Vfb); - T1 = 0.5 * (1.0 + V3 / T0); - Vfbeff = Vfb - 0.5 * (V3 + T0); - dVfbeff_dVg = T1 * dVgs_eff_dVg; - dVfbeff_dVb = -T1 * dVbseffCV_dVb; - Qac0 = CoxWL * (Vfbeff - Vfb); - dQac0_dVg = CoxWL * dVfbeff_dVg; - dQac0_dVb = CoxWL * dVfbeff_dVb; + T1 = 0.5 * (1.0 + V3 / T0); + Vfbeff = Vfb - 0.5 * (V3 + T0); + dVfbeff_dVg = T1 * dVgs_eff_dVg; + dVfbeff_dVb = -T1 * dVbseffCV_dVb; + Qac0 = CoxWL * (Vfbeff - Vfb); + dQac0_dVg = CoxWL * dVfbeff_dVg; + dQac0_dVb = CoxWL * dVfbeff_dVb; T0 = 0.5 * pParam->BSIM4k1ox; - T3 = Vgs_eff - Vfbeff - VbseffCV - Vgsteff; + T3 = Vgs_eff - Vfbeff - VbseffCV - Vgsteff; if (pParam->BSIM4k1ox == 0.0) { T1 = 0.0; T2 = 0.0; } - else if (T3 < 0.0) - { T1 = T0 + T3 / pParam->BSIM4k1ox; + else if (T3 < 0.0) + { T1 = T0 + T3 / pParam->BSIM4k1ox; T2 = CoxWL; - } - else - { T1 = sqrt(T0 * T0 + T3); + } + else + { T1 = sqrt(T0 * T0 + T3); T2 = CoxWL * T0 / T1; - } + } - Qsub0 = CoxWL * pParam->BSIM4k1ox * (T1 - T0); + Qsub0 = CoxWL * pParam->BSIM4k1ox * (T1 - T0); dQsub0_dVg = T2 * (dVgs_eff_dVg - dVfbeff_dVg - dVgsteff_dVg); dQsub0_dVd = -T2 * dVgsteff_dVd; - dQsub0_dVb = -T2 * (dVfbeff_dVb + dVbseffCV_dVb + dQsub0_dVb = -T2 * (dVfbeff_dVb + dVbseffCV_dVb + dVgsteff_dVb); - AbulkCV = Abulk0 * pParam->BSIM4abulkCVfactor; - dAbulkCV_dVb = pParam->BSIM4abulkCVfactor * dAbulk0_dVb; - VdsatCV = Vgsteff / AbulkCV; + AbulkCV = Abulk0_Q * pParam->BSIM4abulkCVfactor; + dAbulkCV_dVb = pParam->BSIM4abulkCVfactor * dAbulk0_Q_dVb; + VdsatCV = Vgsteff / AbulkCV; - T0 = VdsatCV - Vds - DELTA_4; - dT0_dVg = 1.0 / AbulkCV; - dT0_dVb = -VdsatCV * dAbulkCV_dVb / AbulkCV; - T1 = sqrt(T0 * T0 + 4.0 * DELTA_4 * VdsatCV); + T0 = VdsatCV - Vds - DELTA_4; + dT0_dVg = 1.0 / AbulkCV; + dT0_dVb = -VdsatCV * dAbulkCV_dVb / AbulkCV; + T1 = sqrt(T0 * T0 + 4.0 * DELTA_4 * VdsatCV); dT1_dVg = (T0 + DELTA_4 + DELTA_4) / T1; dT1_dVd = -T0 / T1; dT1_dVb = dT1_dVg * dT0_dVb; - dT1_dVg *= dT0_dVg; - if (T0 >= 0.0) - { VdseffCV = VdsatCV - 0.5 * (T0 + T1); + dT1_dVg *= dT0_dVg; + if (T0 >= 0.0) + { VdseffCV = VdsatCV - 0.5 * (T0 + T1); dVdseffCV_dVg = 0.5 * (dT0_dVg - dT1_dVg); dVdseffCV_dVd = 0.5 * (1.0 - dT1_dVd); dVdseffCV_dVb = 0.5 * (dT0_dVb - dT1_dVb); - } + } else { T3 = (DELTA_4 + DELTA_4) / (T1 - T0); - T4 = 1.0 - T3; - T5 = VdsatCV * T3 / (T1 - T0); - VdseffCV = VdsatCV * T4; + T4 = 1.0 - T3; + T5 = VdsatCV * T3 / (T1 - T0); + VdseffCV = VdsatCV * T4; dVdseffCV_dVg = dT0_dVg * T4 + T5 * (dT1_dVg - dT0_dVg); dVdseffCV_dVd = T5 * (dT1_dVd + 1.0); dVdseffCV_dVb = dT0_dVb * (T4 - T5) + T5 * dT1_dVb; @@ -3513,117 +3523,117 @@ for (; model != NULL; model = BSIM4nextModel(model)) dVdseffCV_dVb = 0.0; } - T0 = AbulkCV * VdseffCV; - T1 = 12.0 * (Vgsteff - 0.5 * T0 + 1.0e-20); - T2 = VdseffCV / T1; - T3 = T0 * T2; - - T4 = (1.0 - 12.0 * T2 * T2 * AbulkCV); - T5 = (6.0 * T0 * (4.0 * Vgsteff - T0) / (T1 * T1) - 0.5); - T6 = 12.0 * T2 * T2 * Vgsteff; - - qgate = CoxWL * (Vgsteff - 0.5 * VdseffCV + T3); - Cgg1 = CoxWL * (T4 + T5 * dVdseffCV_dVg); - Cgd1 = CoxWL * T5 * dVdseffCV_dVd + Cgg1 * dVgsteff_dVd; - Cgb1 = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) - + Cgg1 * dVgsteff_dVb; - Cgg1 *= dVgsteff_dVg; - - T7 = 1.0 - AbulkCV; - qbulk = CoxWL * T7 * (0.5 * VdseffCV - T3); - T4 = -T7 * (T4 - 1.0); - T5 = -T7 * T5; - T6 = -(T7 * T6 + (0.5 * VdseffCV - T3)); - Cbg1 = CoxWL * (T4 + T5 * dVdseffCV_dVg); - Cbd1 = CoxWL * T5 * dVdseffCV_dVd + Cbg1 * dVgsteff_dVd; - Cbb1 = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) - + Cbg1 * dVgsteff_dVb; - Cbg1 *= dVgsteff_dVg; - - if (model->BSIM4xpart > 0.5) - { /* 0/100 Charge petition model */ - T1 = T1 + T1; - qsrc = -CoxWL * (0.5 * Vgsteff + 0.25 * T0 - - T0 * T0 / T1); - T7 = (4.0 * Vgsteff - T0) / (T1 * T1); - T4 = -(0.5 + 24.0 * T0 * T0 / (T1 * T1)); - T5 = -(0.25 * AbulkCV - 12.0 * AbulkCV * T0 * T7); - T6 = -(0.25 * VdseffCV - 12.0 * T0 * VdseffCV * T7); - Csg = CoxWL * (T4 + T5 * dVdseffCV_dVg); - Csd = CoxWL * T5 * dVdseffCV_dVd + Csg * dVgsteff_dVd; - Csb = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) - + Csg * dVgsteff_dVb; - Csg *= dVgsteff_dVg; - } - else if (model->BSIM4xpart < 0.5) - { /* 40/60 Charge petition model */ - T1 = T1 / 12.0; - T2 = 0.5 * CoxWL / (T1 * T1); - T3 = Vgsteff * (2.0 * T0 * T0 / 3.0 + Vgsteff - * (Vgsteff - 4.0 * T0 / 3.0)) - - 2.0 * T0 * T0 * T0 / 15.0; - qsrc = -T2 * T3; - T7 = 4.0 / 3.0 * Vgsteff * (Vgsteff - T0) - + 0.4 * T0 * T0; - T4 = -2.0 * qsrc / T1 - T2 * (Vgsteff * (3.0 - * Vgsteff - 8.0 * T0 / 3.0) - + 2.0 * T0 * T0 / 3.0); - T5 = (qsrc / T1 + T2 * T7) * AbulkCV; - T6 = (qsrc / T1 * VdseffCV + T2 * T7 * VdseffCV); - Csg = (T4 + T5 * dVdseffCV_dVg); - Csd = T5 * dVdseffCV_dVd + Csg * dVgsteff_dVd; - Csb = (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) - + Csg * dVgsteff_dVb; - Csg *= dVgsteff_dVg; - } - else - { /* 50/50 Charge petition model */ - qsrc = -0.5 * (qgate + qbulk); - Csg = -0.5 * (Cgg1 + Cbg1); - Csb = -0.5 * (Cgb1 + Cbb1); - Csd = -0.5 * (Cgd1 + Cbd1); - } - - qgate += Qac0 + Qsub0; - qbulk -= (Qac0 + Qsub0); - qdrn = -(qgate + qbulk + qsrc); - - Cgg = dQac0_dVg + dQsub0_dVg + Cgg1; - Cgd = dQsub0_dVd + Cgd1; - Cgb = dQac0_dVb + dQsub0_dVb + Cgb1; - - Cbg = Cbg1 - dQac0_dVg - dQsub0_dVg; - Cbd = Cbd1 - dQsub0_dVd; - Cbb = Cbb1 - dQac0_dVb - dQsub0_dVb; - - Cgb *= dVbseff_dVb; - Cbb *= dVbseff_dVb; - Csb *= dVbseff_dVb; - - here->BSIM4cggb = Cgg; - here->BSIM4cgsb = -(Cgg + Cgd + Cgb); - here->BSIM4cgdb = Cgd; - here->BSIM4cdgb = -(Cgg + Cbg + Csg); - here->BSIM4cdsb = (Cgg + Cgd + Cgb + Cbg + Cbd + Cbb - + Csg + Csd + Csb); - here->BSIM4cddb = -(Cgd + Cbd + Csd); - here->BSIM4cbgb = Cbg; - here->BSIM4cbsb = -(Cbg + Cbd + Cbb); - here->BSIM4cbdb = Cbd; - } - - /* Charge-Thickness capMod (CTM) begins */ - else if (model->BSIM4capMod == 2) - { V3 = here->BSIM4vfbzb - Vgs_eff + VbseffCV - DELTA_3; - if (here->BSIM4vfbzb <= 0.0) - T0 = sqrt(V3 * V3 - 4.0 * DELTA_3 * here->BSIM4vfbzb); - else - T0 = sqrt(V3 * V3 + 4.0 * DELTA_3 * here->BSIM4vfbzb); + T0 = AbulkCV * VdseffCV; + T1 = 12.0 * (Vgsteff - 0.5 * T0 + 1.0e-20); + T2 = VdseffCV / T1; + T3 = T0 * T2; - T1 = 0.5 * (1.0 + V3 / T0); - Vfbeff = here->BSIM4vfbzb - 0.5 * (V3 + T0); - dVfbeff_dVg = T1 * dVgs_eff_dVg; - dVfbeff_dVb = -T1 * dVbseffCV_dVb; + T4 = (1.0 - 12.0 * T2 * T2 * AbulkCV); + T5 = (6.0 * T0 * (4.0 * Vgsteff - T0) / (T1 * T1) - 0.5); + T6 = 12.0 * T2 * T2 * Vgsteff; + + qgate = CoxWL * (Vgsteff - 0.5 * VdseffCV + T3); + Cgg1 = CoxWL * (T4 + T5 * dVdseffCV_dVg); + Cgd1 = CoxWL * T5 * dVdseffCV_dVd + Cgg1 * dVgsteff_dVd; + Cgb1 = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Cgg1 * dVgsteff_dVb; + Cgg1 *= dVgsteff_dVg; + + T7 = 1.0 - AbulkCV; + qbulk = CoxWL * T7 * (0.5 * VdseffCV - T3); + T4 = -T7 * (T4 - 1.0); + T5 = -T7 * T5; + T6 = -(T7 * T6 + (0.5 * VdseffCV - T3)); + Cbg1 = CoxWL * (T4 + T5 * dVdseffCV_dVg); + Cbd1 = CoxWL * T5 * dVdseffCV_dVd + Cbg1 * dVgsteff_dVd; + Cbb1 = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Cbg1 * dVgsteff_dVb; + Cbg1 *= dVgsteff_dVg; + + if (model->BSIM4xpart > 0.5) + { /* 0/100 Charge petition model */ + T1 = T1 + T1; + qsrc = -CoxWL * (0.5 * Vgsteff + 0.25 * T0 + - T0 * T0 / T1); + T7 = (4.0 * Vgsteff - T0) / (T1 * T1); + T4 = -(0.5 + 24.0 * T0 * T0 / (T1 * T1)); + T5 = -(0.25 * AbulkCV - 12.0 * AbulkCV * T0 * T7); + T6 = -(0.25 * VdseffCV - 12.0 * T0 * VdseffCV * T7); + Csg = CoxWL * (T4 + T5 * dVdseffCV_dVg); + Csd = CoxWL * T5 * dVdseffCV_dVd + Csg * dVgsteff_dVd; + Csb = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Csg * dVgsteff_dVb; + Csg *= dVgsteff_dVg; + } + else if (model->BSIM4xpart < 0.5) + { /* 40/60 Charge petition model */ + T1 = T1 / 12.0; + T2 = 0.5 * CoxWL / (T1 * T1); + T3 = Vgsteff * (2.0 * T0 * T0 / 3.0 + Vgsteff + * (Vgsteff - 4.0 * T0 / 3.0)) + - 2.0 * T0 * T0 * T0 / 15.0; + qsrc = -T2 * T3; + T7 = 4.0 / 3.0 * Vgsteff * (Vgsteff - T0) + + 0.4 * T0 * T0; + T4 = -2.0 * qsrc / T1 - T2 * (Vgsteff * (3.0 + * Vgsteff - 8.0 * T0 / 3.0) + + 2.0 * T0 * T0 / 3.0); + T5 = (qsrc / T1 + T2 * T7) * AbulkCV; + T6 = (qsrc / T1 * VdseffCV + T2 * T7 * VdseffCV); + Csg = (T4 + T5 * dVdseffCV_dVg); + Csd = T5 * dVdseffCV_dVd + Csg * dVgsteff_dVd; + Csb = (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Csg * dVgsteff_dVb; + Csg *= dVgsteff_dVg; + } + else + { /* 50/50 Charge petition model */ + qsrc = -0.5 * (qgate + qbulk); + Csg = -0.5 * (Cgg1 + Cbg1); + Csb = -0.5 * (Cgb1 + Cbb1); + Csd = -0.5 * (Cgd1 + Cbd1); + } + + qgate += Qac0 + Qsub0; + qbulk -= (Qac0 + Qsub0); + qdrn = -(qgate + qbulk + qsrc); + + Cgg = dQac0_dVg + dQsub0_dVg + Cgg1; + Cgd = dQsub0_dVd + Cgd1; + Cgb = dQac0_dVb + dQsub0_dVb + Cgb1; + + Cbg = Cbg1 - dQac0_dVg - dQsub0_dVg; + Cbd = Cbd1 - dQsub0_dVd; + Cbb = Cbb1 - dQac0_dVb - dQsub0_dVb; + + Cgb *= dVbseff_dVb; + Cbb *= dVbseff_dVb; + Csb *= dVbseff_dVb; + + here->BSIM4cggb = Cgg; + here->BSIM4cgsb = -(Cgg + Cgd + Cgb); + here->BSIM4cgdb = Cgd; + here->BSIM4cdgb = -(Cgg + Cbg + Csg); + here->BSIM4cdsb = (Cgg + Cgd + Cgb + Cbg + Cbd + Cbb + + Csg + Csd + Csb); + here->BSIM4cddb = -(Cgd + Cbd + Csd); + here->BSIM4cbgb = Cbg; + here->BSIM4cbsb = -(Cbg + Cbd + Cbb); + here->BSIM4cbdb = Cbd; + } + + /* Charge-Thickness capMod (CTM) begins */ + else if (model->BSIM4capMod == 2) + { V3 = here->BSIM4vfbzb - Vgs_eff + VbseffCV - DELTA_3; + if (here->BSIM4vfbzb <= 0.0) + T0 = sqrt(V3 * V3 - 4.0 * DELTA_3 * here->BSIM4vfbzb); + else + T0 = sqrt(V3 * V3 + 4.0 * DELTA_3 * here->BSIM4vfbzb); + + T1 = 0.5 * (1.0 + V3 / T0); + Vfbeff = here->BSIM4vfbzb - 0.5 * (V3 + T0); + dVfbeff_dVg = T1 * dVgs_eff_dVg; + dVfbeff_dVb = -T1 * dVbseffCV_dVb; Cox = here->BSIM4coxp; Tox = 1.0e8 * here->BSIM4toxp; @@ -3668,8 +3678,8 @@ for (; model != NULL; model = BSIM4nextModel(model)) QovCox = Qac0 / Coxeff; dQac0_dVg = CoxWLcen * dVfbeff_dVg + QovCox * dCoxeff_dVg; - dQac0_dVb = CoxWLcen * dVfbeff_dVb - + QovCox * dCoxeff_dVb; + dQac0_dVb = CoxWLcen * dVfbeff_dVb + + QovCox * dCoxeff_dVb; T0 = 0.5 * pParam->BSIM4k1ox; T3 = Vgs_eff - Vfbeff - VbseffCV - Vgsteff; @@ -3694,29 +3704,29 @@ for (; model != NULL; model = BSIM4nextModel(model)) dQsub0_dVb = -T2 * (dVfbeff_dVb + dVbseffCV_dVb + dVgsteff_dVb) + QovCox * dCoxeff_dVb; - /* Gate-bias dependent delta Phis begins */ - if (pParam->BSIM4k1ox <= 0.0) - { Denomi = 0.25 * pParam->BSIM4moin * Vtm; + /* Gate-bias dependent delta Phis begins */ + if (pParam->BSIM4k1ox <= 0.0) + { Denomi = 0.25 * pParam->BSIM4moin * Vtm; T0 = 0.5 * pParam->BSIM4sqrtPhi; - } - else - { Denomi = pParam->BSIM4moin * Vtm - * pParam->BSIM4k1ox * pParam->BSIM4k1ox; + } + else + { Denomi = pParam->BSIM4moin * Vtm + * pParam->BSIM4k1ox * pParam->BSIM4k1ox; T0 = pParam->BSIM4k1ox * pParam->BSIM4sqrtPhi; - } + } T1 = 2.0 * T0 + Vgsteff; - DeltaPhi = Vtm * log(1.0 + T1 * Vgsteff / Denomi); - dDeltaPhi_dVg = 2.0 * Vtm * (T1 -T0) / (Denomi + T1 * Vgsteff); - /* End of delta Phis */ + DeltaPhi = Vtm * log(1.0 + T1 * Vgsteff / Denomi); + dDeltaPhi_dVg = 2.0 * Vtm * (T1 -T0) / (Denomi + T1 * Vgsteff); + /* End of delta Phis */ + + /* VgDP = Vgsteff - DeltaPhi */ + T0 = Vgsteff - DeltaPhi - 0.001; + dT0_dVg = 1.0 - dDeltaPhi_dVg; + T1 = sqrt(T0 * T0 + Vgsteff * 0.004); + VgDP = 0.5 * (T0 + T1); + dVgDP_dVg = 0.5 * (dT0_dVg + (T0 * dT0_dVg + 0.002) / T1); - /* VgDP = Vgsteff - DeltaPhi */ - T0 = Vgsteff - DeltaPhi - 0.001; - dT0_dVg = 1.0 - dDeltaPhi_dVg; - T1 = sqrt(T0 * T0 + Vgsteff * 0.004); - VgDP = 0.5 * (T0 + T1); - dVgDP_dVg = 0.5 * (dT0_dVg + (T0 * dT0_dVg + 0.002) / T1); - Tox += Tox; /* WDLiu: Tcen reevaluated below due to different Vgsteff */ T0 = (Vgsteff + here->BSIM4vtfbphi2) / Tox; tmp = exp(model->BSIM4bdos * 0.7 * log(T0)); @@ -3728,18 +3738,18 @@ for (; model != NULL; model = BSIM4nextModel(model)) dTcen_dVb = dTcen_dVg * dVgsteff_dVb; dTcen_dVg *= dVgsteff_dVg; - Ccen = epssub / Tcen; - T0 = Cox / (Cox + Ccen); - Coxeff = T0 * Ccen; - T1 = -Ccen / Tcen; - dCoxeff_dVg = T0 * T0 * T1; - dCoxeff_dVd = dCoxeff_dVg * dTcen_dVd; - dCoxeff_dVb = dCoxeff_dVg * dTcen_dVb; - dCoxeff_dVg *= dTcen_dVg; - CoxWLcen = CoxWL * Coxeff / model->BSIM4coxe; + Ccen = epssub / Tcen; + T0 = Cox / (Cox + Ccen); + Coxeff = T0 * Ccen; + T1 = -Ccen / Tcen; + dCoxeff_dVg = T0 * T0 * T1; + dCoxeff_dVd = dCoxeff_dVg * dTcen_dVd; + dCoxeff_dVb = dCoxeff_dVg * dTcen_dVb; + dCoxeff_dVg *= dTcen_dVg; + CoxWLcen = CoxWL * Coxeff / model->BSIM4coxe; - AbulkCV = Abulk0 * pParam->BSIM4abulkCVfactor; - dAbulkCV_dVb = pParam->BSIM4abulkCVfactor * dAbulk0_dVb; + AbulkCV = Abulk0_Q * pParam->BSIM4abulkCVfactor; + dAbulkCV_dVb = pParam->BSIM4abulkCVfactor * dAbulk0_Q_dVb; VdsatCV = VgDP / AbulkCV; T0 = VdsatCV - Vds - DELTA_4; @@ -3773,22 +3783,22 @@ for (; model != NULL; model = BSIM4nextModel(model)) } T0 = AbulkCV * VdseffCV; - T1 = VgDP; + T1 = VgDP; T2 = 12.0 * (T1 - 0.5 * T0 + 1.0e-20); T3 = T0 / T2; T4 = 1.0 - 12.0 * T3 * T3; T5 = AbulkCV * (6.0 * T0 * (4.0 * T1 - T0) / (T2 * T2) - 0.5); - T6 = T5 * VdseffCV / AbulkCV; + T6 = T5 * VdseffCV / AbulkCV; qgate = CoxWLcen * (T1 - T0 * (0.5 - T3)); - QovCox = qgate / Coxeff; - Cgg1 = CoxWLcen * (T4 * dVgDP_dVg - + T5 * dVdseffCV_dVg); - Cgd1 = CoxWLcen * T5 * dVdseffCV_dVd + Cgg1 - * dVgsteff_dVd + QovCox * dCoxeff_dVd; - Cgb1 = CoxWLcen * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) - + Cgg1 * dVgsteff_dVb + QovCox * dCoxeff_dVb; - Cgg1 = Cgg1 * dVgsteff_dVg + QovCox * dCoxeff_dVg; + QovCox = qgate / Coxeff; + Cgg1 = CoxWLcen * (T4 * dVgDP_dVg + + T5 * dVdseffCV_dVg); + Cgd1 = CoxWLcen * T5 * dVdseffCV_dVd + Cgg1 + * dVgsteff_dVd + QovCox * dCoxeff_dVd; + Cgb1 = CoxWLcen * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Cgg1 * dVgsteff_dVb + QovCox * dCoxeff_dVb; + Cgg1 = Cgg1 * dVgsteff_dVg + QovCox * dCoxeff_dVg; T7 = 1.0 - AbulkCV; @@ -3798,90 +3808,90 @@ for (; model != NULL; model = BSIM4nextModel(model)) T11 = -T7 * T5 / AbulkCV; T12 = -(T9 * T1 / AbulkCV + VdseffCV * (0.5 - T0 / T2)); - qbulk = CoxWLcen * T7 * (0.5 * VdseffCV - T0 * VdseffCV / T2); - QovCox = qbulk / Coxeff; - Cbg1 = CoxWLcen * (T10 + T11 * dVdseffCV_dVg); - Cbd1 = CoxWLcen * T11 * dVdseffCV_dVd + Cbg1 - * dVgsteff_dVd + QovCox * dCoxeff_dVd; - Cbb1 = CoxWLcen * (T11 * dVdseffCV_dVb + T12 * dAbulkCV_dVb) - + Cbg1 * dVgsteff_dVb + QovCox * dCoxeff_dVb; - Cbg1 = Cbg1 * dVgsteff_dVg + QovCox * dCoxeff_dVg; + qbulk = CoxWLcen * T7 * (0.5 * VdseffCV - T0 * VdseffCV / T2); + QovCox = qbulk / Coxeff; + Cbg1 = CoxWLcen * (T10 + T11 * dVdseffCV_dVg); + Cbd1 = CoxWLcen * T11 * dVdseffCV_dVd + Cbg1 + * dVgsteff_dVd + QovCox * dCoxeff_dVd; + Cbb1 = CoxWLcen * (T11 * dVdseffCV_dVb + T12 * dAbulkCV_dVb) + + Cbg1 * dVgsteff_dVb + QovCox * dCoxeff_dVb; + Cbg1 = Cbg1 * dVgsteff_dVg + QovCox * dCoxeff_dVg; if (model->BSIM4xpart > 0.5) - { /* 0/100 partition */ - qsrc = -CoxWLcen * (T1 / 2.0 + T0 / 4.0 - - 0.5 * T0 * T0 / T2); - QovCox = qsrc / Coxeff; - T2 += T2; - T3 = T2 * T2; - T7 = -(0.25 - 12.0 * T0 * (4.0 * T1 - T0) / T3); - T4 = -(0.5 + 24.0 * T0 * T0 / T3) * dVgDP_dVg; - T5 = T7 * AbulkCV; - T6 = T7 * VdseffCV; + { /* 0/100 partition */ + qsrc = -CoxWLcen * (T1 / 2.0 + T0 / 4.0 + - 0.5 * T0 * T0 / T2); + QovCox = qsrc / Coxeff; + T2 += T2; + T3 = T2 * T2; + T7 = -(0.25 - 12.0 * T0 * (4.0 * T1 - T0) / T3); + T4 = -(0.5 + 24.0 * T0 * T0 / T3) * dVgDP_dVg; + T5 = T7 * AbulkCV; + T6 = T7 * VdseffCV; - Csg = CoxWLcen * (T4 + T5 * dVdseffCV_dVg); - Csd = CoxWLcen * T5 * dVdseffCV_dVd + Csg * dVgsteff_dVd - + QovCox * dCoxeff_dVd; - Csb = CoxWLcen * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) - + Csg * dVgsteff_dVb + QovCox * dCoxeff_dVb; - Csg = Csg * dVgsteff_dVg + QovCox * dCoxeff_dVg; + Csg = CoxWLcen * (T4 + T5 * dVdseffCV_dVg); + Csd = CoxWLcen * T5 * dVdseffCV_dVd + Csg * dVgsteff_dVd + + QovCox * dCoxeff_dVd; + Csb = CoxWLcen * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Csg * dVgsteff_dVb + QovCox * dCoxeff_dVb; + Csg = Csg * dVgsteff_dVg + QovCox * dCoxeff_dVg; } - else if (model->BSIM4xpart < 0.5) - { /* 40/60 partition */ - T2 = T2 / 12.0; - T3 = 0.5 * CoxWLcen / (T2 * T2); - T4 = T1 * (2.0 * T0 * T0 / 3.0 + T1 * (T1 - 4.0 + else if (model->BSIM4xpart < 0.5) + { /* 40/60 partition */ + T2 = T2 / 12.0; + T3 = 0.5 * CoxWLcen / (T2 * T2); + T4 = T1 * (2.0 * T0 * T0 / 3.0 + T1 * (T1 - 4.0 * T0 / 3.0)) - 2.0 * T0 * T0 * T0 / 15.0; - qsrc = -T3 * T4; - QovCox = qsrc / Coxeff; - T8 = 4.0 / 3.0 * T1 * (T1 - T0) + 0.4 * T0 * T0; - T5 = -2.0 * qsrc / T2 - T3 * (T1 * (3.0 * T1 - 8.0 - * T0 / 3.0) + 2.0 * T0 * T0 / 3.0); - T6 = AbulkCV * (qsrc / T2 + T3 * T8); - T7 = T6 * VdseffCV / AbulkCV; + qsrc = -T3 * T4; + QovCox = qsrc / Coxeff; + T8 = 4.0 / 3.0 * T1 * (T1 - T0) + 0.4 * T0 * T0; + T5 = -2.0 * qsrc / T2 - T3 * (T1 * (3.0 * T1 - 8.0 + * T0 / 3.0) + 2.0 * T0 * T0 / 3.0); + T6 = AbulkCV * (qsrc / T2 + T3 * T8); + T7 = T6 * VdseffCV / AbulkCV; - Csg = T5 * dVgDP_dVg + T6 * dVdseffCV_dVg; - Csd = Csg * dVgsteff_dVd + T6 * dVdseffCV_dVd - + QovCox * dCoxeff_dVd; - Csb = Csg * dVgsteff_dVb + T6 * dVdseffCV_dVb - + T7 * dAbulkCV_dVb + QovCox * dCoxeff_dVb; - Csg = Csg * dVgsteff_dVg + QovCox * dCoxeff_dVg; + Csg = T5 * dVgDP_dVg + T6 * dVdseffCV_dVg; + Csd = Csg * dVgsteff_dVd + T6 * dVdseffCV_dVd + + QovCox * dCoxeff_dVd; + Csb = Csg * dVgsteff_dVb + T6 * dVdseffCV_dVb + + T7 * dAbulkCV_dVb + QovCox * dCoxeff_dVb; + Csg = Csg * dVgsteff_dVg + QovCox * dCoxeff_dVg; } - else - { /* 50/50 partition */ + else + { /* 50/50 partition */ qsrc = -0.5 * qgate; Csg = -0.5 * Cgg1; - Csd = -0.5 * Cgd1; - Csb = -0.5 * Cgb1; + Csd = -0.5 * Cgd1; + Csb = -0.5 * Cgb1; } - qgate += Qac0 + Qsub0 - qbulk; - qbulk -= (Qac0 + Qsub0); + qgate += Qac0 + Qsub0 - qbulk; + qbulk -= (Qac0 + Qsub0); qdrn = -(qgate + qbulk + qsrc); - Cbg = Cbg1 - dQac0_dVg - dQsub0_dVg; - Cbd = Cbd1 - dQsub0_dVd; - Cbb = Cbb1 - dQac0_dVb - dQsub0_dVb; + Cbg = Cbg1 - dQac0_dVg - dQsub0_dVg; + Cbd = Cbd1 - dQsub0_dVd; + Cbb = Cbb1 - dQac0_dVb - dQsub0_dVb; Cgg = Cgg1 - Cbg; Cgd = Cgd1 - Cbd; Cgb = Cgb1 - Cbb; - Cgb *= dVbseff_dVb; - Cbb *= dVbseff_dVb; - Csb *= dVbseff_dVb; + Cgb *= dVbseff_dVb; + Cbb *= dVbseff_dVb; + Csb *= dVbseff_dVb; here->BSIM4cggb = Cgg; - here->BSIM4cgsb = -(Cgg + Cgd + Cgb); - here->BSIM4cgdb = Cgd; + here->BSIM4cgsb = -(Cgg + Cgd + Cgb); + here->BSIM4cgdb = Cgd; here->BSIM4cdgb = -(Cgg + Cbg + Csg); - here->BSIM4cdsb = (Cgg + Cgd + Cgb + Cbg + Cbd + Cbb - + Csg + Csd + Csb); - here->BSIM4cddb = -(Cgd + Cbd + Csd); + here->BSIM4cdsb = (Cgg + Cgd + Cgb + Cbg + Cbd + Cbb + + Csg + Csd + Csb); + here->BSIM4cddb = -(Cgd + Cbd + Csd); here->BSIM4cbgb = Cbg; - here->BSIM4cbsb = -(Cbg + Cbd + Cbb); - here->BSIM4cbdb = Cbd; - } /* End of CTM */ + here->BSIM4cbsb = -(Cbg + Cbd + Cbb); + here->BSIM4cbdb = Cbd; + } /* End of CTM */ } here->BSIM4csgb = - here->BSIM4cggb - here->BSIM4cdgb - here->BSIM4cbgb; @@ -3910,26 +3920,26 @@ for (; model != NULL; model = BSIM4nextModel(model)) T1 = here->BSIM4gcrg / CoxWL; /* 1 / tau */ here->BSIM4gtau = T1 * ScalingFactor; - if (here->BSIM4acnqsMod) + if (here->BSIM4acnqsMod) here->BSIM4taunet = 1.0 / T1; *(ckt->CKTstate0 + here->BSIM4qcheq) = qcheq; if (ckt->CKTmode & MODEINITTRAN) *(ckt->CKTstate1 + here->BSIM4qcheq) = *(ckt->CKTstate0 + here->BSIM4qcheq); - if (here->BSIM4trnqsMod) + if (here->BSIM4trnqsMod) { error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM4qcheq); if (error) return(error); - } + } } -finished: +finished: - /* Calculate junction C-V */ + /* Calculate junction C-V */ if (ChargeComputationNeeded) - { czbd = model->BSIM4DunitAreaTempJctCap * here->BSIM4Adeff; /* bug fix */ + { czbd = model->BSIM4DunitAreaTempJctCap * here->BSIM4Adeff; /* bug fix */ czbs = model->BSIM4SunitAreaTempJctCap * here->BSIM4Aseff; czbdsw = model->BSIM4DunitLengthSidewallTempJctCap * here->BSIM4Pdeff; czbdswg = model->BSIM4DunitLengthGateSidewallTempJctCap @@ -3940,109 +3950,109 @@ finished: MJS = model->BSIM4SbulkJctBotGradingCoeff; MJSWS = model->BSIM4SbulkJctSideGradingCoeff; - MJSWGS = model->BSIM4SbulkJctGateSideGradingCoeff; + MJSWGS = model->BSIM4SbulkJctGateSideGradingCoeff; MJD = model->BSIM4DbulkJctBotGradingCoeff; MJSWD = model->BSIM4DbulkJctSideGradingCoeff; MJSWGD = model->BSIM4DbulkJctGateSideGradingCoeff; /* Source Bulk Junction */ - if (vbs_jct == 0.0) - { *(ckt->CKTstate0 + here->BSIM4qbs) = 0.0; + if (vbs_jct == 0.0) + { *(ckt->CKTstate0 + here->BSIM4qbs) = 0.0; here->BSIM4capbs = czbs + czbssw + czbsswg; - } - else if (vbs_jct < 0.0) - { if (czbs > 0.0) - { arg = 1.0 - vbs_jct / model->BSIM4PhiBS; - if (MJS == 0.5) + } + else if (vbs_jct < 0.0) + { if (czbs > 0.0) + { arg = 1.0 - vbs_jct / model->BSIM4PhiBS; + if (MJS == 0.5) sarg = 1.0 / sqrt(arg); - else + else sarg = exp(-MJS * log(arg)); - *(ckt->CKTstate0 + here->BSIM4qbs) = model->BSIM4PhiBS * czbs - * (1.0 - arg * sarg) / (1.0 - MJS); - here->BSIM4capbs = czbs * sarg; - } - else - { *(ckt->CKTstate0 + here->BSIM4qbs) = 0.0; - here->BSIM4capbs = 0.0; - } - if (czbssw > 0.0) - { arg = 1.0 - vbs_jct / model->BSIM4PhiBSWS; - if (MJSWS == 0.5) + *(ckt->CKTstate0 + here->BSIM4qbs) = model->BSIM4PhiBS * czbs + * (1.0 - arg * sarg) / (1.0 - MJS); + here->BSIM4capbs = czbs * sarg; + } + else + { *(ckt->CKTstate0 + here->BSIM4qbs) = 0.0; + here->BSIM4capbs = 0.0; + } + if (czbssw > 0.0) + { arg = 1.0 - vbs_jct / model->BSIM4PhiBSWS; + if (MJSWS == 0.5) sarg = 1.0 / sqrt(arg); - else + else sarg = exp(-MJSWS * log(arg)); *(ckt->CKTstate0 + here->BSIM4qbs) += model->BSIM4PhiBSWS * czbssw - * (1.0 - arg * sarg) / (1.0 - MJSWS); + * (1.0 - arg * sarg) / (1.0 - MJSWS); here->BSIM4capbs += czbssw * sarg; - } - if (czbsswg > 0.0) - { arg = 1.0 - vbs_jct / model->BSIM4PhiBSWGS; - if (MJSWGS == 0.5) + } + if (czbsswg > 0.0) + { arg = 1.0 - vbs_jct / model->BSIM4PhiBSWGS; + if (MJSWGS == 0.5) sarg = 1.0 / sqrt(arg); - else + else sarg = exp(-MJSWGS * log(arg)); *(ckt->CKTstate0 + here->BSIM4qbs) += model->BSIM4PhiBSWGS * czbsswg - * (1.0 - arg * sarg) / (1.0 - MJSWGS); + * (1.0 - arg * sarg) / (1.0 - MJSWGS); here->BSIM4capbs += czbsswg * sarg; - } + } } - else - { T0 = czbs + czbssw + czbsswg; - T1 = vbs_jct * (czbs * MJS / model->BSIM4PhiBS + czbssw * MJSWS - / model->BSIM4PhiBSWS + czbsswg * MJSWGS / model->BSIM4PhiBSWGS); + else + { T0 = czbs + czbssw + czbsswg; + T1 = vbs_jct * (czbs * MJS / model->BSIM4PhiBS + czbssw * MJSWS + / model->BSIM4PhiBSWS + czbsswg * MJSWGS / model->BSIM4PhiBSWGS); *(ckt->CKTstate0 + here->BSIM4qbs) = vbs_jct * (T0 + 0.5 * T1); here->BSIM4capbs = T0 + T1; } /* Drain Bulk Junction */ - if (vbd_jct == 0.0) - { *(ckt->CKTstate0 + here->BSIM4qbd) = 0.0; + if (vbd_jct == 0.0) + { *(ckt->CKTstate0 + here->BSIM4qbd) = 0.0; here->BSIM4capbd = czbd + czbdsw + czbdswg; - } - else if (vbd_jct < 0.0) - { if (czbd > 0.0) - { arg = 1.0 - vbd_jct / model->BSIM4PhiBD; - if (MJD == 0.5) + } + else if (vbd_jct < 0.0) + { if (czbd > 0.0) + { arg = 1.0 - vbd_jct / model->BSIM4PhiBD; + if (MJD == 0.5) sarg = 1.0 / sqrt(arg); - else + else sarg = exp(-MJD * log(arg)); - *(ckt->CKTstate0 + here->BSIM4qbd) = model->BSIM4PhiBD* czbd - * (1.0 - arg * sarg) / (1.0 - MJD); + *(ckt->CKTstate0 + here->BSIM4qbd) = model->BSIM4PhiBD* czbd + * (1.0 - arg * sarg) / (1.0 - MJD); here->BSIM4capbd = czbd * sarg; - } - else - { *(ckt->CKTstate0 + here->BSIM4qbd) = 0.0; + } + else + { *(ckt->CKTstate0 + here->BSIM4qbd) = 0.0; here->BSIM4capbd = 0.0; - } - if (czbdsw > 0.0) - { arg = 1.0 - vbd_jct / model->BSIM4PhiBSWD; - if (MJSWD == 0.5) + } + if (czbdsw > 0.0) + { arg = 1.0 - vbd_jct / model->BSIM4PhiBSWD; + if (MJSWD == 0.5) sarg = 1.0 / sqrt(arg); - else + else sarg = exp(-MJSWD * log(arg)); - *(ckt->CKTstate0 + here->BSIM4qbd) += model->BSIM4PhiBSWD * czbdsw - * (1.0 - arg * sarg) / (1.0 - MJSWD); + *(ckt->CKTstate0 + here->BSIM4qbd) += model->BSIM4PhiBSWD * czbdsw + * (1.0 - arg * sarg) / (1.0 - MJSWD); here->BSIM4capbd += czbdsw * sarg; - } - if (czbdswg > 0.0) - { arg = 1.0 - vbd_jct / model->BSIM4PhiBSWGD; - if (MJSWGD == 0.5) + } + if (czbdswg > 0.0) + { arg = 1.0 - vbd_jct / model->BSIM4PhiBSWGD; + if (MJSWGD == 0.5) sarg = 1.0 / sqrt(arg); - else + else sarg = exp(-MJSWGD * log(arg)); *(ckt->CKTstate0 + here->BSIM4qbd) += model->BSIM4PhiBSWGD * czbdswg - * (1.0 - arg * sarg) / (1.0 - MJSWGD); + * (1.0 - arg * sarg) / (1.0 - MJSWGD); here->BSIM4capbd += czbdswg * sarg; - } + } } - else - { T0 = czbd + czbdsw + czbdswg; + else + { T0 = czbd + czbdsw + czbdswg; T1 = vbd_jct * (czbd * MJD / model->BSIM4PhiBD + czbdsw * MJSWD / model->BSIM4PhiBSWD + czbdswg * MJSWGD / model->BSIM4PhiBSWGD); *(ckt->CKTstate0 + here->BSIM4qbd) = vbd_jct * (T0 + 0.5 * T1); - here->BSIM4capbd = T0 + T1; + here->BSIM4capbd = T0 + T1; } } @@ -4052,21 +4062,21 @@ finished: */ if ((here->BSIM4off == 0) || (!(ckt->CKTmode & MODEINITFIX))) - { if (Check == 1) - { ckt->CKTnoncon++; + { if (Check == 1) + { ckt->CKTnoncon++; #ifndef NEWCONV - } - else + } + else { if (here->BSIM4mode >= 0) { Idtot = here->BSIM4cd + here->BSIM4csub - + here->BSIM4Igidl - here->BSIM4cbd; + + here->BSIM4Igidl - here->BSIM4cbd; } else { Idtot = here->BSIM4cd + here->BSIM4cbd - here->BSIM4Igidl; /* bugfix */ } tol0 = ckt->CKTreltol * MAX(fabs(cdhat), fabs(Idtot)) + ckt->CKTabstol; - tol1 = ckt->CKTreltol * MAX(fabs(cseshat), fabs(Isestot)) + tol1 = ckt->CKTreltol * MAX(fabs(cseshat), fabs(Isestot)) + ckt->CKTabstol; tol2 = ckt->CKTreltol * MAX(fabs(cdedhat), fabs(Idedtot)) + ckt->CKTabstol; @@ -4077,20 +4087,20 @@ finished: tol5 = ckt->CKTreltol * MAX(fabs(cgbhat), fabs(Igbtot)) + ckt->CKTabstol; if ((fabs(cdhat - Idtot) >= tol0) || (fabs(cseshat - Isestot) >= tol1) - || (fabs(cdedhat - Idedtot) >= tol2)) + || (fabs(cdedhat - Idedtot) >= tol2)) { ckt->CKTnoncon++; } - else if ((fabs(cgshat - Igstot) >= tol3) || (fabs(cgdhat - Igdtot) >= tol4) - || (fabs(cgbhat - Igbtot) >= tol5)) + else if ((fabs(cgshat - Igstot) >= tol3) || (fabs(cgdhat - Igdtot) >= tol4) + || (fabs(cgbhat - Igbtot) >= tol5)) { ckt->CKTnoncon++; } else { Ibtot = here->BSIM4cbs + here->BSIM4cbd - - here->BSIM4Igidl - here->BSIM4Igisl - here->BSIM4csub; + - here->BSIM4Igidl - here->BSIM4Igisl - here->BSIM4csub; tol6 = ckt->CKTreltol * MAX(fabs(cbhat), fabs(Ibtot)) + ckt->CKTabstol; if (fabs(cbhat - Ibtot) > tol6) - { ckt->CKTnoncon++; + { ckt->CKTnoncon++; } } #endif /* NEWCONV */ @@ -4100,8 +4110,8 @@ finished: *(ckt->CKTstate0 + here->BSIM4vgs) = vgs; *(ckt->CKTstate0 + here->BSIM4vbs) = vbs; *(ckt->CKTstate0 + here->BSIM4vbd) = vbd; - *(ckt->CKTstate0 + here->BSIM4vges) = vges; - *(ckt->CKTstate0 + here->BSIM4vgms) = vgms; + *(ckt->CKTstate0 + here->BSIM4vges) = vges; + *(ckt->CKTstate0 + here->BSIM4vgms) = vgms; *(ckt->CKTstate0 + here->BSIM4vdbs) = vdbs; *(ckt->CKTstate0 + here->BSIM4vdbd) = vdbd; *(ckt->CKTstate0 + here->BSIM4vsbs) = vsbs; @@ -4111,69 +4121,68 @@ finished: if (!ChargeComputationNeeded) - goto line850; + goto line850; - if (here->BSIM4rgateMod == 3) - { - vgdx = vgmd; - vgsx = vgms; - } - else /* For rgateMod == 0, 1 and 2 */ - { - vgdx = vgd; - vgsx = vgs; - } - if (model->BSIM4capMod == 0) - { - cgdo = pParam->BSIM4cgdo; - qgdo = pParam->BSIM4cgdo * vgdx; - cgso = pParam->BSIM4cgso; - qgso = pParam->BSIM4cgso * vgsx; - } - else /* For both capMod == 1 and 2 */ - { T0 = vgdx + DELTA_1; - T1 = sqrt(T0 * T0 + 4.0 * DELTA_1); - T2 = 0.5 * (T0 - T1); + if (here->BSIM4rgateMod == 3) + { + vgdx = vgmd; + vgsx = vgms; + } + else /* For rgateMod == 0, 1 and 2 */ + { + vgdx = vgd; + vgsx = vgs; + } + if (model->BSIM4capMod == 0) + { + cgdo = pParam->BSIM4cgdo; + qgdo = pParam->BSIM4cgdo * vgdx; + cgso = pParam->BSIM4cgso; + qgso = pParam->BSIM4cgso * vgsx; + } + else /* For both capMod == 1 and 2 */ + { T0 = vgdx + DELTA_1; + T1 = sqrt(T0 * T0 + 4.0 * DELTA_1); + T2 = 0.5 * (T0 - T1); - T3 = pParam->BSIM4weffCV * pParam->BSIM4cgdl; - T4 = sqrt(1.0 - 4.0 * T2 / pParam->BSIM4ckappad); - cgdo = pParam->BSIM4cgdo + T3 - T3 * (1.0 - 1.0 / T4) - * (0.5 - 0.5 * T0 / T1); - qgdo = (pParam->BSIM4cgdo + T3) * vgdx - T3 * (T2 - + 0.5 * pParam->BSIM4ckappad * (T4 - 1.0)); + T3 = pParam->BSIM4weffCV * pParam->BSIM4cgdl; + T4 = sqrt(1.0 - 4.0 * T2 / pParam->BSIM4ckappad); + cgdo = pParam->BSIM4cgdo + T3 - T3 * (1.0 - 1.0 / T4) + * (0.5 - 0.5 * T0 / T1); + qgdo = (pParam->BSIM4cgdo + T3) * vgdx - T3 * (T2 + + 0.5 * pParam->BSIM4ckappad * (T4 - 1.0)); - T0 = vgsx + DELTA_1; - T1 = sqrt(T0 * T0 + 4.0 * DELTA_1); - T2 = 0.5 * (T0 - T1); - T3 = pParam->BSIM4weffCV * pParam->BSIM4cgsl; - T4 = sqrt(1.0 - 4.0 * T2 / pParam->BSIM4ckappas); - cgso = pParam->BSIM4cgso + T3 - T3 * (1.0 - 1.0 / T4) - * (0.5 - 0.5 * T0 / T1); - qgso = (pParam->BSIM4cgso + T3) * vgsx - T3 * (T2 - + 0.5 * pParam->BSIM4ckappas * (T4 - 1.0)); - } + T0 = vgsx + DELTA_1; + T1 = sqrt(T0 * T0 + 4.0 * DELTA_1); + T2 = 0.5 * (T0 - T1); + T3 = pParam->BSIM4weffCV * pParam->BSIM4cgsl; + T4 = sqrt(1.0 - 4.0 * T2 / pParam->BSIM4ckappas); + cgso = pParam->BSIM4cgso + T3 - T3 * (1.0 - 1.0 / T4) + * (0.5 - 0.5 * T0 / T1); + qgso = (pParam->BSIM4cgso + T3) * vgsx - T3 * (T2 + + 0.5 * pParam->BSIM4ckappas * (T4 - 1.0)); + } - if (here->BSIM4nf != 1.0) - { cgdo *= here->BSIM4nf; - cgso *= here->BSIM4nf; + if (here->BSIM4nf != 1.0) + { cgdo *= here->BSIM4nf; + cgso *= here->BSIM4nf; qgdo *= here->BSIM4nf; qgso *= here->BSIM4nf; - } + } here->BSIM4cgdo = cgdo; here->BSIM4qgdo = qgdo; here->BSIM4cgso = cgso; here->BSIM4qgso = qgso; -#ifndef NOBYPASS + line755: -#endif ag0 = ckt->CKTag[0]; if (here->BSIM4mode > 0) { if (here->BSIM4trnqsMod == 0) { qdrn -= qgdo; - if (here->BSIM4rgateMod == 3) - { gcgmgmb = (cgdo + cgso + pParam->BSIM4cgbo) * ag0; - gcgmdb = -cgdo * ag0; + if (here->BSIM4rgateMod == 3) + { gcgmgmb = (cgdo + cgso + pParam->BSIM4cgbo) * ag0; + gcgmdb = -cgdo * ag0; gcgmsb = -cgso * ag0; gcgmbb = -pParam->BSIM4cgbo * ag0; @@ -4181,13 +4190,13 @@ line755: gcsgmb = gcgmsb; gcbgmb = gcgmbb; - gcggb = here->BSIM4cggb * ag0; + gcggb = here->BSIM4cggb * ag0; gcgdb = here->BSIM4cgdb * ag0; - gcgsb = here->BSIM4cgsb * ag0; + gcgsb = here->BSIM4cgsb * ag0; gcgbb = -(gcggb + gcgdb + gcgsb); - gcdgb = here->BSIM4cdgb * ag0; - gcsgb = -(here->BSIM4cggb + here->BSIM4cbgb + gcdgb = here->BSIM4cdgb * ag0; + gcsgb = -(here->BSIM4cggb + here->BSIM4cbgb + here->BSIM4cdgb) * ag0; gcbgb = here->BSIM4cbgb * ag0; @@ -4195,26 +4204,26 @@ line755: qgmid = qgdo + qgso + qgmb; qbulk -= qgmb; qsrc = -(qgate + qgmid + qbulk + qdrn); - } - else - { gcggb = (here->BSIM4cggb + cgdo + cgso + } + else + { gcggb = (here->BSIM4cggb + cgdo + cgso + pParam->BSIM4cgbo ) * ag0; gcgdb = (here->BSIM4cgdb - cgdo) * ag0; gcgsb = (here->BSIM4cgsb - cgso) * ag0; gcgbb = -(gcggb + gcgdb + gcgsb); - gcdgb = (here->BSIM4cdgb - cgdo) * ag0; + gcdgb = (here->BSIM4cdgb - cgdo) * ag0; gcsgb = -(here->BSIM4cggb + here->BSIM4cbgb + here->BSIM4cdgb + cgso) * ag0; gcbgb = (here->BSIM4cbgb - pParam->BSIM4cgbo) * ag0; - gcdgmb = gcsgmb = gcbgmb = 0.0; + gcdgmb = gcsgmb = gcbgmb = 0.0; qgb = pParam->BSIM4cgbo * vgb; qgate += qgdo + qgso + qgb; qbulk -= qgb; qsrc = -(qgate + qbulk + qdrn); - } + } gcddb = (here->BSIM4cddb + here->BSIM4capbd + cgdo) * ag0; gcdsb = here->BSIM4cdsb * ag0; @@ -4231,23 +4240,23 @@ line755: gcdbdb = 0.0; gcsbsb = 0.0; } else - { gcdbb = -(here->BSIM4cddb + here->BSIM4cdgb + { gcdbb = -(here->BSIM4cddb + here->BSIM4cdgb + here->BSIM4cdsb) * ag0; gcsbb = -(gcsgb + gcsdb + gcssb + gcsgmb) - + here->BSIM4capbs * ag0; + + here->BSIM4capbs * ag0; gcbdb = here->BSIM4cbdb * ag0; gcbsb = here->BSIM4cbsb * ag0; gcdbdb = -here->BSIM4capbd * ag0; gcsbsb = -here->BSIM4capbs * ag0; } - gcbbb = -(gcbdb + gcbgb + gcbsb + gcbgmb); + gcbbb = -(gcbdb + gcbgb + gcbsb + gcbgmb); ggtg = ggtd = ggtb = ggts = 0.0; - sxpart = 0.6; + sxpart = 0.6; dxpart = 0.4; - ddxpart_dVd = ddxpart_dVg = ddxpart_dVb = ddxpart_dVs = 0.0; - dsxpart_dVd = dsxpart_dVg = dsxpart_dVb = dsxpart_dVs = 0.0; + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb = dsxpart_dVs = 0.0; } else { qcheq = here->BSIM4qchqs; @@ -4259,7 +4268,7 @@ line755: ggtd = here->BSIM4gtd = T0 * here->BSIM4gcrgd; ggts = here->BSIM4gts = T0 * here->BSIM4gcrgs; ggtb = here->BSIM4gtb = T0 * here->BSIM4gcrgb; - gqdef = ScalingFactor * ag0; + gqdef = ScalingFactor * ag0; gcqgb = here->BSIM4cqgb * ag0; gcqdb = here->BSIM4cqdb * ag0; @@ -4314,20 +4323,20 @@ line755: gcbgmb = gcgmbb; gcdgb = gcsgb = gcbgb = 0.0; - gcggb = gcgdb = gcgsb = gcgbb = 0.0; + gcggb = gcgdb = gcgsb = gcgbb = 0.0; qgmb = pParam->BSIM4cgbo * vgmb; qgmid = qgdo + qgso + qgmb; - qgate = 0.0; + qgate = 0.0; qbulk = -qgmb; - qdrn = -qgdo; + qdrn = -qgdo; qsrc = -(qgmid + qbulk + qdrn); } else { gcggb = (cgdo + cgso + pParam->BSIM4cgbo ) * ag0; gcgdb = -cgdo * ag0; gcgsb = -cgso * ag0; - gcgbb = -pParam->BSIM4cgbo * ag0; + gcgbb = -pParam->BSIM4cgbo * ag0; gcdgb = gcgdb; gcsgb = gcgsb; @@ -4337,7 +4346,7 @@ line755: qgb = pParam->BSIM4cgbo * vgb; qgate = qgdo + qgso + qgb; qbulk = -qgb; - qdrn = -qgdo; + qdrn = -qgdo; qsrc = -(qgate + qbulk + qdrn); } @@ -4363,11 +4372,11 @@ line755: else { if (here->BSIM4trnqsMod == 0) { qsrc = qdrn - qgso; - if (here->BSIM4rgateMod == 3) - { gcgmgmb = (cgdo + cgso + pParam->BSIM4cgbo) * ag0; - gcgmdb = -cgdo * ag0; - gcgmsb = -cgso * ag0; - gcgmbb = -pParam->BSIM4cgbo * ag0; + if (here->BSIM4rgateMod == 3) + { gcgmgmb = (cgdo + cgso + pParam->BSIM4cgbo) * ag0; + gcgmdb = -cgdo * ag0; + gcgmsb = -cgso * ag0; + gcgmbb = -pParam->BSIM4cgbo * ag0; gcdgmb = gcgmdb; gcsgmb = gcgmsb; @@ -4387,9 +4396,9 @@ line755: qgmid = qgdo + qgso + qgmb; qbulk -= qgmb; qdrn = -(qgate + qgmid + qbulk + qsrc); - } - else - { gcggb = (here->BSIM4cggb + cgdo + cgso + } + else + { gcggb = (here->BSIM4cggb + cgdo + cgso + pParam->BSIM4cgbo ) * ag0; gcgdb = (here->BSIM4cgsb - cgdo) * ag0; gcgsb = (here->BSIM4cgdb - cgso) * ag0; @@ -4406,7 +4415,7 @@ line755: qgate += qgdo + qgso + qgb; qbulk -= qgb; qdrn = -(qgate + qbulk + qsrc); - } + } gcddb = (here->BSIM4capbd + cgdo - (here->BSIM4cgsb + here->BSIM4cbsb + here->BSIM4cdsb)) * ag0; gcdsb = -(here->BSIM4cgdb + here->BSIM4cbdb @@ -4415,8 +4424,8 @@ line755: gcsdb = here->BSIM4cdsb * ag0; gcssb = (here->BSIM4cddb + here->BSIM4capbs + cgso) * ag0; - if (!here->BSIM4rbodyMod) - { gcdbb = -(gcdgb + gcddb + gcdsb + gcdgmb); + if (!here->BSIM4rbodyMod) + { gcdbb = -(gcdgb + gcddb + gcdsb + gcdgmb); gcsbb = -(gcsgb + gcsdb + gcssb + gcsgmb); gcbdb = (here->BSIM4cbsb - here->BSIM4capbd) * ag0; gcbsb = (here->BSIM4cbdb - here->BSIM4capbs) * ag0; @@ -4424,21 +4433,21 @@ line755: } else { gcdbb = -(gcdgb + gcddb + gcdsb + gcdgmb) - + here->BSIM4capbd * ag0; + + here->BSIM4capbd * ag0; gcsbb = -(here->BSIM4cddb + here->BSIM4cdgb + here->BSIM4cdsb) * ag0; gcbdb = here->BSIM4cbsb * ag0; gcbsb = here->BSIM4cbdb * ag0; gcdbdb = -here->BSIM4capbd * ag0; - gcsbsb = -here->BSIM4capbs * ag0; + gcsbsb = -here->BSIM4capbs * ag0; } - gcbbb = -(gcbgb + gcbdb + gcbsb + gcbgmb); + gcbbb = -(gcbgb + gcbdb + gcbsb + gcbgmb); ggtg = ggtd = ggtb = ggts = 0.0; - sxpart = 0.4; + sxpart = 0.4; dxpart = 0.6; - ddxpart_dVd = ddxpart_dVg = ddxpart_dVb = ddxpart_dVs = 0.0; - dsxpart_dVd = dsxpart_dVg = dsxpart_dVb = dsxpart_dVs = 0.0; + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb = dsxpart_dVs = 0.0; } else { qcheq = here->BSIM4qchqs; @@ -4449,7 +4458,7 @@ line755: ggts = here->BSIM4gts = T0 * here->BSIM4gcrgd; ggtd = here->BSIM4gtd = T0 * here->BSIM4gcrgs; ggtb = here->BSIM4gtb = T0 * here->BSIM4gcrgb; - gqdef = ScalingFactor * ag0; + gqdef = ScalingFactor * ag0; gcqgb = here->BSIM4cqgb * ag0; gcqdb = here->BSIM4cqsb * ag0; @@ -4588,10 +4597,6 @@ 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); @@ -4611,13 +4616,13 @@ line755: } error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM4qb); - if (error) + if (error) return(error); error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM4qg); - if (error) + if (error) return(error); error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM4qd); - if (error) + if (error) return(error); if (here->BSIM4rgateMod == 3) @@ -4627,10 +4632,10 @@ line755: if (here->BSIM4rbodyMod) { error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM4qbs); - if (error) + if (error) return(error); error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM4qbd); - if (error) + if (error) return(error); } @@ -4648,15 +4653,15 @@ line850: gcggb = gcgdb = gcgsb = gcgbb = 0.0; gcbdb = gcbgb = gcbsb = gcbbb = 0.0; - gcgmgmb = gcgmdb = gcgmsb = gcgmbb = 0.0; - gcdgmb = gcsgmb = gcbgmb = ceqqgmid = 0.0; + gcgmgmb = gcgmdb = gcgmsb = gcgmbb = 0.0; + gcdgmb = gcsgmb = gcbgmb = ceqqgmid = 0.0; gcdbdb = gcsbsb = 0.0; - gqdef = gcqgb = gcqdb = gcqsb = gcqbb = 0.0; + gqdef = gcqgb = gcqdb = gcqsb = gcqbb = 0.0; ggtg = ggtd = ggtb = ggts = 0.0; sxpart = (1.0 - (dxpart = (here->BSIM4mode > 0) ? 0.4 : 0.6)); - ddxpart_dVd = ddxpart_dVg = ddxpart_dVb = ddxpart_dVs = 0.0; - dsxpart_dVd = dsxpart_dVg = dsxpart_dVb = dsxpart_dVs = 0.0; + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb = dsxpart_dVs = 0.0; if (here->BSIM4trnqsMod) { CoxWL = model->BSIM4coxe * pParam->BSIM4weffCV * here->BSIM4nf @@ -4664,12 +4669,12 @@ line850: T1 = here->BSIM4gcrg / CoxWL; here->BSIM4gtau = T1 * ScalingFactor; } - else + else here->BSIM4gtau = 0.0; goto line900; - + line860: /* Calculate equivalent charge current */ @@ -4679,8 +4684,8 @@ line860: ceqqg = cqgate - gcggb * vgb + gcgdb * vbd + gcgsb * vbs; ceqqd = cqdrn - gcdgb * vgb - gcdgmb * vgmb + (gcddb + gcdbdb) - * vbd - gcdbdb * vbd_jct + gcdsb * vbs; - ceqqb = cqbody - gcbgb * vgb - gcbgmb * vgmb + * vbd - gcdbdb * vbd_jct + gcdsb * vbs; + ceqqb = cqbody - gcbgb * vgb - gcbgmb * vgmb + gcbdb * vbd + gcbsb * vbs; @@ -4688,19 +4693,19 @@ line860: ceqqgmid = *(ckt->CKTstate0 + here->BSIM4cqgmid) + gcgmdb * vbd + gcgmsb * vbs - gcgmgmb * vgmb; else - ceqqgmid = 0.0; + ceqqgmid = 0.0; if (here->BSIM4rbodyMod) { ceqqjs = *(ckt->CKTstate0 + here->BSIM4cqbs) + gcsbsb * vbs_jct; - ceqqjd = *(ckt->CKTstate0 + here->BSIM4cqbd) + gcdbdb * vbd_jct; + ceqqjd = *(ckt->CKTstate0 + here->BSIM4cqbd) + gcdbdb * vbd_jct; } if (here->BSIM4trnqsMod) { T0 = ggtg * vgb - ggtd * vbd - ggts * vbs; ceqqg += T0; - T1 = qdef * here->BSIM4gtau; + T1 = qdef * here->BSIM4gtau; ceqqd -= dxpart * T0 + T1 * (ddxpart_dVg * vgb - ddxpart_dVd - * vbd - ddxpart_dVs * vbs); + * vbd - ddxpart_dVs * vbs); cqdef = *(ckt->CKTstate0 + here->BSIM4cqcdump) - gqdef * qdef; cqcheq = *(ckt->CKTstate0 + here->BSIM4cqcheq) - (gcqgb * vgb - gcqdb * vbd - gcqsb * vbs) + T0; @@ -4733,23 +4738,23 @@ line860: line900: if (here->BSIM4mode >= 0) - { Gm = here->BSIM4gm; + { Gm = here->BSIM4gm; Gmbs = here->BSIM4gmbs; FwdSum = Gm + Gmbs; RevSum = 0.0; ceqdrn = model->BSIM4type * (cdrain - here->BSIM4gds * vds - - Gm * vgs - Gmbs * vbs); + - Gm * vgs - Gmbs * vbs); ceqbd = model->BSIM4type * (here->BSIM4csub + here->BSIM4Igidl - (here->BSIM4gbds + here->BSIM4ggidld) * vds - - (here->BSIM4gbgs + here->BSIM4ggidlg) * vgs - - (here->BSIM4gbbs + here->BSIM4ggidlb) * vbs); - ceqbs = model->BSIM4type * (here->BSIM4Igisl + here->BSIM4ggisls * vds - - here->BSIM4ggislg * vgd - here->BSIM4ggislb * vbd); + - (here->BSIM4gbgs + here->BSIM4ggidlg) * vgs + - (here->BSIM4gbbs + here->BSIM4ggidlb) * vbs); + ceqbs = model->BSIM4type * (here->BSIM4Igisl + here->BSIM4ggisls * vds + - here->BSIM4ggislg * vgd - here->BSIM4ggislb * vbd); gbbdp = -(here->BSIM4gbds); - gbbsp = here->BSIM4gbds + here->BSIM4gbgs + here->BSIM4gbbs; - + gbbsp = here->BSIM4gbds + here->BSIM4gbgs + here->BSIM4gbbs; + gbdpg = here->BSIM4gbgs; gbdpdp = here->BSIM4gbds; gbdpb = here->BSIM4gbbs; @@ -4761,13 +4766,13 @@ line900: gbspsp = 0.0; if (model->BSIM4igcMod) - { gIstotg = here->BSIM4gIgsg + here->BSIM4gIgcsg; - gIstotd = here->BSIM4gIgcsd; + { gIstotg = here->BSIM4gIgsg + here->BSIM4gIgcsg; + gIstotd = here->BSIM4gIgcsd; gIstots = here->BSIM4gIgss + here->BSIM4gIgcss; gIstotb = here->BSIM4gIgcsb; - Istoteq = model->BSIM4type * (here->BSIM4Igs + here->BSIM4Igcs - - gIstotg * vgs - here->BSIM4gIgcsd * vds - - here->BSIM4gIgcsb * vbs); + Istoteq = model->BSIM4type * (here->BSIM4Igs + here->BSIM4Igcs + - gIstotg * vgs - here->BSIM4gIgcsd * vds + - here->BSIM4gIgcsb * vbs); gIdtotg = here->BSIM4gIgdg + here->BSIM4gIgcdg; gIdtotd = here->BSIM4gIgdd + here->BSIM4gIgcdd; @@ -4775,12 +4780,12 @@ line900: gIdtotb = here->BSIM4gIgcdb; Idtoteq = model->BSIM4type * (here->BSIM4Igd + here->BSIM4Igcd - here->BSIM4gIgdg * vgd - here->BSIM4gIgcdg * vgs - - here->BSIM4gIgcdd * vds - here->BSIM4gIgcdb * vbs); - } - else - { gIstotg = gIstotd = gIstots = gIstotb = Istoteq = 0.0; - gIdtotg = gIdtotd = gIdtots = gIdtotb = Idtoteq = 0.0; - } + - here->BSIM4gIgcdd * vds - here->BSIM4gIgcdb * vbs); + } + else + { gIstotg = gIstotd = gIstots = gIstotb = Istoteq = 0.0; + gIdtotg = gIdtotd = gIdtots = gIdtotb = Idtoteq = 0.0; + } if (model->BSIM4igbMod) { gIbtotg = here->BSIM4gIgbg; @@ -4799,31 +4804,31 @@ line900: gIgtotd = gIstotd + gIdtotd + gIbtotd ; gIgtots = gIstots + gIdtots + gIbtots; gIgtotb = gIstotb + gIdtotb + gIbtotb; - Igtoteq = Istoteq + Idtoteq + Ibtoteq; - } - else - gIgtotg = gIgtotd = gIgtots = gIgtotb = Igtoteq = 0.0; + Igtoteq = Istoteq + Idtoteq + Ibtoteq; + } + else { + gIgtotg = gIgtotd = gIgtots = gIgtotb = Igtoteq = 0.0; + } - - if (here->BSIM4rgateMod == 2) - T0 = vges - vgs; - else if (here->BSIM4rgateMod == 3) - T0 = vgms - vgs; - if (here->BSIM4rgateMod > 1) - { gcrgd = here->BSIM4gcrgd * T0; - gcrgg = here->BSIM4gcrgg * T0; - gcrgs = here->BSIM4gcrgs * T0; - gcrgb = here->BSIM4gcrgb * T0; - ceqgcrg = -(gcrgd * vds + gcrgg * vgs - + gcrgb * vbs); - gcrgg -= here->BSIM4gcrg; - gcrg = here->BSIM4gcrg; - } - else - ceqgcrg = gcrg = gcrgd = gcrgg = gcrgs = gcrgb = 0.0; + if (here->BSIM4rgateMod == 2) + T0 = vges - vgs; + else if (here->BSIM4rgateMod == 3) + T0 = vgms - vgs; + if (here->BSIM4rgateMod > 1) + { gcrgd = here->BSIM4gcrgd * T0; + gcrgg = here->BSIM4gcrgg * T0; + gcrgs = here->BSIM4gcrgs * T0; + gcrgb = here->BSIM4gcrgb * T0; + ceqgcrg = -(gcrgd * vds + gcrgg * vgs + + gcrgb * vbs); + gcrgg -= here->BSIM4gcrg; + gcrg = here->BSIM4gcrg; } else - { Gm = -here->BSIM4gm; + ceqgcrg = gcrg = gcrgd = gcrgg = gcrgs = gcrgb = 0.0; + } + else + { Gm = -here->BSIM4gm; Gmbs = -here->BSIM4gmbs; FwdSum = 0.0; RevSum = -(Gm + Gmbs); @@ -4831,15 +4836,15 @@ line900: ceqdrn = -model->BSIM4type * (cdrain + here->BSIM4gds * vds + Gm * vgd + Gmbs * vbd); - ceqbs = model->BSIM4type * (here->BSIM4csub + here->BSIM4Igisl + ceqbs = model->BSIM4type * (here->BSIM4csub + here->BSIM4Igisl + (here->BSIM4gbds + here->BSIM4ggisls) * vds - - (here->BSIM4gbgs + here->BSIM4ggislg) * vgd + - (here->BSIM4gbgs + here->BSIM4ggislg) * vgd - (here->BSIM4gbbs + here->BSIM4ggislb) * vbd); - ceqbd = model->BSIM4type * (here->BSIM4Igidl - here->BSIM4ggidld * vds - - here->BSIM4ggidlg * vgs - here->BSIM4ggidlb * vbs); + ceqbd = model->BSIM4type * (here->BSIM4Igidl - here->BSIM4ggidld * vds + - here->BSIM4ggidlg * vgs - here->BSIM4ggidlb * vbs); gbbsp = -(here->BSIM4gbds); - gbbdp = here->BSIM4gbds + here->BSIM4gbgs + here->BSIM4gbbs; + gbbdp = here->BSIM4gbds + here->BSIM4gbgs + here->BSIM4gbbs; gbdpg = 0.0; gbdpsp = 0.0; @@ -4858,7 +4863,7 @@ line900: gIstotb = here->BSIM4gIgcdb; Istoteq = model->BSIM4type * (here->BSIM4Igs + here->BSIM4Igcd - here->BSIM4gIgsg * vgs - here->BSIM4gIgcdg * vgd - + here->BSIM4gIgcdd * vds - here->BSIM4gIgcdb * vbd); + + here->BSIM4gIgcdd * vds - here->BSIM4gIgcdb * vbd); gIdtotg = here->BSIM4gIgdg + here->BSIM4gIgcsg; gIdtotd = here->BSIM4gIgdd + here->BSIM4gIgcss; @@ -4938,215 +4943,216 @@ line900: gdtot = gdtotd = gdtotg = gdtots = gdtotb = ceqgdtot = 0.0; } - if (model->BSIM4type > 0) + if (model->BSIM4type > 0) { ceqjs = (here->BSIM4cbs - here->BSIM4gbs * vbs_jct); ceqjd = (here->BSIM4cbd - here->BSIM4gbd * vbd_jct); } - else - { ceqjs = -(here->BSIM4cbs - here->BSIM4gbs * vbs_jct); + else + { ceqjs = -(here->BSIM4cbs - here->BSIM4gbs * vbs_jct); ceqjd = -(here->BSIM4cbd - here->BSIM4gbd * vbd_jct); ceqqg = -ceqqg; ceqqd = -ceqqd; ceqqb = -ceqqb; - ceqgcrg = -ceqgcrg; + ceqgcrg = -ceqgcrg; if (here->BSIM4trnqsMod) { cqdef = -cqdef; cqcheq = -cqcheq; - } + } if (here->BSIM4rbodyMod) { ceqqjs = -ceqqjs; ceqqjd = -ceqqjd; } - if (here->BSIM4rgateMod == 3) - ceqqgmid = -ceqqgmid; - } + if (here->BSIM4rgateMod == 3) + ceqqgmid = -ceqqgmid; + } /* * Loading RHS */ - m = here->BSIM4m; + m = here->BSIM4m; + mult_i = here->BSIM4mult_i; + mult_q = here->BSIM4mult_q; #ifdef USE_OMP - here->BSIM4rhsdPrime = m * (ceqjd - ceqbd + ceqgdtot - - ceqdrn - ceqqd + Idtoteq); - here->BSIM4rhsgPrime = m * (ceqqg - ceqgcrg + Igtoteq); + here->BSIM4rhsdPrime = (mult_i * (ceqjd - ceqbd + ceqgdtot + - ceqdrn + Idtoteq) - mult_q * ceqqd); + here->BSIM4rhsgPrime = mult_q * ceqqg - mult_i * (ceqgcrg - Igtoteq); if (here->BSIM4rgateMod == 2) - here->BSIM4rhsgExt = m * ceqgcrg; + here->BSIM4rhsgExt = mult_i * ceqgcrg; else if (here->BSIM4rgateMod == 3) - here->BSIM4grhsMid = m * (ceqqgmid + ceqgcrg); + here->BSIM4grhsMid = mult_q * ceqqgmid + mult_i * ceqgcrg; if (!here->BSIM4rbodyMod) - { here->BSIM4rhsbPrime = m * (ceqbd + ceqbs - ceqjd - - ceqjs - ceqqb + Ibtoteq); - here->BSIM4rhssPrime = m * (ceqdrn - ceqbs + ceqjs - + ceqqg + ceqqb + ceqqd + ceqqgmid - ceqgstot + Istoteq); + { here->BSIM4rhsbPrime = (mult_i * (ceqbd + ceqbs - ceqjd + - ceqjs + Ibtoteq) - mult_q * ceqqb); + here->BSIM4rhssPrime = (mult_i * (ceqdrn - ceqbs + ceqjs + - ceqgstot + Istoteq) + mult_q * (ceqqg + ceqqb + ceqqd + ceqqgmid)); } else - { here->BSIM4rhsdb = m * (ceqjd + ceqqjd); - here->BSIM4rhsbPrime = m * (ceqbd + ceqbs - ceqqb + Ibtoteq); - here->BSIM4rhssb = m * (ceqjs + ceqqjs); - here->BSIM4rhssPrime = m * (ceqdrn - ceqbs + ceqjs + ceqqd - + ceqqg + ceqqb + ceqqjd + ceqqjs + ceqqgmid - ceqgstot + Istoteq); + { here->BSIM4rhsdb = mult_i * (ceqjd + ceqqjd); + here->BSIM4rhsbPrime = (mult_i * (ceqbd + ceqbs + Ibtoteq) - mult_q * ceqqb); + here->BSIM4rhssb = mult_i * (ceqjs + ceqqjs); + here->BSIM4rhssPrime = (mult_i * (ceqdrn - ceqbs + ceqjs - ceqgstot + Istoteq) + mult_q * (ceqqd + + ceqqg + ceqqb + ceqqjd + ceqqjs + ceqqgmid)); } if (model->BSIM4rdsMod) - { here->BSIM4rhsd = m * ceqgdtot; - here->BSIM4rhss = m * ceqgstot; + { here->BSIM4rhsd = mult_i * ceqgdtot; + here->BSIM4rhss = mult_i * ceqgstot; } if (here->BSIM4trnqsMod) here->BSIM4rhsq = m * (cqcheq - cqdef); #else - (*(ckt->CKTrhs + here->BSIM4dNodePrime) += m * (ceqjd - ceqbd + ceqgdtot - - ceqdrn - ceqqd + Idtoteq)); - (*(ckt->CKTrhs + here->BSIM4gNodePrime) -= m * (ceqqg - ceqgcrg + Igtoteq)); + (*(ckt->CKTrhs + here->BSIM4dNodePrime) += (mult_i * (ceqjd - ceqbd + ceqgdtot + - ceqdrn + Idtoteq) - mult_q * ceqqd)); + (*(ckt->CKTrhs + here->BSIM4gNodePrime) -= mult_q * ceqqg - mult_i * (ceqgcrg - Igtoteq)); - if (here->BSIM4rgateMod == 2) - (*(ckt->CKTrhs + here->BSIM4gNodeExt) -= m * ceqgcrg); - else if (here->BSIM4rgateMod == 3) - (*(ckt->CKTrhs + here->BSIM4gNodeMid) -= m * (ceqqgmid + ceqgcrg)); - - if (!here->BSIM4rbodyMod) - { (*(ckt->CKTrhs + here->BSIM4bNodePrime) += m * (ceqbd + ceqbs - ceqjd - - ceqjs - ceqqb + Ibtoteq)); - (*(ckt->CKTrhs + here->BSIM4sNodePrime) += m * (ceqdrn - ceqbs + ceqjs - + ceqqg + ceqqb + ceqqd + ceqqgmid - ceqgstot + Istoteq)); - } - - else - { (*(ckt->CKTrhs + here->BSIM4dbNode) -= m * (ceqjd + ceqqjd)); - (*(ckt->CKTrhs + here->BSIM4bNodePrime) += m * (ceqbd + ceqbs - ceqqb + Ibtoteq)); - (*(ckt->CKTrhs + here->BSIM4sbNode) -= m * (ceqjs + ceqqjs)); - (*(ckt->CKTrhs + here->BSIM4sNodePrime) += m * (ceqdrn - ceqbs + ceqjs + ceqqd - + ceqqg + ceqqb + ceqqjd + ceqqjs + ceqqgmid - ceqgstot + Istoteq)); - } - - if (model->BSIM4rdsMod) - { (*(ckt->CKTrhs + here->BSIM4dNode) -= m * ceqgdtot); - (*(ckt->CKTrhs + here->BSIM4sNode) += m * ceqgstot); - } - - if (here->BSIM4trnqsMod) - *(ckt->CKTrhs + here->BSIM4qNode) += m * (cqcheq - cqdef); -#endif - - /* - * Loading matrix - */ + if (here->BSIM4rgateMod == 2) + (*(ckt->CKTrhs + here->BSIM4gNodeExt) -= mult_i * ceqgcrg); + else if (here->BSIM4rgateMod == 3) + (*(ckt->CKTrhs + here->BSIM4gNodeMid) -= mult_q * ceqqgmid + mult_i * ceqgcrg); if (!here->BSIM4rbodyMod) + { (*(ckt->CKTrhs + here->BSIM4bNodePrime) += (mult_i * (ceqbd + ceqbs - ceqjd + - ceqjs + Ibtoteq) - mult_q * ceqqb)); + (*(ckt->CKTrhs + here->BSIM4sNodePrime) += (mult_i * (ceqdrn - ceqbs + ceqjs + - ceqgstot + Istoteq) + mult_q * (ceqqg + ceqqb + ceqqd + ceqqgmid))); + } + else + { (*(ckt->CKTrhs + here->BSIM4dbNode) -= mult_i * (ceqjd + ceqqjd)); + (*(ckt->CKTrhs + here->BSIM4bNodePrime) += (mult_i * (ceqbd + ceqbs + Ibtoteq) - mult_q * ceqqb)); + (*(ckt->CKTrhs + here->BSIM4sbNode) -= mult_i * (ceqjs + ceqqjs)); + (*(ckt->CKTrhs + here->BSIM4sNodePrime) += (mult_i * (ceqdrn - ceqbs + ceqjs - ceqgstot + Istoteq) + mult_q * (ceqqd + + ceqqg + ceqqb + ceqqjd + ceqqjs + ceqqgmid))); + } + + if (model->BSIM4rdsMod) + { (*(ckt->CKTrhs + here->BSIM4dNode) -= mult_i * ceqgdtot); + (*(ckt->CKTrhs + here->BSIM4sNode) += mult_i * ceqgstot); + } + + if (here->BSIM4trnqsMod) + *(ckt->CKTrhs + here->BSIM4qNode) += m * (cqcheq - cqdef); +#endif + + /* + * Loading matrix + */ + + if (!here->BSIM4rbodyMod) { gjbd = here->BSIM4gbd; gjbs = here->BSIM4gbs; } - else - gjbd = gjbs = 0.0; + else + gjbd = gjbs = 0.0; - if (!model->BSIM4rdsMod) - { gdpr = here->BSIM4drainConductance; - gspr = here->BSIM4sourceConductance; - } - else - gdpr = gspr = 0.0; + if (!model->BSIM4rdsMod) + { gdpr = here->BSIM4drainConductance; + gspr = here->BSIM4sourceConductance; + } + else + gdpr = gspr = 0.0; - geltd = here->BSIM4grgeltd; + geltd = here->BSIM4grgeltd; + + T1 = qdef * here->BSIM4gtau; - T1 = qdef * here->BSIM4gtau; #ifdef USE_OMP if (here->BSIM4rgateMod == 1) - { here->BSIM4_1 = m * geltd; - here->BSIM4_2 = m * geltd; - here->BSIM4_3 = m * geltd; - here->BSIM4_4 = m * (gcggb + geltd - ggtg + gIgtotg); - here->BSIM4_5 = m * (gcgdb - ggtd + gIgtotd); - here->BSIM4_6 = m * (gcgsb - ggts + gIgtots); - here->BSIM4_7 = m * (gcgbb - ggtb + gIgtotb); + { here->BSIM4_1 = mult_i * geltd; + here->BSIM4_2 = mult_i * geltd; + here->BSIM4_3 = mult_i * geltd; + here->BSIM4_4 = mult_q * (gcggb - ggtg) + mult_i * (geltd + gIgtotg); + here->BSIM4_5 = mult_q * (gcgdb - ggtd) + mult_i * gIgtotd; + here->BSIM4_6 = mult_q * (gcgsb - ggts) + mult_i * gIgtots; + here->BSIM4_7 = mult_q * (gcgbb - ggtb) + mult_i * gIgtotb; } /* WDLiu: gcrg already subtracted from all gcrgg below */ - else if (here->BSIM4rgateMod == 2) - { here->BSIM4_8 = m * gcrg; - here->BSIM4_9 = m * gcrgg; - here->BSIM4_10 = m * gcrgd; - here->BSIM4_11 = m * gcrgs; - here->BSIM4_12 = m * gcrgb; + else if (here->BSIM4rgateMod == 2) + { here->BSIM4_8 = mult_i * gcrg; + here->BSIM4_9 = mult_i * gcrgg; + here->BSIM4_10 = mult_i * gcrgd; + here->BSIM4_11 = mult_i * gcrgs; + here->BSIM4_12 = mult_i * gcrgb; - here->BSIM4_13 = m * gcrg; - here->BSIM4_14 = m * (gcggb - gcrgg - ggtg + gIgtotg); - here->BSIM4_15 = m * (gcgdb - gcrgd - ggtd + gIgtotd); - here->BSIM4_16 = m * (gcgsb - gcrgs - ggts + gIgtots); - here->BSIM4_17 = m * (gcgbb - gcrgb - ggtb + gIgtotb); + here->BSIM4_13 = mult_i * gcrg; + here->BSIM4_14 = mult_q * (gcggb - ggtg) + mult_i * (gIgtotg - gcrgg); + here->BSIM4_15 = mult_q * (gcgdb - ggtd) + mult_i * (gIgtotd - gcrgd); + here->BSIM4_16 = mult_q * (gcgsb - ggts) + mult_i * (gIgtots - gcrgs); + here->BSIM4_17 = mult_q * (gcgbb - ggtb) + mult_i * (gIgtotb - gcrgb); } else if (here->BSIM4rgateMod == 3) - { here->BSIM4_18 = m * geltd; - here->BSIM4_19 = m * geltd; - here->BSIM4_20 = m * geltd; - here->BSIM4_21 = m * (geltd + gcrg + gcgmgmb); + { here->BSIM4_18 = mult_i * geltd; + here->BSIM4_19 = mult_i * geltd; + here->BSIM4_20 = mult_i * geltd; + here->BSIM4_21 = mult_i * (geltd + gcrg) + mult_q * gcgmgmb; - here->BSIM4_22 = m * (gcrgd + gcgmdb); - here->BSIM4_23 = m * gcrgg; - here->BSIM4_24 = m * (gcrgs + gcgmsb); - here->BSIM4_25 = m * (gcrgb + gcgmbb); + here->BSIM4_22 = mult_i * gcrgd + mult_q * gcgmdb; + here->BSIM4_23 = mult_i * gcrgg; + here->BSIM4_24 = mult_i * gcrgs + mult_q * gcgmsb; + here->BSIM4_25 = mult_i * gcrgb + mult_q * gcgmbb; - here->BSIM4_26 = m * gcdgmb; - here->BSIM4_27 = m * gcrg; - here->BSIM4_28 = m * gcsgmb; - here->BSIM4_29 = m * gcbgmb; + here->BSIM4_26 = mult_q * gcdgmb; + here->BSIM4_27 = mult_i * gcrg; + here->BSIM4_28 = mult_q * gcsgmb; + here->BSIM4_29 = mult_q * gcbgmb; - here->BSIM4_30 = m * (gcggb - gcrgg - ggtg + gIgtotg); - here->BSIM4_31 = m * (gcgdb - gcrgd - ggtd + gIgtotd); - here->BSIM4_32 = m * (gcgsb - gcrgs - ggts + gIgtots); - here->BSIM4_33 = m * (gcgbb - gcrgb - ggtb + gIgtotb); + here->BSIM4_30 = mult_q * (gcggb - ggtg) + mult_i * (gIgtotg - gcrgg); + here->BSIM4_31 = mult_q * (gcgdb - ggtd) + mult_i * (gIgtotd - gcrgd); + here->BSIM4_32 = mult_q * (gcgsb - ggts) + mult_i * (gIgtots - gcrgs); + here->BSIM4_33 = mult_q * (gcgbb - ggtb) + mult_i * (gIgtotb - gcrgb); } else - { here->BSIM4_34 = m * (gcggb - ggtg + gIgtotg); - here->BSIM4_35 = m * (gcgdb - ggtd + gIgtotd); - here->BSIM4_36 = m * (gcgsb - ggts + gIgtots); - here->BSIM4_37 = m * (gcgbb - ggtb + gIgtotb); + { here->BSIM4_34 = mult_q * (gcggb - ggtg) + mult_i * gIgtotg; + here->BSIM4_35 = mult_q * (gcgdb - ggtd) + mult_i * gIgtotd; + here->BSIM4_36 = mult_q * (gcgsb - ggts) + mult_i * gIgtots; + here->BSIM4_37 = mult_q * (gcgbb - ggtb) + mult_i * gIgtotb; } if (model->BSIM4rdsMod) - { here->BSIM4_38 = m * gdtotg; - here->BSIM4_39 = m * gdtots; - here->BSIM4_40 = m * gdtotb; - here->BSIM4_41 = m * gstotd; - here->BSIM4_42 = m * gstotg; - here->BSIM4_43 = m * gstotb; + { here->BSIM4_38 = mult_i * gdtotg; + here->BSIM4_39 = mult_i * gdtots; + here->BSIM4_40 = mult_i * gdtotb; + here->BSIM4_41 = mult_i * gstotd; + here->BSIM4_42 = mult_i * gstotg; + here->BSIM4_43 = mult_i * gstotb; } - here->BSIM4_44 = m * (gdpr + here->BSIM4gds + here->BSIM4gbd + T1 * ddxpart_dVd - - gdtotd + RevSum + gcddb + gbdpdp + dxpart * ggtd - gIdtotd); - here->BSIM4_45 = m * (gdpr + gdtot); - here->BSIM4_46 = m * (Gm + gcdgb - gdtotg + gbdpg - gIdtotg - + dxpart * ggtg + T1 * ddxpart_dVg); - here->BSIM4_47 = m * (here->BSIM4gds + gdtots - dxpart * ggts + gIdtots - - T1 * ddxpart_dVs + FwdSum - gcdsb - gbdpsp); - here->BSIM4_48 = m * (gjbd + gdtotb - Gmbs - gcdbb - gbdpb + gIdtotb - - T1 * ddxpart_dVb - dxpart * ggtb); + here->BSIM4_44 = mult_i * (gdpr + here->BSIM4gds + here->BSIM4gbd + - gdtotd + RevSum + gbdpdp - gIdtotd) + mult_q * (T1 * ddxpart_dVd + gcddb + dxpart * ggtd); + here->BSIM4_45 = mult_i * (gdpr + gdtot); + here->BSIM4_46 = mult_i * (Gm - gdtotg + gbdpg - gIdtotg) + + mult_q * (dxpart * ggtg + T1 * ddxpart_dVg + gcdgb); + here->BSIM4_47 = mult_i * (here->BSIM4gds + gdtots + gIdtots + + FwdSum - gbdpsp) - mult_q * (dxpart * ggts + T1 * ddxpart_dVs + gcdsb); + here->BSIM4_48 = mult_i * (gjbd + gdtotb - Gmbs - gbdpb + gIdtotb) + - mult_q * (dxpart * ggtb + gcdbb + T1 * ddxpart_dVb); - here->BSIM4_49 = m * (gdpr - gdtotd); - here->BSIM4_50 = m * (gdpr + gdtot); + here->BSIM4_49 = mult_i * (gdpr - gdtotd); + here->BSIM4_50 = mult_i * (gdpr + gdtot); - here->BSIM4_51 = m * (here->BSIM4gds + gstotd + RevSum - gcsdb - gbspdp - - T1 * dsxpart_dVd - sxpart * ggtd + gIstotd); - here->BSIM4_52 = m * (gcsgb - Gm - gstotg + gbspg + sxpart * ggtg - + T1 * dsxpart_dVg - gIstotg); - here->BSIM4_53 = m * (gspr + here->BSIM4gds + here->BSIM4gbs + T1 * dsxpart_dVs - - gstots + FwdSum + gcssb + gbspsp + sxpart * ggts - gIstots); - here->BSIM4_54 = m * (gspr + gstot); - here->BSIM4_55 = m * (gjbs + gstotb + Gmbs - gcsbb - gbspb - sxpart * ggtb - - T1 * dsxpart_dVb + gIstotb); + here->BSIM4_51 = mult_i * (here->BSIM4gds + gstotd + RevSum - gbspdp + gIstotd) + - mult_q * (T1 * dsxpart_dVd + sxpart * ggtd + gcsdb); + here->BSIM4_52 = mult_q * (gcsgb + sxpart * ggtg + T1 * dsxpart_dVg) + mult_i * (gbspg - Gm - gstotg - gIstotg); + here->BSIM4_53 = mult_i * (gspr + here->BSIM4gds + here->BSIM4gbs - gIstots - gstots + FwdSum + gbspsp) + + mult_q * (sxpart * ggts + T1 * dsxpart_dVs + gcssb); + here->BSIM4_54 = mult_i * (gspr + gstot); + here->BSIM4_55 = mult_i * (gjbs + gstotb + Gmbs - gbspb + gIstotb) - mult_q * (gcsbb + sxpart * ggtb + T1 * dsxpart_dVb); - here->BSIM4_56 = m * (gspr - gstots); - here->BSIM4_57 = m * (gspr + gstot); + here->BSIM4_56 = mult_i * (gspr - gstots); + here->BSIM4_57 = mult_i * (gspr + gstot); - here->BSIM4_58 = m * (gcbdb - gjbd + gbbdp - gIbtotd); - here->BSIM4_59 = m * (gcbgb - here->BSIM4gbgs - gIbtotg); - here->BSIM4_60 = m * (gcbsb - gjbs + gbbsp - gIbtots); - here->BSIM4_61 = m * (gjbd + gjbs + gcbbb - here->BSIM4gbbs - gIbtotb); + here->BSIM4_58 = mult_q * gcbdb - mult_i * (gjbd - gbbdp + gIbtotd); + here->BSIM4_59 = mult_q * gcbgb - mult_i * (here->BSIM4gbgs + gIbtotg); + here->BSIM4_60 = mult_q * gcbsb - mult_i * (gjbs - gbbsp + gIbtots); + here->BSIM4_61 = mult_i * (gjbd + gjbs - here->BSIM4gbbs + - gIbtotb) + mult_q * gcbbb; ggidld = here->BSIM4ggidld; ggidlg = here->BSIM4ggidlg; @@ -5156,52 +5162,51 @@ line900: ggislb = here->BSIM4ggislb; /* stamp gidl */ - here->BSIM4_62 = m * ggidld; - here->BSIM4_63 = m * ggidlg; - here->BSIM4_64 = m * (ggidlg + ggidld + ggidlb); - here->BSIM4_65 = m * ggidlb; - here->BSIM4_66 = m * ggidld; - here->BSIM4_67 = m * ggidlg; - here->BSIM4_68 = m * (ggidlg + ggidld + ggidlb); - here->BSIM4_69 = m * ggidlb; + here->BSIM4_62 = mult_i * ggidld; + here->BSIM4_63 = mult_i * ggidlg; + here->BSIM4_64 = mult_i * (ggidlg + ggidld + ggidlb); + here->BSIM4_65 = mult_i * ggidlb; + here->BSIM4_66 = mult_i * ggidld; + here->BSIM4_67 = mult_i * ggidlg; + here->BSIM4_68 = mult_i * (ggidlg + ggidld + ggidlb); + here->BSIM4_69 = mult_i * ggidlb; /* stamp gisl */ - here->BSIM4_70 = m * (ggisls + ggislg + ggislb); - here->BSIM4_71 = m * ggislg; - here->BSIM4_72 = m * ggisls; - here->BSIM4_73 = m * ggislb; - here->BSIM4_74 = m * (ggislg + ggisls + ggislb); - here->BSIM4_75 = m * ggislg; - here->BSIM4_76 = m * ggisls; - here->BSIM4_77 = m * ggislb; + here->BSIM4_70 = mult_i * (ggisls + ggislg + ggislb); + here->BSIM4_71 = mult_i * ggislg; + here->BSIM4_72 = mult_i * ggisls; + here->BSIM4_73 = mult_i * ggislb; + here->BSIM4_74 = mult_i * (ggislg + ggisls + ggislb); + here->BSIM4_75 = mult_i * ggislg; + here->BSIM4_76 = mult_i * ggisls; + here->BSIM4_77 = mult_i * ggislb; if (here->BSIM4rbodyMod) - { here->BSIM4_78 = m * (gcdbdb - here->BSIM4gbd); - here->BSIM4_79 = m * (here->BSIM4gbs - gcsbsb); + { here->BSIM4_78 = mult_q * gcdbdb - mult_i * here->BSIM4gbd; + here->BSIM4_79 = mult_i * here->BSIM4gbs - mult_q * gcsbsb; - here->BSIM4_80 = m * (gcdbdb - here->BSIM4gbd); - here->BSIM4_81 = m * (here->BSIM4gbd - gcdbdb - + here->BSIM4grbpd + here->BSIM4grbdb); - here->BSIM4_82 = m * here->BSIM4grbpd; - here->BSIM4_83 = m * here->BSIM4grbdb; + here->BSIM4_80 = mult_q * gcdbdb - mult_i * here->BSIM4gbd; + here->BSIM4_81 = mult_i * (here->BSIM4gbd + here->BSIM4grbpd + here->BSIM4grbdb) - mult_q * gcdbdb; + here->BSIM4_82 = mult_i * here->BSIM4grbpd; + here->BSIM4_83 = mult_i * here->BSIM4grbdb; - here->BSIM4_84 = m * here->BSIM4grbpd; - here->BSIM4_85 = m * here->BSIM4grbpb; - here->BSIM4_86 = m * here->BSIM4grbps; - here->BSIM4_87 = m * (here->BSIM4grbpd + here->BSIM4grbps + here->BSIM4_84 = mult_i * here->BSIM4grbpd; + here->BSIM4_85 = mult_i * here->BSIM4grbpb; + here->BSIM4_86 = mult_i * here->BSIM4grbps; + here->BSIM4_87 = mult_i * (here->BSIM4grbpd + here->BSIM4grbps + here->BSIM4grbpb); - /* WDLiu: (gcbbb - here->BSIM4gbbs) already added to BPbpPtr */ + /* WDLiu: (gcbbb - here->BSIM4gbbs) already added to BPbpPtr */ - here->BSIM4_88 = m * (gcsbsb - here->BSIM4gbs); - here->BSIM4_89 = m * here->BSIM4grbps; - here->BSIM4_90 = m * here->BSIM4grbsb; - here->BSIM4_91 = m * (here->BSIM4gbs - gcsbsb + here->BSIM4_88 = mult_q * gcsbsb - mult_i * here->BSIM4gbs; + here->BSIM4_89 = mult_i * here->BSIM4grbps; + here->BSIM4_90 = mult_i * here->BSIM4grbsb; + here->BSIM4_91 = mult_i * (here->BSIM4gbs - gcsbsb + here->BSIM4grbps + here->BSIM4grbsb); - here->BSIM4_92 = m * here->BSIM4grbdb; - here->BSIM4_93 = m * here->BSIM4grbpb; - here->BSIM4_94 = m * here->BSIM4grbsb; - here->BSIM4_95 = m * (here->BSIM4grbsb + here->BSIM4grbdb - + here->BSIM4grbpb); + here->BSIM4_92 = mult_i * here->BSIM4grbdb; + here->BSIM4_93 = mult_i * here->BSIM4grbpb; + here->BSIM4_94 = mult_i * here->BSIM4grbsb; + here->BSIM4_95 = mult_i * (here->BSIM4grbsb + here->BSIM4grbdb + + here->BSIM4grbpb); } if (here->BSIM4trnqsMod) @@ -5217,95 +5222,92 @@ line900: } #else if (here->BSIM4rgateMod == 1) - { (*(here->BSIM4GEgePtr) += m * geltd); - (*(here->BSIM4GPgePtr) -= m * geltd); - (*(here->BSIM4GEgpPtr) -= m * geltd); - (*(here->BSIM4GPgpPtr) += m * (gcggb + geltd - ggtg + gIgtotg)); - (*(here->BSIM4GPdpPtr) += m * (gcgdb - ggtd + gIgtotd)); - (*(here->BSIM4GPspPtr) += m * (gcgsb - ggts + gIgtots)); - (*(here->BSIM4GPbpPtr) += m * (gcgbb - ggtb + gIgtotb)); + { (*(here->BSIM4GEgePtr) += mult_i * geltd); + (*(here->BSIM4GPgePtr) -= mult_i * geltd); + (*(here->BSIM4GEgpPtr) -= mult_i * geltd); + (*(here->BSIM4GPgpPtr) += mult_q * (gcggb - ggtg) + mult_i * (geltd + gIgtotg)); + (*(here->BSIM4GPdpPtr) += mult_q * (gcgdb - ggtd) + mult_i * gIgtotd); + (*(here->BSIM4GPspPtr) += mult_q * (gcgsb - ggts) + mult_i * gIgtots); + (*(here->BSIM4GPbpPtr) += mult_q * (gcgbb - ggtb) + mult_i * gIgtotb); } /* WDLiu: gcrg already subtracted from all gcrgg below */ - else if (here->BSIM4rgateMod == 2) - { (*(here->BSIM4GEgePtr) += m * gcrg); - (*(here->BSIM4GEgpPtr) += m * gcrgg); - (*(here->BSIM4GEdpPtr) += m * gcrgd); - (*(here->BSIM4GEspPtr) += m * gcrgs); - (*(here->BSIM4GEbpPtr) += m * gcrgb); + else if (here->BSIM4rgateMod == 2) + { (*(here->BSIM4GEgePtr) += mult_i * gcrg); + (*(here->BSIM4GEgpPtr) += mult_i * gcrgg); + (*(here->BSIM4GEdpPtr) += mult_i * gcrgd); + (*(here->BSIM4GEspPtr) += mult_i * gcrgs); + (*(here->BSIM4GEbpPtr) += mult_i * gcrgb); - (*(here->BSIM4GPgePtr) -= m * gcrg); - (*(here->BSIM4GPgpPtr) += m * (gcggb - gcrgg - ggtg + gIgtotg)); - (*(here->BSIM4GPdpPtr) += m * (gcgdb - gcrgd - ggtd + gIgtotd)); - (*(here->BSIM4GPspPtr) += m * (gcgsb - gcrgs - ggts + gIgtots)); - (*(here->BSIM4GPbpPtr) += m * (gcgbb - gcrgb - ggtb + gIgtotb)); + (*(here->BSIM4GPgePtr) -= mult_i * gcrg); + (*(here->BSIM4GPgpPtr) += mult_q * (gcggb - ggtg) + mult_i * (gIgtotg - gcrgg)); + (*(here->BSIM4GPdpPtr) += mult_q * (gcgdb - ggtd) + mult_i * (gIgtotd - gcrgd)); + (*(here->BSIM4GPspPtr) += mult_q * (gcgsb - ggts) + mult_i * (gIgtots - gcrgs)); + (*(here->BSIM4GPbpPtr) += mult_q * (gcgbb - ggtb) + mult_i * (gIgtotb - gcrgb)); } else if (here->BSIM4rgateMod == 3) - { (*(here->BSIM4GEgePtr) += m * geltd); - (*(here->BSIM4GEgmPtr) -= m * geltd); - (*(here->BSIM4GMgePtr) -= m * geltd); - (*(here->BSIM4GMgmPtr) += m * (geltd + gcrg + gcgmgmb)); + { (*(here->BSIM4GEgePtr) += mult_i * geltd); + (*(here->BSIM4GEgmPtr) -= mult_i * geltd); + (*(here->BSIM4GMgePtr) -= mult_i * geltd); + (*(here->BSIM4GMgmPtr) += mult_i * (geltd + gcrg) + mult_q * gcgmgmb); - (*(here->BSIM4GMdpPtr) += m * (gcrgd + gcgmdb)); - (*(here->BSIM4GMgpPtr) += m * gcrgg); - (*(here->BSIM4GMspPtr) += m * (gcrgs + gcgmsb)); - (*(here->BSIM4GMbpPtr) += m * (gcrgb + gcgmbb)); + (*(here->BSIM4GMdpPtr) += mult_i * gcrgd + mult_q * gcgmdb); + (*(here->BSIM4GMgpPtr) += mult_i * gcrgg); + (*(here->BSIM4GMspPtr) += mult_i * gcrgs + mult_q * gcgmsb); + (*(here->BSIM4GMbpPtr) += mult_i * gcrgb + mult_q * gcgmbb); - (*(here->BSIM4DPgmPtr) += m * gcdgmb); - (*(here->BSIM4GPgmPtr) -= m * gcrg); - (*(here->BSIM4SPgmPtr) += m * gcsgmb); - (*(here->BSIM4BPgmPtr) += m * gcbgmb); + (*(here->BSIM4DPgmPtr) += mult_q * gcdgmb); + (*(here->BSIM4GPgmPtr) -= mult_i * gcrg); + (*(here->BSIM4SPgmPtr) += mult_q * gcsgmb); + (*(here->BSIM4BPgmPtr) += mult_q * gcbgmb); - (*(here->BSIM4GPgpPtr) += m * (gcggb - gcrgg - ggtg + gIgtotg)); - (*(here->BSIM4GPdpPtr) += m * (gcgdb - gcrgd - ggtd + gIgtotd)); - (*(here->BSIM4GPspPtr) += m * (gcgsb - gcrgs - ggts + gIgtots)); - (*(here->BSIM4GPbpPtr) += m * (gcgbb - gcrgb - ggtb + gIgtotb)); + (*(here->BSIM4GPgpPtr) += mult_q * (gcggb - ggtg) + mult_i * (gIgtotg - gcrgg)); + (*(here->BSIM4GPdpPtr) += mult_q * (gcgdb - ggtd) + mult_i * (gIgtotd - gcrgd)); + (*(here->BSIM4GPspPtr) += mult_q * (gcgsb - ggts) + mult_i * (gIgtots - gcrgs)); + (*(here->BSIM4GPbpPtr) += mult_q * (gcgbb - ggtb) + mult_i * (gIgtotb - gcrgb)); } - else - { (*(here->BSIM4GPgpPtr) += m * (gcggb - ggtg + gIgtotg)); - (*(here->BSIM4GPdpPtr) += m * (gcgdb - ggtd + gIgtotd)); - (*(here->BSIM4GPspPtr) += m * (gcgsb - ggts + gIgtots)); - (*(here->BSIM4GPbpPtr) += m * (gcgbb - ggtb + gIgtotb)); + else + { (*(here->BSIM4GPgpPtr) += mult_q * (gcggb - ggtg) + mult_i * gIgtotg); + (*(here->BSIM4GPdpPtr) += mult_q * (gcgdb - ggtd) + mult_i * gIgtotd); + (*(here->BSIM4GPspPtr) += mult_q * (gcgsb - ggts) + mult_i * gIgtots); + (*(here->BSIM4GPbpPtr) += mult_q * (gcgbb - ggtb) + mult_i * gIgtotb); } if (model->BSIM4rdsMod) - { (*(here->BSIM4DgpPtr) += m * gdtotg); - (*(here->BSIM4DspPtr) += m * gdtots); - (*(here->BSIM4DbpPtr) += m * gdtotb); - (*(here->BSIM4SdpPtr) += m * gstotd); - (*(here->BSIM4SgpPtr) += m * gstotg); - (*(here->BSIM4SbpPtr) += m * gstotb); + { (*(here->BSIM4DgpPtr) += mult_i * gdtotg); + (*(here->BSIM4DspPtr) += mult_i * gdtots); + (*(here->BSIM4DbpPtr) += mult_i * gdtotb); + (*(here->BSIM4SdpPtr) += mult_i * gstotd); + (*(here->BSIM4SgpPtr) += mult_i * gstotg); + (*(here->BSIM4SbpPtr) += mult_i * gstotb); } - (*(here->BSIM4DPdpPtr) += m * (gdpr + here->BSIM4gds + here->BSIM4gbd + T1 * ddxpart_dVd - - gdtotd + RevSum + gcddb + gbdpdp + dxpart * ggtd - gIdtotd)); - (*(here->BSIM4DPdPtr) -= m * (gdpr + gdtot)); - (*(here->BSIM4DPgpPtr) += m * (Gm + gcdgb - gdtotg + gbdpg - gIdtotg - + dxpart * ggtg + T1 * ddxpart_dVg)); - (*(here->BSIM4DPspPtr) -= m * (here->BSIM4gds + gdtots - dxpart * ggts + gIdtots - - T1 * ddxpart_dVs + FwdSum - gcdsb - gbdpsp)); - (*(here->BSIM4DPbpPtr) -= m * (gjbd + gdtotb - Gmbs - gcdbb - gbdpb + gIdtotb - - T1 * ddxpart_dVb - dxpart * ggtb)); + (*(here->BSIM4DPdpPtr) += mult_i * (gdpr + here->BSIM4gds + here->BSIM4gbd + - gdtotd + RevSum + gbdpdp - gIdtotd) + mult_q * (T1 * ddxpart_dVd + gcddb + dxpart * ggtd)); + (*(here->BSIM4DPdPtr) -= mult_i * (gdpr + gdtot)); + (*(here->BSIM4DPgpPtr) += mult_i * (Gm - gdtotg + gbdpg - gIdtotg) + + mult_q * (dxpart * ggtg + T1 * ddxpart_dVg + gcdgb)); + (*(here->BSIM4DPspPtr) -= mult_i * (here->BSIM4gds + gdtots + gIdtots + + FwdSum - gbdpsp) - mult_q * (dxpart * ggts + T1 * ddxpart_dVs + gcdsb)); + (*(here->BSIM4DPbpPtr) -= mult_i * (gjbd + gdtotb - Gmbs - gbdpb + gIdtotb) + - mult_q * (dxpart * ggtb + gcdbb + T1 * ddxpart_dVb)); - (*(here->BSIM4DdpPtr) -= m * (gdpr - gdtotd)); - (*(here->BSIM4DdPtr) += m * (gdpr + gdtot)); + (*(here->BSIM4DdpPtr) -= mult_i * (gdpr - gdtotd)); + (*(here->BSIM4DdPtr) += mult_i * (gdpr + gdtot)); - (*(here->BSIM4SPdpPtr) -= m * (here->BSIM4gds + gstotd + RevSum - gcsdb - gbspdp - - T1 * dsxpart_dVd - sxpart * ggtd + gIstotd)); - (*(here->BSIM4SPgpPtr) += m * (gcsgb - Gm - gstotg + gbspg + sxpart * ggtg - + T1 * dsxpart_dVg - gIstotg)); - (*(here->BSIM4SPspPtr) += m * (gspr + here->BSIM4gds + here->BSIM4gbs + T1 * dsxpart_dVs - - gstots + FwdSum + gcssb + gbspsp + sxpart * ggts - gIstots)); - (*(here->BSIM4SPsPtr) -= m * (gspr + gstot)); - (*(here->BSIM4SPbpPtr) -= m * (gjbs + gstotb + Gmbs - gcsbb - gbspb - sxpart * ggtb - - T1 * dsxpart_dVb + gIstotb)); + (*(here->BSIM4SPdpPtr) -= mult_i * (here->BSIM4gds + gstotd + RevSum - gbspdp + gIstotd) + - mult_q * (T1 * dsxpart_dVd + sxpart * ggtd + gcsdb)); + (*(here->BSIM4SPgpPtr) += mult_q * (gcsgb + sxpart * ggtg + T1 * dsxpart_dVg) + mult_i * (gbspg - Gm - gstotg - gIstotg)); + (*(here->BSIM4SPspPtr) += mult_i * (gspr + here->BSIM4gds + here->BSIM4gbs - gIstots - gstots + FwdSum + gbspsp) + mult_q * (sxpart * ggts + T1 * dsxpart_dVs + gcssb)); + (*(here->BSIM4SPsPtr) -= mult_i * (gspr + gstot)); + (*(here->BSIM4SPbpPtr) -= mult_i * (gjbs + gstotb + Gmbs - gbspb + gIstotb) - mult_q * (gcsbb + sxpart * ggtb + T1 * dsxpart_dVb)); - (*(here->BSIM4SspPtr) -= m * (gspr - gstots)); - (*(here->BSIM4SsPtr) += m * (gspr + gstot)); + (*(here->BSIM4SspPtr) -= mult_i * (gspr - gstots)); + (*(here->BSIM4SsPtr) += mult_i * (gspr + gstot)); - (*(here->BSIM4BPdpPtr) += m * (gcbdb - gjbd + gbbdp - gIbtotd)); - (*(here->BSIM4BPgpPtr) += m * (gcbgb - here->BSIM4gbgs - gIbtotg)); - (*(here->BSIM4BPspPtr) += m * (gcbsb - gjbs + gbbsp - gIbtots)); - (*(here->BSIM4BPbpPtr) += m * (gjbd + gjbs + gcbbb - here->BSIM4gbbs - - gIbtotb)); + (*(here->BSIM4BPdpPtr) += mult_q * gcbdb - mult_i * (gjbd - gbbdp + gIbtotd)); + (*(here->BSIM4BPgpPtr) += mult_q * gcbgb - mult_i * (here->BSIM4gbgs + gIbtotg)); + (*(here->BSIM4BPspPtr) += mult_q * gcbsb - mult_i * (gjbs - gbbsp + gIbtots)); + (*(here->BSIM4BPbpPtr) += mult_i * (gjbd + gjbs - here->BSIM4gbbs + - gIbtotb) + mult_q * gcbbb); ggidld = here->BSIM4ggidld; ggidlg = here->BSIM4ggidlg; @@ -5315,52 +5317,50 @@ line900: ggislb = here->BSIM4ggislb; /* stamp gidl */ - (*(here->BSIM4DPdpPtr) += m * ggidld); - (*(here->BSIM4DPgpPtr) += m * ggidlg); - (*(here->BSIM4DPspPtr) -= m * (ggidlg + ggidld + ggidlb)); - (*(here->BSIM4DPbpPtr) += m * ggidlb); - (*(here->BSIM4BPdpPtr) -= m * ggidld); - (*(here->BSIM4BPgpPtr) -= m * ggidlg); - (*(here->BSIM4BPspPtr) += m * (ggidlg + ggidld + ggidlb)); - (*(here->BSIM4BPbpPtr) -= m * ggidlb); + (*(here->BSIM4DPdpPtr) += mult_i * ggidld); + (*(here->BSIM4DPgpPtr) += mult_i * ggidlg); + (*(here->BSIM4DPspPtr) -= mult_i * (ggidlg + ggidld + ggidlb)); + (*(here->BSIM4DPbpPtr) += mult_i * ggidlb); + (*(here->BSIM4BPdpPtr) -= mult_i * ggidld); + (*(here->BSIM4BPgpPtr) -= mult_i * ggidlg); + (*(here->BSIM4BPspPtr) += mult_i * (ggidlg + ggidld + ggidlb)); + (*(here->BSIM4BPbpPtr) -= mult_i * ggidlb); /* stamp gisl */ - (*(here->BSIM4SPdpPtr) -= m * (ggisls + ggislg + ggislb)); - (*(here->BSIM4SPgpPtr) += m * ggislg); - (*(here->BSIM4SPspPtr) += m * ggisls); - (*(here->BSIM4SPbpPtr) += m * ggislb); - (*(here->BSIM4BPdpPtr) += m * (ggislg + ggisls + ggislb)); - (*(here->BSIM4BPgpPtr) -= m * ggislg); - (*(here->BSIM4BPspPtr) -= m * ggisls); - (*(here->BSIM4BPbpPtr) -= m * ggislb); + (*(here->BSIM4SPdpPtr) -= mult_i * (ggisls + ggislg + ggislb)); + (*(here->BSIM4SPgpPtr) += mult_i * ggislg); + (*(here->BSIM4SPspPtr) += mult_i * ggisls); + (*(here->BSIM4SPbpPtr) += mult_i * ggislb); + (*(here->BSIM4BPdpPtr) += mult_i * (ggislg + ggisls + ggislb)); + (*(here->BSIM4BPgpPtr) -= mult_i * ggislg); + (*(here->BSIM4BPspPtr) -= mult_i * ggisls); + (*(here->BSIM4BPbpPtr) -= mult_i * ggislb); if (here->BSIM4rbodyMod) - { (*(here->BSIM4DPdbPtr) += m * (gcdbdb - here->BSIM4gbd)); - (*(here->BSIM4SPsbPtr) -= m * (here->BSIM4gbs - gcsbsb)); + { (*(here->BSIM4DPdbPtr) += mult_q * gcdbdb - mult_i * here->BSIM4gbd); + (*(here->BSIM4SPsbPtr) -= mult_i * here->BSIM4gbs - mult_q * gcsbsb); - (*(here->BSIM4DBdpPtr) += m * (gcdbdb - here->BSIM4gbd)); - (*(here->BSIM4DBdbPtr) += m * (here->BSIM4gbd - gcdbdb - + here->BSIM4grbpd + here->BSIM4grbdb)); - (*(here->BSIM4DBbpPtr) -= m * here->BSIM4grbpd); - (*(here->BSIM4DBbPtr) -= m * here->BSIM4grbdb); + (*(here->BSIM4DBdpPtr) += mult_q * gcdbdb - mult_i * here->BSIM4gbd); + (*(here->BSIM4DBdbPtr) += mult_i * (here->BSIM4gbd + here->BSIM4grbpd + here->BSIM4grbdb) - mult_q * gcdbdb); + (*(here->BSIM4DBbpPtr) -= mult_i * here->BSIM4grbpd); + (*(here->BSIM4DBbPtr) -= mult_i * here->BSIM4grbdb); - (*(here->BSIM4BPdbPtr) -= m * here->BSIM4grbpd); - (*(here->BSIM4BPbPtr) -= m * here->BSIM4grbpb); - (*(here->BSIM4BPsbPtr) -= m * here->BSIM4grbps); - (*(here->BSIM4BPbpPtr) += m * (here->BSIM4grbpd + here->BSIM4grbps + (*(here->BSIM4BPdbPtr) -= mult_i * here->BSIM4grbpd); + (*(here->BSIM4BPbPtr) -= mult_i * here->BSIM4grbpb); + (*(here->BSIM4BPsbPtr) -= mult_i * here->BSIM4grbps); + (*(here->BSIM4BPbpPtr) += mult_i * (here->BSIM4grbpd + here->BSIM4grbps + here->BSIM4grbpb)); - /* WDLiu: (gcbbb - here->BSIM4gbbs) already added to BPbpPtr */ + /* WDLiu: (gcbbb - here->BSIM4gbbs) already added to BPbpPtr */ - (*(here->BSIM4SBspPtr) += m * (gcsbsb - here->BSIM4gbs)); - (*(here->BSIM4SBbpPtr) -= m * here->BSIM4grbps); - (*(here->BSIM4SBbPtr) -= m * here->BSIM4grbsb); - (*(here->BSIM4SBsbPtr) += m * (here->BSIM4gbs - gcsbsb - + here->BSIM4grbps + here->BSIM4grbsb)); + (*(here->BSIM4SBspPtr) += mult_q * gcsbsb - mult_i * here->BSIM4gbs); + (*(here->BSIM4SBbpPtr) -= mult_i * here->BSIM4grbps); + (*(here->BSIM4SBbPtr) -= mult_i * here->BSIM4grbsb); + (*(here->BSIM4SBsbPtr) += mult_i * (here->BSIM4gbs + here->BSIM4grbps + here->BSIM4grbsb) - mult_q * gcsbsb); - (*(here->BSIM4BdbPtr) -= m * here->BSIM4grbdb); - (*(here->BSIM4BbpPtr) -= m * here->BSIM4grbpb); - (*(here->BSIM4BsbPtr) -= m * here->BSIM4grbsb); - (*(here->BSIM4BbPtr) += m * (here->BSIM4grbsb + here->BSIM4grbdb + (*(here->BSIM4BdbPtr) -= mult_i * here->BSIM4grbdb); + (*(here->BSIM4BbpPtr) -= mult_i * here->BSIM4grbpb); + (*(here->BSIM4BsbPtr) -= mult_i * here->BSIM4grbsb); + (*(here->BSIM4BbPtr) += mult_i * (here->BSIM4grbsb + here->BSIM4grbdb + here->BSIM4grbpb)); } @@ -5371,9 +5371,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) += m * (dxpart * here->BSIM4gtau)); + (*(here->BSIM4SPqPtr) += m * (sxpart * here->BSIM4gtau)); + (*(here->BSIM4GPqPtr) -= m * (here->BSIM4gtau)); } #endif @@ -5400,7 +5400,7 @@ int BSIM4polyDepletion( double T1, T2, T3, T4, T5, T6, T7, T8; /* Poly Gate Si Depletion Effect */ - if ((ngate > 1.0e18) && + if ((ngate > 1.0e18) && (ngate < 1.0e25) && (Vgs > phi) && (epsgate!=0) ){ T1 = 1.0e6 * CHARGE * epsgate * ngate / (coxe * coxe); @@ -5412,7 +5412,7 @@ int BSIM4polyDepletion( T6 = sqrt(T7 * T7 + 0.224); T5 = 1.12 - 0.5 * (T7 + T6); *Vgs_eff = Vgs - T5; - *dVgs_eff_dVg = 1.0 - (0.5 - 0.5 / T4) * (1.0 + T7 / T6); + *dVgs_eff_dVg = 1.0 - (0.5 - 0.5 / T4) * (1.0 + T7 / T6); } else { *Vgs_eff = Vgs; @@ -5456,7 +5456,7 @@ void BSIM4LoadRhsMat(GENmodel *inModel, CKTcircuit *ckt) } if (model->BSIM4rdsMod) - { (*(ckt->CKTrhs + here->BSIM4dNode) -= here->BSIM4rhsd); + { (*(ckt->CKTrhs + here->BSIM4dNode) -= here->BSIM4rhsd); (*(ckt->CKTrhs + here->BSIM4sNode) += here->BSIM4rhss); } @@ -5474,12 +5474,12 @@ void BSIM4LoadRhsMat(GENmodel *inModel, CKTcircuit *ckt) (*(here->BSIM4GPspPtr) += here->BSIM4_6); (*(here->BSIM4GPbpPtr) += here->BSIM4_7); } - else if (here->BSIM4rgateMod == 2) + else if (here->BSIM4rgateMod == 2) { (*(here->BSIM4GEgePtr) += here->BSIM4_8); (*(here->BSIM4GEgpPtr) += here->BSIM4_9); (*(here->BSIM4GEdpPtr) += here->BSIM4_10); (*(here->BSIM4GEspPtr) += here->BSIM4_11); - (*(here->BSIM4GEbpPtr) += here->BSIM4_12); + (*(here->BSIM4GEbpPtr) += here->BSIM4_12); (*(here->BSIM4GPgePtr) -= here->BSIM4_13); (*(here->BSIM4GPgpPtr) += here->BSIM4_14); diff --git a/src/spicelib/devices/bsim4/b4mask.c b/src/spicelib/devices/bsim4/b4mask.c index ff8a8f7ee..9b1c6a412 100644 --- a/src/spicelib/devices/bsim4/b4mask.c +++ b/src/spicelib/devices/bsim4/b4mask.c @@ -1,29 +1,25 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* Licensed under Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the license at http://opensource.org/licenses/ECL-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc */ #include "ngspice/ngspice.h" @@ -45,21 +41,21 @@ IFvalue *value) NG_IGNORE(ckt); - switch(which) + switch(which) { case BSIM4_MOD_MOBMOD : - value->iValue = model->BSIM4mobMod; + value->iValue = model->BSIM4mobMod; return(OK); case BSIM4_MOD_PARAMCHK : - value->iValue = model->BSIM4paramChk; + value->iValue = model->BSIM4paramChk; return(OK); case BSIM4_MOD_BINUNIT : - value->iValue = model->BSIM4binUnit; + value->iValue = model->BSIM4binUnit; return(OK); case BSIM4_MOD_CVCHARGEMOD : - value->iValue = model->BSIM4cvchargeMod; + value->iValue = model->BSIM4cvchargeMod; return(OK); case BSIM4_MOD_CAPMOD : - value->iValue = model->BSIM4capMod; + value->iValue = model->BSIM4capMod; return(OK); case BSIM4_MOD_DIOMOD : value->iValue = model->BSIM4dioMod; @@ -71,7 +67,7 @@ IFvalue *value) value->iValue = model->BSIM4acnqsMod; return(OK); case BSIM4_MOD_FNOIMOD : - value->iValue = model->BSIM4fnoiMod; + value->iValue = model->BSIM4fnoiMod; return(OK); case BSIM4_MOD_TNOIMOD : value->iValue = model->BSIM4tnoiMod; @@ -91,18 +87,15 @@ IFvalue *value) case BSIM4_MOD_GEOMOD : value->iValue = model->BSIM4geoMod; return(OK); - case BSIM4_MOD_RGEOMOD : - value->iValue = model->BSIM4rgeoMod; - return(OK); case BSIM4_MOD_MTRLMOD : value->iValue = model->BSIM4mtrlMod; return(OK); - case BSIM4_MOD_GIDLMOD : /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_GIDLMOD : /* v4.7 New GIDL/GISL*/ value->iValue = model->BSIM4gidlMod; return(OK); case BSIM4_MOD_MTRLCOMPATMOD : - value->iValue = model->BSIM4mtrlCompatMod; - return(OK); + value->iValue = model->BSIM4mtrlCompatMod; + return(OK); case BSIM4_MOD_IGCMOD : value->iValue = model->BSIM4igcMod; return(OK); @@ -114,7 +107,7 @@ IFvalue *value) return(OK); case BSIM4_MOD_VERSION : - value->sValue = model->BSIM4version; + value->sValue = model->BSIM4version; return(OK); case BSIM4_MOD_TOXREF : value->rValue = model->BSIM4toxref; @@ -125,13 +118,13 @@ IFvalue *value) case BSIM4_MOD_VDDEOT : value->rValue = model->BSIM4vddeot; return(OK); - case BSIM4_MOD_TEMPEOT : + case BSIM4_MOD_TEMPEOT : value->rValue = model->BSIM4tempeot; return(OK); - case BSIM4_MOD_LEFFEOT : + case BSIM4_MOD_LEFFEOT : value->rValue = model->BSIM4leffeot; return(OK); - case BSIM4_MOD_WEFFEOT : + case BSIM4_MOD_WEFFEOT : value->rValue = model->BSIM4weffeot; return(OK); case BSIM4_MOD_ADOS : @@ -209,16 +202,19 @@ IFvalue *value) return(OK); case BSIM4_MOD_KETA: value->rValue = model->BSIM4keta; - return(OK); + return(OK); + case BSIM4_MOD_KETAC: + value->rValue = model->BSIM4ketac; + return(OK); case BSIM4_MOD_NSUB: value->rValue = model->BSIM4nsub; return(OK); case BSIM4_MOD_PHIG: - value->rValue = model->BSIM4phig; - return(OK); + value->rValue = model->BSIM4phig; + return(OK); case BSIM4_MOD_EPSRGATE: - value->rValue = model->BSIM4epsrgate; - return(OK); + value->rValue = model->BSIM4epsrgate; + return(OK); case BSIM4_MOD_EASUB: value->rValue = model->BSIM4easub; return(OK); @@ -309,68 +305,68 @@ IFvalue *value) case BSIM4_MOD_DVTP5: value->rValue = model->BSIM4dvtp5; return(OK); - case BSIM4_MOD_DVT0 : + case BSIM4_MOD_DVT0 : value->rValue = model->BSIM4dvt0; return(OK); - case BSIM4_MOD_DVT1 : + case BSIM4_MOD_DVT1 : value->rValue = model->BSIM4dvt1; return(OK); - case BSIM4_MOD_DVT2 : + case BSIM4_MOD_DVT2 : value->rValue = model->BSIM4dvt2; return(OK); - case BSIM4_MOD_DVT0W : + case BSIM4_MOD_DVT0W : value->rValue = model->BSIM4dvt0w; return(OK); - case BSIM4_MOD_DVT1W : + case BSIM4_MOD_DVT1W : value->rValue = model->BSIM4dvt1w; return(OK); - case BSIM4_MOD_DVT2W : + case BSIM4_MOD_DVT2W : value->rValue = model->BSIM4dvt2w; return(OK); - case BSIM4_MOD_DROUT : + case BSIM4_MOD_DROUT : value->rValue = model->BSIM4drout; return(OK); - case BSIM4_MOD_DSUB : + case BSIM4_MOD_DSUB : value->rValue = model->BSIM4dsub; return(OK); case BSIM4_MOD_VTH0: - value->rValue = model->BSIM4vth0; + value->rValue = model->BSIM4vth0; return(OK); case BSIM4_MOD_EU: value->rValue = model->BSIM4eu; return(OK); - case BSIM4_MOD_UCS: + case BSIM4_MOD_UCS: value->rValue = model->BSIM4ucs; return(OK); case BSIM4_MOD_UA: - value->rValue = model->BSIM4ua; + value->rValue = model->BSIM4ua; return(OK); case BSIM4_MOD_UA1: - value->rValue = model->BSIM4ua1; + value->rValue = model->BSIM4ua1; return(OK); case BSIM4_MOD_UB: - value->rValue = model->BSIM4ub; + value->rValue = model->BSIM4ub; return(OK); case BSIM4_MOD_UB1: - value->rValue = model->BSIM4ub1; + value->rValue = model->BSIM4ub1; return(OK); case BSIM4_MOD_UC: - value->rValue = model->BSIM4uc; + value->rValue = model->BSIM4uc; return(OK); case BSIM4_MOD_UC1: - value->rValue = model->BSIM4uc1; + value->rValue = model->BSIM4uc1; return(OK); case BSIM4_MOD_UD: - value->rValue = model->BSIM4ud; + value->rValue = model->BSIM4ud; return(OK); case BSIM4_MOD_UD1: - value->rValue = model->BSIM4ud1; + value->rValue = model->BSIM4ud1; return(OK); case BSIM4_MOD_UP: - value->rValue = model->BSIM4up; + value->rValue = model->BSIM4up; return(OK); case BSIM4_MOD_LP: - value->rValue = model->BSIM4lp; + value->rValue = model->BSIM4lp; return(OK); case BSIM4_MOD_U0: value->rValue = model->BSIM4u0; @@ -378,7 +374,7 @@ IFvalue *value) case BSIM4_MOD_UTE: value->rValue = model->BSIM4ute; return(OK); - case BSIM4_MOD_UCSTE: + case BSIM4_MOD_UCSTE: value->rValue = model->BSIM4ucste; return(OK); case BSIM4_MOD_VOFF: @@ -387,13 +383,13 @@ IFvalue *value) case BSIM4_MOD_TVOFF: value->rValue = model->BSIM4tvoff; return(OK); - case BSIM4_MOD_TNFACTOR: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_TNFACTOR: /* v4.7 temp dep of leakage current */ value->rValue = model->BSIM4tnfactor; return(OK); - case BSIM4_MOD_TETA0: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_TETA0: /* v4.7 temp dep of leakage current */ value->rValue = model->BSIM4teta0; return(OK); - case BSIM4_MOD_TVOFFCV: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_TVOFFCV: /* v4.7 temp dep of leakage current */ value->rValue = model->BSIM4tvoffcv; return(OK); case BSIM4_MOD_VFBSDOFF: @@ -430,7 +426,7 @@ IFvalue *value) value->rValue = model->BSIM4delta; return(OK); case BSIM4_MOD_RDSW: - value->rValue = model->BSIM4rdsw; + value->rValue = model->BSIM4rdsw; return(OK); case BSIM4_MOD_RDSWMIN: value->rValue = model->BSIM4rdswmin; @@ -448,41 +444,41 @@ IFvalue *value) value->rValue = model->BSIM4rsw; return(OK); case BSIM4_MOD_PRWG: - value->rValue = model->BSIM4prwg; - return(OK); + value->rValue = model->BSIM4prwg; + return(OK); case BSIM4_MOD_PRWB: - value->rValue = model->BSIM4prwb; - return(OK); + value->rValue = model->BSIM4prwb; + return(OK); case BSIM4_MOD_PRT: - value->rValue = model->BSIM4prt; - return(OK); + value->rValue = model->BSIM4prt; + return(OK); case BSIM4_MOD_ETA0: - value->rValue = model->BSIM4eta0; - return(OK); + value->rValue = model->BSIM4eta0; + return(OK); case BSIM4_MOD_ETAB: - value->rValue = model->BSIM4etab; - return(OK); + value->rValue = model->BSIM4etab; + return(OK); case BSIM4_MOD_PCLM: - value->rValue = model->BSIM4pclm; - return(OK); + value->rValue = model->BSIM4pclm; + return(OK); case BSIM4_MOD_PDIBL1: - value->rValue = model->BSIM4pdibl1; - return(OK); + value->rValue = model->BSIM4pdibl1; + return(OK); case BSIM4_MOD_PDIBL2: - value->rValue = model->BSIM4pdibl2; - return(OK); + value->rValue = model->BSIM4pdibl2; + return(OK); case BSIM4_MOD_PDIBLB: - value->rValue = model->BSIM4pdiblb; - return(OK); + value->rValue = model->BSIM4pdiblb; + return(OK); case BSIM4_MOD_PSCBE1: - value->rValue = model->BSIM4pscbe1; - return(OK); + value->rValue = model->BSIM4pscbe1; + return(OK); case BSIM4_MOD_PSCBE2: - value->rValue = model->BSIM4pscbe2; - return(OK); + value->rValue = model->BSIM4pscbe2; + return(OK); case BSIM4_MOD_PVAG: - value->rValue = model->BSIM4pvag; - return(OK); + value->rValue = model->BSIM4pvag; + return(OK); case BSIM4_MOD_WR: value->rValue = model->BSIM4wr; return(OK); @@ -519,13 +515,13 @@ IFvalue *value) case BSIM4_MOD_EGIDL: value->rValue = model->BSIM4egidl; return(OK); - case BSIM4_MOD_FGIDL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_FGIDL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4fgidl; return(OK); - case BSIM4_MOD_KGIDL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_KGIDL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4kgidl; return(OK); - case BSIM4_MOD_RGIDL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_RGIDL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4rgidl; return(OK); case BSIM4_MOD_AGISL: @@ -540,13 +536,13 @@ IFvalue *value) case BSIM4_MOD_EGISL: value->rValue = model->BSIM4egisl; return(OK); - case BSIM4_MOD_FGISL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_FGISL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4fgisl; return(OK); - case BSIM4_MOD_KGISL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_KGISL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4kgisl; return(OK); - case BSIM4_MOD_RGISL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_RGISL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4rgisl; return(OK); case BSIM4_MOD_AIGC: @@ -653,7 +649,7 @@ IFvalue *value) return(OK); case BSIM4_MOD_GIDLCLAMP: value->rValue = model->BSIM4gidlclamp; - return(OK); + return(OK); case BSIM4_MOD_IDOVVDSC: value->rValue = model->BSIM4idovvdsc; return(OK); @@ -706,9 +702,9 @@ IFvalue *value) case BSIM4_MOD_JTSSWGD: value->rValue = model->BSIM4jtsswgd; return(OK); - case BSIM4_MOD_JTWEFF: - value->rValue = model->BSIM4jtweff; - return(OK); + case BSIM4_MOD_JTWEFF: + value->rValue = model->BSIM4jtweff; + return(OK); case BSIM4_MOD_NJTS: value->rValue = model->BSIM4njts; return(OK); @@ -925,7 +921,7 @@ IFvalue *value) value->rValue = model->BSIM4dwj; return(OK); case BSIM4_MOD_VFBCV: - value->rValue = model->BSIM4vfbcv; + value->rValue = model->BSIM4vfbcv; return(OK); case BSIM4_MOD_ACDE: value->rValue = model->BSIM4acde; @@ -957,12 +953,12 @@ IFvalue *value) case BSIM4_MOD_XGL: value->rValue = model->BSIM4xgl; return(OK); + case BSIM4_MOD_NGCON: + value->rValue = model->BSIM4ngcon; + return(OK); case BSIM4_MOD_RSHG: value->rValue = model->BSIM4rshg; return(OK); - case BSIM4_MOD_NGCON: - value->rValue = model->BSIM4ngcon; - return(OK); case BSIM4_MOD_TCJ: value->rValue = model->BSIM4tcj; return(OK); @@ -982,7 +978,7 @@ IFvalue *value) value->rValue = model->BSIM4tpbswg; return(OK); - /* Length dependence */ + /* Length dependence */ case BSIM4_MOD_LCDSC : value->rValue = model->BSIM4lcdsc; return(OK); @@ -1021,7 +1017,10 @@ IFvalue *value) return(OK); case BSIM4_MOD_LKETA: value->rValue = model->BSIM4lketa; - return(OK); + return(OK); + case BSIM4_MOD_LKETAC: + value->rValue = model->BSIM4lketac; + return(OK); case BSIM4_MOD_LNSUB: value->rValue = model->BSIM4lnsub; return(OK); @@ -1085,7 +1084,7 @@ IFvalue *value) case BSIM4_MOD_LDVTP1: value->rValue = model->BSIM4ldvtp1; return(OK); - case BSIM4_MOD_LDVTP2: + case BSIM4_MOD_LDVTP2: value->rValue = model->BSIM4ldvtp2; /* New DIBL/Rout */ return(OK); case BSIM4_MOD_LDVTP3: @@ -1097,62 +1096,62 @@ IFvalue *value) case BSIM4_MOD_LDVTP5: value->rValue = model->BSIM4ldvtp5; return(OK); - case BSIM4_MOD_LDVT0: + case BSIM4_MOD_LDVT0: value->rValue = model->BSIM4ldvt0; return(OK); - case BSIM4_MOD_LDVT1 : + case BSIM4_MOD_LDVT1 : value->rValue = model->BSIM4ldvt1; return(OK); - case BSIM4_MOD_LDVT2 : + case BSIM4_MOD_LDVT2 : value->rValue = model->BSIM4ldvt2; return(OK); - case BSIM4_MOD_LDVT0W : + case BSIM4_MOD_LDVT0W : value->rValue = model->BSIM4ldvt0w; return(OK); - case BSIM4_MOD_LDVT1W : + case BSIM4_MOD_LDVT1W : value->rValue = model->BSIM4ldvt1w; return(OK); - case BSIM4_MOD_LDVT2W : + case BSIM4_MOD_LDVT2W : value->rValue = model->BSIM4ldvt2w; return(OK); - case BSIM4_MOD_LDROUT : + case BSIM4_MOD_LDROUT : value->rValue = model->BSIM4ldrout; return(OK); - case BSIM4_MOD_LDSUB : + case BSIM4_MOD_LDSUB : value->rValue = model->BSIM4ldsub; return(OK); case BSIM4_MOD_LVTH0: - value->rValue = model->BSIM4lvth0; + value->rValue = model->BSIM4lvth0; return(OK); case BSIM4_MOD_LUA: - value->rValue = model->BSIM4lua; + value->rValue = model->BSIM4lua; return(OK); case BSIM4_MOD_LUA1: - value->rValue = model->BSIM4lua1; + value->rValue = model->BSIM4lua1; return(OK); case BSIM4_MOD_LUB: - value->rValue = model->BSIM4lub; + value->rValue = model->BSIM4lub; return(OK); case BSIM4_MOD_LUB1: - value->rValue = model->BSIM4lub1; + value->rValue = model->BSIM4lub1; return(OK); case BSIM4_MOD_LUC: - value->rValue = model->BSIM4luc; + value->rValue = model->BSIM4luc; return(OK); case BSIM4_MOD_LUC1: - value->rValue = model->BSIM4luc1; + value->rValue = model->BSIM4luc1; return(OK); case BSIM4_MOD_LUD: - value->rValue = model->BSIM4lud; + value->rValue = model->BSIM4lud; return(OK); case BSIM4_MOD_LUD1: - value->rValue = model->BSIM4lud1; + value->rValue = model->BSIM4lud1; return(OK); case BSIM4_MOD_LUP: - value->rValue = model->BSIM4lup; + value->rValue = model->BSIM4lup; return(OK); case BSIM4_MOD_LLP: - value->rValue = model->BSIM4llp; + value->rValue = model->BSIM4llp; return(OK); case BSIM4_MOD_LU0: value->rValue = model->BSIM4lu0; @@ -1160,7 +1159,7 @@ IFvalue *value) case BSIM4_MOD_LUTE: value->rValue = model->BSIM4lute; return(OK); - case BSIM4_MOD_LUCSTE: + case BSIM4_MOD_LUCSTE: value->rValue = model->BSIM4lucste; return(OK); case BSIM4_MOD_LVOFF: @@ -1169,15 +1168,18 @@ IFvalue *value) case BSIM4_MOD_LTVOFF: value->rValue = model->BSIM4ltvoff; return(OK); - case BSIM4_MOD_LTNFACTOR: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_LTNFACTOR: /* v4.7 temp dep of leakage current */ value->rValue = model->BSIM4ltnfactor; return(OK); - case BSIM4_MOD_LTETA0: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_LTETA0: /* v4.7 temp dep of leakage current */ value->rValue = model->BSIM4lteta0; return(OK); - case BSIM4_MOD_LTVOFFCV: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_LTVOFFCV: /* v4.7 temp dep of leakage current */ value->rValue = model->BSIM4ltvoffcv; return(OK); + case BSIM4_MOD_LINTNOI: + value->rValue = model->BSIM4lintnoi; + return(OK); case BSIM4_MOD_LMINV: value->rValue = model->BSIM4lminv; return(OK); @@ -1197,8 +1199,8 @@ IFvalue *value) value->rValue = model->BSIM4ldelta; return(OK); case BSIM4_MOD_LRDSW: - value->rValue = model->BSIM4lrdsw; - return(OK); + value->rValue = model->BSIM4lrdsw; + return(OK); case BSIM4_MOD_LRDW: value->rValue = model->BSIM4lrdw; return(OK); @@ -1206,41 +1208,41 @@ IFvalue *value) value->rValue = model->BSIM4lrsw; return(OK); case BSIM4_MOD_LPRWB: - value->rValue = model->BSIM4lprwb; - return(OK); + value->rValue = model->BSIM4lprwb; + return(OK); case BSIM4_MOD_LPRWG: - value->rValue = model->BSIM4lprwg; - return(OK); + value->rValue = model->BSIM4lprwg; + return(OK); case BSIM4_MOD_LPRT: - value->rValue = model->BSIM4lprt; - return(OK); + value->rValue = model->BSIM4lprt; + return(OK); case BSIM4_MOD_LETA0: - value->rValue = model->BSIM4leta0; - return(OK); + value->rValue = model->BSIM4leta0; + return(OK); case BSIM4_MOD_LETAB: - value->rValue = model->BSIM4letab; - return(OK); + value->rValue = model->BSIM4letab; + return(OK); case BSIM4_MOD_LPCLM: - value->rValue = model->BSIM4lpclm; - return(OK); + value->rValue = model->BSIM4lpclm; + return(OK); case BSIM4_MOD_LPDIBL1: - value->rValue = model->BSIM4lpdibl1; - return(OK); + value->rValue = model->BSIM4lpdibl1; + return(OK); case BSIM4_MOD_LPDIBL2: - value->rValue = model->BSIM4lpdibl2; - return(OK); + value->rValue = model->BSIM4lpdibl2; + return(OK); case BSIM4_MOD_LPDIBLB: - value->rValue = model->BSIM4lpdiblb; - return(OK); + value->rValue = model->BSIM4lpdiblb; + return(OK); case BSIM4_MOD_LPSCBE1: - value->rValue = model->BSIM4lpscbe1; - return(OK); + value->rValue = model->BSIM4lpscbe1; + return(OK); case BSIM4_MOD_LPSCBE2: - value->rValue = model->BSIM4lpscbe2; - return(OK); + value->rValue = model->BSIM4lpscbe2; + return(OK); case BSIM4_MOD_LPVAG: - value->rValue = model->BSIM4lpvag; - return(OK); + value->rValue = model->BSIM4lpvag; + return(OK); case BSIM4_MOD_LWR: value->rValue = model->BSIM4lwr; return(OK); @@ -1274,16 +1276,16 @@ IFvalue *value) case BSIM4_MOD_LCGIDL: value->rValue = model->BSIM4lcgidl; return(OK); - case BSIM4_MOD_LEGIDL: + case BSIM4_MOD_LEGIDL: value->rValue = model->BSIM4legidl; return(OK); - case BSIM4_MOD_LFGIDL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_LFGIDL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4lfgidl; return(OK); - case BSIM4_MOD_LKGIDL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_LKGIDL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4lkgidl; return(OK); - case BSIM4_MOD_LRGIDL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_LRGIDL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4lrgidl; return(OK); case BSIM4_MOD_LAGISL: @@ -1298,13 +1300,13 @@ IFvalue *value) case BSIM4_MOD_LEGISL: value->rValue = model->BSIM4legisl; return(OK); - case BSIM4_MOD_LFGISL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_LFGISL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4lfgisl; return(OK); - case BSIM4_MOD_LKGISL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_LKGISL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4lkgisl; return(OK); - case BSIM4_MOD_LRGISL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_LRGISL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4lrgisl; return(OK); case BSIM4_MOD_LAIGC: @@ -1391,10 +1393,19 @@ IFvalue *value) case BSIM4_MOD_LXRCRG2: value->rValue = model->BSIM4lxrcrg2; return(OK); + case BSIM4_MOD_LLAMBDA: + value->rValue = model->BSIM4llambda; + return(OK); + case BSIM4_MOD_LVTL: + value->rValue = model->BSIM4lvtl; + return(OK); + case BSIM4_MOD_LXN: + value->rValue = model->BSIM4lxn; + return(OK); case BSIM4_MOD_LEU: value->rValue = model->BSIM4leu; return(OK); - case BSIM4_MOD_LUCS: + case BSIM4_MOD_LUCS: value->rValue = model->BSIM4lucs; return(OK); case BSIM4_MOD_LVFB: @@ -1444,17 +1455,7 @@ IFvalue *value) value->rValue = model->BSIM4ltvfbsdoff; return(OK); - case BSIM4_MOD_LLAMBDA: - value->rValue = model->BSIM4llambda; - return(OK); - case BSIM4_MOD_LVTL: - value->rValue = model->BSIM4lvtl; - return(OK); - case BSIM4_MOD_LXN: - value->rValue = model->BSIM4lxn; - return(OK); - - /* Width dependence */ + /* Width dependence */ case BSIM4_MOD_WCDSC : value->rValue = model->BSIM4wcdsc; return(OK); @@ -1493,7 +1494,10 @@ IFvalue *value) return(OK); case BSIM4_MOD_WKETA: value->rValue = model->BSIM4wketa; - return(OK); + return(OK); + case BSIM4_MOD_WKETAC: + value->rValue = model->BSIM4wketac; + return(OK); case BSIM4_MOD_WNSUB: value->rValue = model->BSIM4wnsub; return(OK); @@ -1569,62 +1573,62 @@ IFvalue *value) case BSIM4_MOD_WLPEB: value->rValue = model->BSIM4wlpeb; return(OK); - case BSIM4_MOD_WDVT0: + case BSIM4_MOD_WDVT0: value->rValue = model->BSIM4wdvt0; return(OK); - case BSIM4_MOD_WDVT1 : + case BSIM4_MOD_WDVT1 : value->rValue = model->BSIM4wdvt1; return(OK); - case BSIM4_MOD_WDVT2 : + case BSIM4_MOD_WDVT2 : value->rValue = model->BSIM4wdvt2; return(OK); - case BSIM4_MOD_WDVT0W : + case BSIM4_MOD_WDVT0W : value->rValue = model->BSIM4wdvt0w; return(OK); - case BSIM4_MOD_WDVT1W : + case BSIM4_MOD_WDVT1W : value->rValue = model->BSIM4wdvt1w; return(OK); - case BSIM4_MOD_WDVT2W : + case BSIM4_MOD_WDVT2W : value->rValue = model->BSIM4wdvt2w; return(OK); - case BSIM4_MOD_WDROUT : + case BSIM4_MOD_WDROUT : value->rValue = model->BSIM4wdrout; return(OK); - case BSIM4_MOD_WDSUB : + case BSIM4_MOD_WDSUB : value->rValue = model->BSIM4wdsub; return(OK); case BSIM4_MOD_WVTH0: - value->rValue = model->BSIM4wvth0; + value->rValue = model->BSIM4wvth0; return(OK); case BSIM4_MOD_WUA: - value->rValue = model->BSIM4wua; + value->rValue = model->BSIM4wua; return(OK); case BSIM4_MOD_WUA1: - value->rValue = model->BSIM4wua1; + value->rValue = model->BSIM4wua1; return(OK); case BSIM4_MOD_WUB: - value->rValue = model->BSIM4wub; + value->rValue = model->BSIM4wub; return(OK); case BSIM4_MOD_WUB1: - value->rValue = model->BSIM4wub1; + value->rValue = model->BSIM4wub1; return(OK); case BSIM4_MOD_WUC: - value->rValue = model->BSIM4wuc; + value->rValue = model->BSIM4wuc; return(OK); case BSIM4_MOD_WUC1: - value->rValue = model->BSIM4wuc1; + value->rValue = model->BSIM4wuc1; return(OK); case BSIM4_MOD_WUD: - value->rValue = model->BSIM4wud; + value->rValue = model->BSIM4wud; return(OK); case BSIM4_MOD_WUD1: - value->rValue = model->BSIM4wud1; + value->rValue = model->BSIM4wud1; return(OK); case BSIM4_MOD_WUP: - value->rValue = model->BSIM4wup; + value->rValue = model->BSIM4wup; return(OK); case BSIM4_MOD_WLP: - value->rValue = model->BSIM4wlp; + value->rValue = model->BSIM4wlp; return(OK); case BSIM4_MOD_WU0: value->rValue = model->BSIM4wu0; @@ -1641,13 +1645,13 @@ IFvalue *value) case BSIM4_MOD_WTVOFF: value->rValue = model->BSIM4wtvoff; return(OK); - case BSIM4_MOD_WTNFACTOR: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_WTNFACTOR: /* v4.7 temp dep of leakage current */ value->rValue = model->BSIM4wtnfactor; return(OK); - case BSIM4_MOD_WTETA0: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_WTETA0: /* v4.7 temp dep of leakage current */ value->rValue = model->BSIM4wteta0; return(OK); - case BSIM4_MOD_WTVOFFCV: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_WTVOFFCV: /* v4.7 temp dep of leakage current */ value->rValue = model->BSIM4wtvoffcv; return(OK); case BSIM4_MOD_WMINV: @@ -1669,8 +1673,8 @@ IFvalue *value) value->rValue = model->BSIM4wdelta; return(OK); case BSIM4_MOD_WRDSW: - value->rValue = model->BSIM4wrdsw; - return(OK); + value->rValue = model->BSIM4wrdsw; + return(OK); case BSIM4_MOD_WRDW: value->rValue = model->BSIM4wrdw; return(OK); @@ -1678,41 +1682,41 @@ IFvalue *value) value->rValue = model->BSIM4wrsw; return(OK); case BSIM4_MOD_WPRWB: - value->rValue = model->BSIM4wprwb; - return(OK); + value->rValue = model->BSIM4wprwb; + return(OK); case BSIM4_MOD_WPRWG: - value->rValue = model->BSIM4wprwg; - return(OK); + value->rValue = model->BSIM4wprwg; + return(OK); case BSIM4_MOD_WPRT: - value->rValue = model->BSIM4wprt; - return(OK); + value->rValue = model->BSIM4wprt; + return(OK); case BSIM4_MOD_WETA0: - value->rValue = model->BSIM4weta0; - return(OK); + value->rValue = model->BSIM4weta0; + return(OK); case BSIM4_MOD_WETAB: - value->rValue = model->BSIM4wetab; - return(OK); + value->rValue = model->BSIM4wetab; + return(OK); case BSIM4_MOD_WPCLM: - value->rValue = model->BSIM4wpclm; - return(OK); + value->rValue = model->BSIM4wpclm; + return(OK); case BSIM4_MOD_WPDIBL1: - value->rValue = model->BSIM4wpdibl1; - return(OK); + value->rValue = model->BSIM4wpdibl1; + return(OK); case BSIM4_MOD_WPDIBL2: - value->rValue = model->BSIM4wpdibl2; - return(OK); + value->rValue = model->BSIM4wpdibl2; + return(OK); case BSIM4_MOD_WPDIBLB: - value->rValue = model->BSIM4wpdiblb; - return(OK); + value->rValue = model->BSIM4wpdiblb; + return(OK); case BSIM4_MOD_WPSCBE1: - value->rValue = model->BSIM4wpscbe1; - return(OK); + value->rValue = model->BSIM4wpscbe1; + return(OK); case BSIM4_MOD_WPSCBE2: - value->rValue = model->BSIM4wpscbe2; - return(OK); + value->rValue = model->BSIM4wpscbe2; + return(OK); case BSIM4_MOD_WPVAG: - value->rValue = model->BSIM4wpvag; - return(OK); + value->rValue = model->BSIM4wpvag; + return(OK); case BSIM4_MOD_WWR: value->rValue = model->BSIM4wwr; return(OK); @@ -1749,13 +1753,13 @@ IFvalue *value) case BSIM4_MOD_WEGIDL: value->rValue = model->BSIM4wegidl; return(OK); - case BSIM4_MOD_WFGIDL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_WFGIDL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4wfgidl; return(OK); - case BSIM4_MOD_WKGIDL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_WKGIDL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4wkgidl; return(OK); - case BSIM4_MOD_WRGIDL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_WRGIDL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4wrgidl; return(OK); case BSIM4_MOD_WAGISL: @@ -1770,13 +1774,13 @@ IFvalue *value) case BSIM4_MOD_WEGISL: value->rValue = model->BSIM4wegisl; return(OK); - case BSIM4_MOD_WFGISL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_WFGISL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4wfgisl; return(OK); - case BSIM4_MOD_WKGISL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_WKGISL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4wkgisl; return(OK); - case BSIM4_MOD_WRGISL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_WRGISL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4wrgisl; return(OK); case BSIM4_MOD_WAIGC: @@ -1863,10 +1867,19 @@ IFvalue *value) case BSIM4_MOD_WXRCRG2: value->rValue = model->BSIM4wxrcrg2; return(OK); + case BSIM4_MOD_WLAMBDA: + value->rValue = model->BSIM4wlambda; + return(OK); + case BSIM4_MOD_WVTL: + value->rValue = model->BSIM4wvtl; + return(OK); + case BSIM4_MOD_WXN: + value->rValue = model->BSIM4wxn; + return(OK); case BSIM4_MOD_WEU: value->rValue = model->BSIM4weu; return(OK); - case BSIM4_MOD_WUCS: + case BSIM4_MOD_WUCS: value->rValue = model->BSIM4wucs; return(OK); case BSIM4_MOD_WVFB: @@ -1916,17 +1929,7 @@ IFvalue *value) value->rValue = model->BSIM4wtvfbsdoff; return(OK); - case BSIM4_MOD_WLAMBDA: - value->rValue = model->BSIM4wlambda; - return(OK); - case BSIM4_MOD_WVTL: - value->rValue = model->BSIM4wvtl; - return(OK); - case BSIM4_MOD_WXN: - value->rValue = model->BSIM4wxn; - return(OK); - - /* Cross-term dependence */ + /* Cross-term dependence */ case BSIM4_MOD_PCDSC : value->rValue = model->BSIM4pcdsc; return(OK); @@ -1965,7 +1968,10 @@ IFvalue *value) return(OK); case BSIM4_MOD_PKETA: value->rValue = model->BSIM4pketa; - return(OK); + return(OK); + case BSIM4_MOD_PKETAC: + value->rValue = model->BSIM4pketac; + return(OK); case BSIM4_MOD_PNSUB: value->rValue = model->BSIM4pnsub; return(OK); @@ -2041,62 +2047,62 @@ IFvalue *value) case BSIM4_MOD_PDVTP5: value->rValue = model->BSIM4pdvtp5; return(OK); - case BSIM4_MOD_PDVT0 : + case BSIM4_MOD_PDVT0 : value->rValue = model->BSIM4pdvt0; return(OK); - case BSIM4_MOD_PDVT1 : + case BSIM4_MOD_PDVT1 : value->rValue = model->BSIM4pdvt1; return(OK); - case BSIM4_MOD_PDVT2 : + case BSIM4_MOD_PDVT2 : value->rValue = model->BSIM4pdvt2; return(OK); - case BSIM4_MOD_PDVT0W : + case BSIM4_MOD_PDVT0W : value->rValue = model->BSIM4pdvt0w; return(OK); - case BSIM4_MOD_PDVT1W : + case BSIM4_MOD_PDVT1W : value->rValue = model->BSIM4pdvt1w; return(OK); - case BSIM4_MOD_PDVT2W : + case BSIM4_MOD_PDVT2W : value->rValue = model->BSIM4pdvt2w; return(OK); - case BSIM4_MOD_PDROUT : + case BSIM4_MOD_PDROUT : value->rValue = model->BSIM4pdrout; return(OK); - case BSIM4_MOD_PDSUB : + case BSIM4_MOD_PDSUB : value->rValue = model->BSIM4pdsub; return(OK); case BSIM4_MOD_PVTH0: - value->rValue = model->BSIM4pvth0; + value->rValue = model->BSIM4pvth0; return(OK); case BSIM4_MOD_PUA: - value->rValue = model->BSIM4pua; + value->rValue = model->BSIM4pua; return(OK); case BSIM4_MOD_PUA1: - value->rValue = model->BSIM4pua1; + value->rValue = model->BSIM4pua1; return(OK); case BSIM4_MOD_PUB: - value->rValue = model->BSIM4pub; + value->rValue = model->BSIM4pub; return(OK); case BSIM4_MOD_PUB1: - value->rValue = model->BSIM4pub1; + value->rValue = model->BSIM4pub1; return(OK); case BSIM4_MOD_PUC: - value->rValue = model->BSIM4puc; + value->rValue = model->BSIM4puc; return(OK); case BSIM4_MOD_PUC1: - value->rValue = model->BSIM4puc1; + value->rValue = model->BSIM4puc1; return(OK); case BSIM4_MOD_PUD: - value->rValue = model->BSIM4pud; + value->rValue = model->BSIM4pud; return(OK); case BSIM4_MOD_PUD1: - value->rValue = model->BSIM4pud1; + value->rValue = model->BSIM4pud1; return(OK); case BSIM4_MOD_PUP: - value->rValue = model->BSIM4pup; + value->rValue = model->BSIM4pup; return(OK); case BSIM4_MOD_PLP: - value->rValue = model->BSIM4plp; + value->rValue = model->BSIM4plp; return(OK); case BSIM4_MOD_PU0: value->rValue = model->BSIM4pu0; @@ -2113,13 +2119,13 @@ IFvalue *value) case BSIM4_MOD_PTVOFF: value->rValue = model->BSIM4ptvoff; return(OK); - case BSIM4_MOD_PTNFACTOR: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_PTNFACTOR: /* v4.7 temp dep of leakage current */ value->rValue = model->BSIM4ptnfactor; return(OK); - case BSIM4_MOD_PTETA0: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_PTETA0: /* v4.7 temp dep of leakage current */ value->rValue = model->BSIM4pteta0; return(OK); - case BSIM4_MOD_PTVOFFCV: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_PTVOFFCV: /* v4.7 temp dep of leakage current */ value->rValue = model->BSIM4ptvoffcv; return(OK); case BSIM4_MOD_PMINV: @@ -2141,8 +2147,8 @@ IFvalue *value) value->rValue = model->BSIM4pdelta; return(OK); case BSIM4_MOD_PRDSW: - value->rValue = model->BSIM4prdsw; - return(OK); + value->rValue = model->BSIM4prdsw; + return(OK); case BSIM4_MOD_PRDW: value->rValue = model->BSIM4prdw; return(OK); @@ -2150,41 +2156,41 @@ IFvalue *value) value->rValue = model->BSIM4prsw; return(OK); case BSIM4_MOD_PPRWB: - value->rValue = model->BSIM4pprwb; - return(OK); + value->rValue = model->BSIM4pprwb; + return(OK); case BSIM4_MOD_PPRWG: - value->rValue = model->BSIM4pprwg; - return(OK); + value->rValue = model->BSIM4pprwg; + return(OK); case BSIM4_MOD_PPRT: - value->rValue = model->BSIM4pprt; - return(OK); + value->rValue = model->BSIM4pprt; + return(OK); case BSIM4_MOD_PETA0: - value->rValue = model->BSIM4peta0; - return(OK); + value->rValue = model->BSIM4peta0; + return(OK); case BSIM4_MOD_PETAB: - value->rValue = model->BSIM4petab; - return(OK); + value->rValue = model->BSIM4petab; + return(OK); case BSIM4_MOD_PPCLM: - value->rValue = model->BSIM4ppclm; - return(OK); + value->rValue = model->BSIM4ppclm; + return(OK); case BSIM4_MOD_PPDIBL1: - value->rValue = model->BSIM4ppdibl1; - return(OK); + value->rValue = model->BSIM4ppdibl1; + return(OK); case BSIM4_MOD_PPDIBL2: - value->rValue = model->BSIM4ppdibl2; - return(OK); + value->rValue = model->BSIM4ppdibl2; + return(OK); case BSIM4_MOD_PPDIBLB: - value->rValue = model->BSIM4ppdiblb; - return(OK); + value->rValue = model->BSIM4ppdiblb; + return(OK); case BSIM4_MOD_PPSCBE1: - value->rValue = model->BSIM4ppscbe1; - return(OK); + value->rValue = model->BSIM4ppscbe1; + return(OK); case BSIM4_MOD_PPSCBE2: - value->rValue = model->BSIM4ppscbe2; - return(OK); + value->rValue = model->BSIM4ppscbe2; + return(OK); case BSIM4_MOD_PPVAG: - value->rValue = model->BSIM4ppvag; - return(OK); + value->rValue = model->BSIM4ppvag; + return(OK); case BSIM4_MOD_PWR: value->rValue = model->BSIM4pwr; return(OK); @@ -2221,13 +2227,13 @@ IFvalue *value) case BSIM4_MOD_PEGIDL: value->rValue = model->BSIM4pegidl; return(OK); - case BSIM4_MOD_PFGIDL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_PFGIDL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4pfgidl; return(OK); - case BSIM4_MOD_PKGIDL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_PKGIDL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4pkgidl; return(OK); - case BSIM4_MOD_PRGIDL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_PRGIDL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4prgidl; return(OK); case BSIM4_MOD_PAGISL: @@ -2242,13 +2248,13 @@ IFvalue *value) case BSIM4_MOD_PEGISL: value->rValue = model->BSIM4pegisl; return(OK); - case BSIM4_MOD_PFGISL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_PFGISL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4pfgisl; return(OK); - case BSIM4_MOD_PKGISL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_PKGISL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4pkgisl; return(OK); - case BSIM4_MOD_PRGISL: /* v4.7 New GIDL/GISL*/ + case BSIM4_MOD_PRGISL: /* v4.7 New GIDL/GISL*/ value->rValue = model->BSIM4prgisl; return(OK); case BSIM4_MOD_PAIGC: @@ -2335,6 +2341,15 @@ IFvalue *value) case BSIM4_MOD_PXRCRG2: value->rValue = model->BSIM4pxrcrg2; return(OK); + case BSIM4_MOD_PLAMBDA: + value->rValue = model->BSIM4plambda; + return(OK); + case BSIM4_MOD_PVTL: + value->rValue = model->BSIM4pvtl; + return(OK); + case BSIM4_MOD_PXN: + value->rValue = model->BSIM4pxn; + return(OK); case BSIM4_MOD_PEU: value->rValue = model->BSIM4peu; return(OK); @@ -2388,75 +2403,65 @@ IFvalue *value) value->rValue = model->BSIM4ptvfbsdoff; return(OK); - case BSIM4_MOD_PLAMBDA: - value->rValue = model->BSIM4plambda; - return(OK); - case BSIM4_MOD_PVTL: - value->rValue = model->BSIM4pvtl; - return(OK); - case BSIM4_MOD_PXN: - value->rValue = model->BSIM4pxn; - return(OK); - case BSIM4_MOD_TNOM : value->rValue = model->BSIM4tnom; return(OK); case BSIM4_MOD_CGSO: - value->rValue = model->BSIM4cgso; + value->rValue = model->BSIM4cgso; return(OK); case BSIM4_MOD_CGDO: - value->rValue = model->BSIM4cgdo; + value->rValue = model->BSIM4cgdo; return(OK); case BSIM4_MOD_CGBO: - value->rValue = model->BSIM4cgbo; + value->rValue = model->BSIM4cgbo; return(OK); case BSIM4_MOD_XPART: - value->rValue = model->BSIM4xpart; + value->rValue = model->BSIM4xpart; return(OK); case BSIM4_MOD_RSH: - value->rValue = model->BSIM4sheetResistance; + value->rValue = model->BSIM4sheetResistance; return(OK); case BSIM4_MOD_JSS: - value->rValue = model->BSIM4SjctSatCurDensity; + value->rValue = model->BSIM4SjctSatCurDensity; return(OK); case BSIM4_MOD_JSWS: - value->rValue = model->BSIM4SjctSidewallSatCurDensity; + value->rValue = model->BSIM4SjctSidewallSatCurDensity; return(OK); case BSIM4_MOD_JSWGS: value->rValue = model->BSIM4SjctGateSidewallSatCurDensity; return(OK); case BSIM4_MOD_PBS: - value->rValue = model->BSIM4SbulkJctPotential; + value->rValue = model->BSIM4SbulkJctPotential; return(OK); case BSIM4_MOD_MJS: - value->rValue = model->BSIM4SbulkJctBotGradingCoeff; + value->rValue = model->BSIM4SbulkJctBotGradingCoeff; return(OK); case BSIM4_MOD_PBSWS: - value->rValue = model->BSIM4SsidewallJctPotential; + value->rValue = model->BSIM4SsidewallJctPotential; return(OK); case BSIM4_MOD_MJSWS: - value->rValue = model->BSIM4SbulkJctSideGradingCoeff; + value->rValue = model->BSIM4SbulkJctSideGradingCoeff; return(OK); case BSIM4_MOD_CJS: - value->rValue = model->BSIM4SunitAreaJctCap; + value->rValue = model->BSIM4SunitAreaJctCap; return(OK); case BSIM4_MOD_CJSWS: - value->rValue = model->BSIM4SunitLengthSidewallJctCap; + value->rValue = model->BSIM4SunitLengthSidewallJctCap; return(OK); case BSIM4_MOD_PBSWGS: - value->rValue = model->BSIM4SGatesidewallJctPotential; + value->rValue = model->BSIM4SGatesidewallJctPotential; return(OK); case BSIM4_MOD_MJSWGS: - value->rValue = model->BSIM4SbulkJctGateSideGradingCoeff; + value->rValue = model->BSIM4SbulkJctGateSideGradingCoeff; return(OK); case BSIM4_MOD_CJSWGS: - value->rValue = model->BSIM4SunitLengthGateSidewallJctCap; + value->rValue = model->BSIM4SunitLengthGateSidewallJctCap; return(OK); case BSIM4_MOD_NJS: - value->rValue = model->BSIM4SjctEmissionCoeff; + value->rValue = model->BSIM4SjctEmissionCoeff; return(OK); case BSIM4_MOD_XTIS: - value->rValue = model->BSIM4SjctTempExponent; + value->rValue = model->BSIM4SjctTempExponent; return(OK); case BSIM4_MOD_JSD: value->rValue = model->BSIM4DjctSatCurDensity; @@ -2500,11 +2505,8 @@ IFvalue *value) case BSIM4_MOD_XTID: value->rValue = model->BSIM4DjctTempExponent; return(OK); - case BSIM4_MOD_LINTNOI: - value->rValue = model->BSIM4lintnoi; - return(OK); case BSIM4_MOD_LINT: - value->rValue = model->BSIM4Lint; + value->rValue = model->BSIM4Lint; return(OK); case BSIM4_MOD_LL: value->rValue = model->BSIM4Ll; @@ -2577,7 +2579,7 @@ IFvalue *value) case BSIM4_MOD_SBREF: value->rValue = model->BSIM4sbref; return(OK); - case BSIM4_MOD_WLOD: + case BSIM4_MOD_WLOD: value->rValue = model->BSIM4wlod; return(OK); case BSIM4_MOD_KU0: diff --git a/src/spicelib/devices/bsim4/b4mdel.c b/src/spicelib/devices/bsim4/b4mdel.c index 7901a6cad..3e354995e 100644 --- a/src/spicelib/devices/bsim4/b4mdel.c +++ b/src/spicelib/devices/bsim4/b4mdel.c @@ -1,29 +1,25 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* Licensed under Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the license at http://opensource.org/licenses/ECL-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc */ #include "ngspice/ngspice.h" diff --git a/src/spicelib/devices/bsim4/b4mpar.c b/src/spicelib/devices/bsim4/b4mpar.c index b94442531..e9e0eab11 100644 --- a/src/spicelib/devices/bsim4/b4mpar.c +++ b/src/spicelib/devices/bsim4/b4mpar.c @@ -1,29 +1,25 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* Licensed under Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the license at http://opensource.org/licenses/ECL-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc */ #include "ngspice/ngspice.h" @@ -93,10 +89,6 @@ GENmodel *inMod) mod->BSIM4geoMod = value->iValue; mod->BSIM4geoModGiven = TRUE; break; - case BSIM4_MOD_RGEOMOD : - mod->BSIM4rgeoMod = value->iValue; - mod->BSIM4rgeoModGiven = TRUE; - break; case BSIM4_MOD_FNOIMOD : mod->BSIM4fnoiMod = value->iValue; mod->BSIM4fnoiModGiven = TRUE; @@ -113,7 +105,7 @@ GENmodel *inMod) mod->BSIM4mtrlCompatMod = value->iValue; mod->BSIM4mtrlCompatModGiven = TRUE; break; - case BSIM4_MOD_GIDLMOD : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_GIDLMOD : /* v4.7 New GIDL/GISL */ mod->BSIM4gidlMod = value->iValue; mod->BSIM4gidlModGiven = TRUE; break; @@ -134,6 +126,14 @@ GENmodel *inMod) mod->BSIM4version = value->sValue; mod->BSIM4versionGiven = TRUE; break; + case BSIM4_MOD_GIDLCLAMP : /* gidlclamp introduced in b4mpar.c */ + mod->BSIM4gidlclamp = value->rValue; + mod->BSIM4gidlclampGiven = TRUE; + break; + case BSIM4_MOD_IDOVVDSC : /* idovvdsc introduced in b4mpar.c */ + mod->BSIM4idovvdsc = value->rValue; + mod->BSIM4idovvdscGiven = TRUE; + break; case BSIM4_MOD_TOXREF : mod->BSIM4toxref = value->rValue; mod->BSIM4toxrefGiven = TRUE; @@ -154,11 +154,11 @@ GENmodel *inMod) mod->BSIM4leffeot = value->rValue; mod->BSIM4leffeotGiven = TRUE; break; - case BSIM4_MOD_WEFFEOT : + case BSIM4_MOD_WEFFEOT : mod->BSIM4weffeot = value->rValue; mod->BSIM4weffeotGiven = TRUE; break; - case BSIM4_MOD_ADOS : + case BSIM4_MOD_ADOS : mod->BSIM4ados = value->rValue; mod->BSIM4adosGiven = TRUE; break; @@ -166,7 +166,7 @@ GENmodel *inMod) mod->BSIM4bdos = value->rValue; mod->BSIM4bdosGiven = TRUE; break; - case BSIM4_MOD_TOXE : + case BSIM4_MOD_TOXE : mod->BSIM4toxe = value->rValue; mod->BSIM4toxeGiven = TRUE; break; @@ -186,7 +186,6 @@ GENmodel *inMod) mod->BSIM4epsrox = value->rValue; mod->BSIM4epsroxGiven = TRUE; break; - case BSIM4_MOD_CDSC : mod->BSIM4cdsc = value->rValue; mod->BSIM4cdscGiven = TRUE; @@ -195,12 +194,10 @@ GENmodel *inMod) mod->BSIM4cdscb = value->rValue; mod->BSIM4cdscbGiven = TRUE; break; - case BSIM4_MOD_CDSCD : mod->BSIM4cdscd = value->rValue; mod->BSIM4cdscdGiven = TRUE; break; - case BSIM4_MOD_CIT : mod->BSIM4cit = value->rValue; mod->BSIM4citGiven = TRUE; @@ -221,12 +218,12 @@ GENmodel *inMod) mod->BSIM4a0 = value->rValue; mod->BSIM4a0Given = TRUE; break; - + case BSIM4_MOD_AGS: mod->BSIM4ags= value->rValue; mod->BSIM4agsGiven = TRUE; break; - + case BSIM4_MOD_A1: mod->BSIM4a1 = value->rValue; mod->BSIM4a1Given = TRUE; @@ -242,7 +239,11 @@ GENmodel *inMod) case BSIM4_MOD_KETA: mod->BSIM4keta = value->rValue; mod->BSIM4ketaGiven = TRUE; - break; + break; + case BSIM4_MOD_KETAC: + mod->BSIM4ketac = value->rValue; + mod->BSIM4ketacGiven = TRUE; + break; case BSIM4_MOD_NSUB: mod->BSIM4nsub = value->rValue; mod->BSIM4nsubGiven = TRUE; @@ -288,13 +289,13 @@ GENmodel *inMod) case BSIM4_MOD_NSD: mod->BSIM4nsd = value->rValue; mod->BSIM4nsdGiven = TRUE; - if (mod->BSIM4nsd > 1.000001e24) + if (mod->BSIM4nsd > 1.0e23) mod->BSIM4nsd *= 1.0e-6; break; case BSIM4_MOD_NGATE: mod->BSIM4ngate = value->rValue; mod->BSIM4ngateGiven = TRUE; - if (mod->BSIM4ngate > 1.000001e24) + if (mod->BSIM4ngate > 1.0e23) mod->BSIM4ngate *= 1.0e-6; break; case BSIM4_MOD_GAMMA1: @@ -376,40 +377,40 @@ GENmodel *inMod) case BSIM4_MOD_DVTP5: mod->BSIM4dvtp5 = value->rValue; mod->BSIM4dvtp5Given = TRUE; - break; + break; case BSIM4_MOD_W0: mod->BSIM4w0 = value->rValue; mod->BSIM4w0Given = TRUE; break; - case BSIM4_MOD_DVT0: + case BSIM4_MOD_DVT0: mod->BSIM4dvt0 = value->rValue; mod->BSIM4dvt0Given = TRUE; break; - case BSIM4_MOD_DVT1: + case BSIM4_MOD_DVT1: mod->BSIM4dvt1 = value->rValue; mod->BSIM4dvt1Given = TRUE; break; - case BSIM4_MOD_DVT2: + case BSIM4_MOD_DVT2: mod->BSIM4dvt2 = value->rValue; mod->BSIM4dvt2Given = TRUE; break; - case BSIM4_MOD_DVT0W: + case BSIM4_MOD_DVT0W: mod->BSIM4dvt0w = value->rValue; mod->BSIM4dvt0wGiven = TRUE; break; - case BSIM4_MOD_DVT1W: + case BSIM4_MOD_DVT1W: mod->BSIM4dvt1w = value->rValue; mod->BSIM4dvt1wGiven = TRUE; break; - case BSIM4_MOD_DVT2W: + case BSIM4_MOD_DVT2W: mod->BSIM4dvt2w = value->rValue; mod->BSIM4dvt2wGiven = TRUE; break; - case BSIM4_MOD_DROUT: + case BSIM4_MOD_DROUT: mod->BSIM4drout = value->rValue; mod->BSIM4droutGiven = TRUE; break; - case BSIM4_MOD_DSUB: + case BSIM4_MOD_DSUB: mod->BSIM4dsub = value->rValue; mod->BSIM4dsubGiven = TRUE; break; @@ -421,7 +422,7 @@ GENmodel *inMod) mod->BSIM4eu = value->rValue; mod->BSIM4euGiven = TRUE; break; - case BSIM4_MOD_UCS: + case BSIM4_MOD_UCS: mod->BSIM4ucs = value->rValue; mod->BSIM4ucsGiven = TRUE; break; @@ -525,8 +526,6 @@ GENmodel *inMod) mod->BSIM4plp = value->rValue; mod->BSIM4plpGiven = TRUE; break; - - case BSIM4_MOD_VOFF: mod->BSIM4voff = value->rValue; mod->BSIM4voffGiven = TRUE; @@ -535,15 +534,15 @@ GENmodel *inMod) mod->BSIM4tvoff = value->rValue; mod->BSIM4tvoffGiven = TRUE; break; - case BSIM4_MOD_TNFACTOR: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_TNFACTOR: /* v4.7 temp dep of leakage current */ mod->BSIM4tnfactor = value->rValue; mod->BSIM4tnfactorGiven = TRUE; break; - case BSIM4_MOD_TETA0: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_TETA0: /* v4.7 temp dep of leakage current */ mod->BSIM4teta0 = value->rValue; mod->BSIM4teta0Given = TRUE; break; - case BSIM4_MOD_TVOFFCV: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_TVOFFCV: /* v4.7 temp dep of leakage current */ mod->BSIM4tvoffcv = value->rValue; mod->BSIM4tvoffcvGiven = TRUE; break; @@ -586,7 +585,7 @@ GENmodel *inMod) case BSIM4_MOD_RDSW: mod->BSIM4rdsw = value->rValue; mod->BSIM4rdswGiven = TRUE; - break; + break; case BSIM4_MOD_RDSWMIN: mod->BSIM4rdswmin = value->rValue; mod->BSIM4rdswminGiven = TRUE; @@ -610,51 +609,51 @@ GENmodel *inMod) case BSIM4_MOD_PRWG: mod->BSIM4prwg = value->rValue; mod->BSIM4prwgGiven = TRUE; - break; + break; case BSIM4_MOD_PRWB: mod->BSIM4prwb = value->rValue; mod->BSIM4prwbGiven = TRUE; - break; + break; case BSIM4_MOD_PRT: mod->BSIM4prt = value->rValue; mod->BSIM4prtGiven = TRUE; - break; + break; case BSIM4_MOD_ETA0: mod->BSIM4eta0 = value->rValue; mod->BSIM4eta0Given = TRUE; - break; + break; case BSIM4_MOD_ETAB: mod->BSIM4etab = value->rValue; mod->BSIM4etabGiven = TRUE; - break; + break; case BSIM4_MOD_PCLM: mod->BSIM4pclm = value->rValue; mod->BSIM4pclmGiven = TRUE; - break; + break; case BSIM4_MOD_PDIBL1: mod->BSIM4pdibl1 = value->rValue; mod->BSIM4pdibl1Given = TRUE; - break; + break; case BSIM4_MOD_PDIBL2: mod->BSIM4pdibl2 = value->rValue; mod->BSIM4pdibl2Given = TRUE; - break; + break; case BSIM4_MOD_PDIBLB: mod->BSIM4pdiblb = value->rValue; mod->BSIM4pdiblbGiven = TRUE; - break; + break; case BSIM4_MOD_PSCBE1: mod->BSIM4pscbe1 = value->rValue; mod->BSIM4pscbe1Given = TRUE; - break; + break; case BSIM4_MOD_PSCBE2: mod->BSIM4pscbe2 = value->rValue; mod->BSIM4pscbe2Given = TRUE; - break; + break; case BSIM4_MOD_PVAG: mod->BSIM4pvag = value->rValue; mod->BSIM4pvagGiven = TRUE; - break; + break; case BSIM4_MOD_WR : mod->BSIM4wr = value->rValue; mod->BSIM4wrGiven = TRUE; @@ -703,15 +702,15 @@ GENmodel *inMod) mod->BSIM4egidl = value->rValue; mod->BSIM4egidlGiven = TRUE; break; - case BSIM4_MOD_FGIDL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_FGIDL : /* v4.7 New GIDL/GISL */ mod->BSIM4fgidl = value->rValue; mod->BSIM4fgidlGiven = TRUE; break; - case BSIM4_MOD_KGIDL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_KGIDL : /* v4.7 New GIDL/GISL */ mod->BSIM4kgidl = value->rValue; mod->BSIM4kgidlGiven = TRUE; break; - case BSIM4_MOD_RGIDL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_RGIDL : /* v4.7 New GIDL/GISL */ mod->BSIM4rgidl = value->rValue; mod->BSIM4rgidlGiven = TRUE; break; @@ -731,15 +730,15 @@ GENmodel *inMod) mod->BSIM4egisl = value->rValue; mod->BSIM4egislGiven = TRUE; break; - case BSIM4_MOD_FGISL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_FGISL : /* v4.7 New GIDL/GISL */ mod->BSIM4fgisl = value->rValue; mod->BSIM4fgislGiven = TRUE; break; - case BSIM4_MOD_KGISL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_KGISL : /* v4.7 New GIDL/GISL */ mod->BSIM4kgisl = value->rValue; mod->BSIM4kgislGiven = TRUE; break; - case BSIM4_MOD_RGISL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_RGISL : /* v4.7 New GIDL/GISL */ mod->BSIM4rgisl = value->rValue; mod->BSIM4rgislGiven = TRUE; break; @@ -1095,7 +1094,7 @@ GENmodel *inMod) mod->BSIM4bvs = value->rValue; mod->BSIM4bvsGiven = TRUE; break; - + /* reverse diode */ case BSIM4_MOD_JTSS : mod->BSIM4jtss = value->rValue; @@ -1121,10 +1120,11 @@ GENmodel *inMod) mod->BSIM4jtsswgd = value->rValue; mod->BSIM4jtsswgdGiven = TRUE; break; - case BSIM4_MOD_JTWEFF : - mod->BSIM4jtweff = value->rValue; - mod->BSIM4jtweffGiven = TRUE; - break; + + case BSIM4_MOD_JTWEFF : + mod->BSIM4jtweff = value->rValue; + mod->BSIM4jtweffGiven = TRUE; + break; case BSIM4_MOD_NJTS : mod->BSIM4njts = value->rValue; mod->BSIM4njtsGiven = TRUE; @@ -1318,49 +1318,49 @@ GENmodel *inMod) mod->BSIM4rbpbynf = value->rValue; mod->BSIM4rbpbynfGiven = TRUE; break; - case BSIM4_MOD_RBSBX0 : + case BSIM4_MOD_RBSBX0 : mod->BSIM4rbsbx0 = value->rValue; mod->BSIM4rbsbx0Given = TRUE; break; - case BSIM4_MOD_RBSBY0 : + case BSIM4_MOD_RBSBY0 : mod->BSIM4rbsby0 = value->rValue; mod->BSIM4rbsby0Given = TRUE; break; - case BSIM4_MOD_RBDBX0 : + case BSIM4_MOD_RBDBX0 : mod->BSIM4rbdbx0 = value->rValue; mod->BSIM4rbdbx0Given = TRUE; break; - case BSIM4_MOD_RBDBY0 : + case BSIM4_MOD_RBDBY0 : mod->BSIM4rbdby0 = value->rValue; mod->BSIM4rbdby0Given = TRUE; break; - case BSIM4_MOD_RBSDBXL : + case BSIM4_MOD_RBSDBXL : mod->BSIM4rbsdbxl = value->rValue; mod->BSIM4rbsdbxlGiven = TRUE; break; - case BSIM4_MOD_RBSDBXW : + case BSIM4_MOD_RBSDBXW : mod->BSIM4rbsdbxw = value->rValue; mod->BSIM4rbsdbxwGiven = TRUE; break; - case BSIM4_MOD_RBSDBXNF : + case BSIM4_MOD_RBSDBXNF : mod->BSIM4rbsdbxnf = value->rValue; mod->BSIM4rbsdbxnfGiven = TRUE; break; - case BSIM4_MOD_RBSDBYL : + case BSIM4_MOD_RBSDBYL : mod->BSIM4rbsdbyl = value->rValue; mod->BSIM4rbsdbylGiven = TRUE; break; - case BSIM4_MOD_RBSDBYW : + case BSIM4_MOD_RBSDBYW : mod->BSIM4rbsdbyw = value->rValue; mod->BSIM4rbsdbywGiven = TRUE; break; - case BSIM4_MOD_RBSDBYNF : + case BSIM4_MOD_RBSDBYNF : mod->BSIM4rbsdbynf = value->rValue; mod->BSIM4rbsdbynfGiven = TRUE; break; - + case BSIM4_MOD_CGSL : mod->BSIM4cgsl = value->rValue; mod->BSIM4cgslGiven = TRUE; @@ -1494,13 +1494,11 @@ GENmodel *inMod) mod->BSIM4tpbswgGiven = TRUE; break; - /* Length dependence */ + /* Length dependence */ case BSIM4_MOD_LCDSC : mod->BSIM4lcdsc = value->rValue; mod->BSIM4lcdscGiven = TRUE; break; - - case BSIM4_MOD_LCDSCB : mod->BSIM4lcdscb = value->rValue; mod->BSIM4lcdscbGiven = TRUE; @@ -1525,8 +1523,8 @@ GENmodel *inMod) mod->BSIM4lvsat = value->rValue; mod->BSIM4lvsatGiven = TRUE; break; - - + + case BSIM4_MOD_LA0: mod->BSIM4la0 = value->rValue; mod->BSIM4la0Given = TRUE; @@ -1550,7 +1548,11 @@ GENmodel *inMod) case BSIM4_MOD_LKETA: mod->BSIM4lketa = value->rValue; mod->BSIM4lketaGiven = TRUE; - break; + break; + case BSIM4_MOD_LKETAC: + mod->BSIM4lketac = value->rValue; + mod->BSIM4lketacGiven = TRUE; + break; case BSIM4_MOD_LNSUB: mod->BSIM4lnsub = value->rValue; mod->BSIM4lnsubGiven = TRUE; @@ -1657,35 +1659,35 @@ GENmodel *inMod) mod->BSIM4lw0 = value->rValue; mod->BSIM4lw0Given = TRUE; break; - case BSIM4_MOD_LDVT0: + case BSIM4_MOD_LDVT0: mod->BSIM4ldvt0 = value->rValue; mod->BSIM4ldvt0Given = TRUE; break; - case BSIM4_MOD_LDVT1: + case BSIM4_MOD_LDVT1: mod->BSIM4ldvt1 = value->rValue; mod->BSIM4ldvt1Given = TRUE; break; - case BSIM4_MOD_LDVT2: + case BSIM4_MOD_LDVT2: mod->BSIM4ldvt2 = value->rValue; mod->BSIM4ldvt2Given = TRUE; break; - case BSIM4_MOD_LDVT0W: + case BSIM4_MOD_LDVT0W: mod->BSIM4ldvt0w = value->rValue; mod->BSIM4ldvt0wGiven = TRUE; break; - case BSIM4_MOD_LDVT1W: + case BSIM4_MOD_LDVT1W: mod->BSIM4ldvt1w = value->rValue; mod->BSIM4ldvt1wGiven = TRUE; break; - case BSIM4_MOD_LDVT2W: + case BSIM4_MOD_LDVT2W: mod->BSIM4ldvt2w = value->rValue; mod->BSIM4ldvt2wGiven = TRUE; break; - case BSIM4_MOD_LDROUT: + case BSIM4_MOD_LDROUT: mod->BSIM4ldrout = value->rValue; mod->BSIM4ldroutGiven = TRUE; break; - case BSIM4_MOD_LDSUB: + case BSIM4_MOD_LDSUB: mod->BSIM4ldsub = value->rValue; mod->BSIM4ldsubGiven = TRUE; break; @@ -1725,7 +1727,7 @@ GENmodel *inMod) mod->BSIM4lute = value->rValue; mod->BSIM4luteGiven = TRUE; break; - case BSIM4_MOD_LUCSTE : + case BSIM4_MOD_LUCSTE : mod->BSIM4lucste = value->rValue; mod->BSIM4lucsteGiven = TRUE; break; @@ -1737,15 +1739,15 @@ GENmodel *inMod) mod->BSIM4ltvoff = value->rValue; mod->BSIM4ltvoffGiven = TRUE; break; - case BSIM4_MOD_LTNFACTOR: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_LTNFACTOR: /* v4.7 temp dep of leakage current */ mod->BSIM4ltnfactor = value->rValue; mod->BSIM4ltnfactorGiven = TRUE; break; - case BSIM4_MOD_LTETA0: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_LTETA0: /* v4.7 temp dep of leakage current */ mod->BSIM4lteta0 = value->rValue; mod->BSIM4lteta0Given = TRUE; break; - case BSIM4_MOD_LTVOFFCV: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_LTVOFFCV: /* v4.7 temp dep of leakage current */ mod->BSIM4ltvoffcv = value->rValue; mod->BSIM4ltvoffcvGiven = TRUE; break; @@ -1776,7 +1778,7 @@ GENmodel *inMod) case BSIM4_MOD_LRDSW: mod->BSIM4lrdsw = value->rValue; mod->BSIM4lrdswGiven = TRUE; - break; + break; case BSIM4_MOD_LRDW: mod->BSIM4lrdw = value->rValue; mod->BSIM4lrdwGiven = TRUE; @@ -1788,51 +1790,51 @@ GENmodel *inMod) case BSIM4_MOD_LPRWB: mod->BSIM4lprwb = value->rValue; mod->BSIM4lprwbGiven = TRUE; - break; + break; case BSIM4_MOD_LPRWG: mod->BSIM4lprwg = value->rValue; mod->BSIM4lprwgGiven = TRUE; - break; + break; case BSIM4_MOD_LPRT: mod->BSIM4lprt = value->rValue; mod->BSIM4lprtGiven = TRUE; - break; + break; case BSIM4_MOD_LETA0: mod->BSIM4leta0 = value->rValue; mod->BSIM4leta0Given = TRUE; - break; + break; case BSIM4_MOD_LETAB: mod->BSIM4letab = value->rValue; mod->BSIM4letabGiven = TRUE; - break; + break; case BSIM4_MOD_LPCLM: mod->BSIM4lpclm = value->rValue; mod->BSIM4lpclmGiven = TRUE; - break; + break; case BSIM4_MOD_LPDIBL1: mod->BSIM4lpdibl1 = value->rValue; mod->BSIM4lpdibl1Given = TRUE; - break; + break; case BSIM4_MOD_LPDIBL2: mod->BSIM4lpdibl2 = value->rValue; mod->BSIM4lpdibl2Given = TRUE; - break; + break; case BSIM4_MOD_LPDIBLB: mod->BSIM4lpdiblb = value->rValue; mod->BSIM4lpdiblbGiven = TRUE; - break; + break; case BSIM4_MOD_LPSCBE1: mod->BSIM4lpscbe1 = value->rValue; mod->BSIM4lpscbe1Given = TRUE; - break; + break; case BSIM4_MOD_LPSCBE2: mod->BSIM4lpscbe2 = value->rValue; mod->BSIM4lpscbe2Given = TRUE; - break; + break; case BSIM4_MOD_LPVAG: mod->BSIM4lpvag = value->rValue; mod->BSIM4lpvagGiven = TRUE; - break; + break; case BSIM4_MOD_LWR : mod->BSIM4lwr = value->rValue; mod->BSIM4lwrGiven = TRUE; @@ -1885,15 +1887,15 @@ GENmodel *inMod) mod->BSIM4legidl = value->rValue; mod->BSIM4legidlGiven = TRUE; break; - case BSIM4_MOD_LFGIDL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_LFGIDL : /* v4.7 New GIDL/GISL */ mod->BSIM4lfgidl = value->rValue; mod->BSIM4lfgidlGiven = TRUE; break; - case BSIM4_MOD_LKGIDL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_LKGIDL : /* v4.7 New GIDL/GISL */ mod->BSIM4lkgidl = value->rValue; mod->BSIM4lkgidlGiven = TRUE; break; - case BSIM4_MOD_LRGIDL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_LRGIDL : /* v4.7 New GIDL/GISL */ mod->BSIM4lrgidl = value->rValue; mod->BSIM4lrgidlGiven = TRUE; break; @@ -1913,15 +1915,15 @@ GENmodel *inMod) mod->BSIM4legisl = value->rValue; mod->BSIM4legislGiven = TRUE; break; - case BSIM4_MOD_LFGISL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_LFGISL : /* v4.7 New GIDL/GISL */ mod->BSIM4lfgisl = value->rValue; mod->BSIM4lfgislGiven = TRUE; break; - case BSIM4_MOD_LKGISL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_LKGISL : /* v4.7 New GIDL/GISL */ mod->BSIM4lkgisl = value->rValue; mod->BSIM4lkgislGiven = TRUE; break; - case BSIM4_MOD_LRGISL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_LRGISL : /* v4.7 New GIDL/GISL */ mod->BSIM4lrgisl = value->rValue; mod->BSIM4lrgislGiven = TRUE; break; @@ -2057,7 +2059,7 @@ GENmodel *inMod) mod->BSIM4leu = value->rValue; mod->BSIM4leuGiven = TRUE; break; - case BSIM4_MOD_LUCS : + case BSIM4_MOD_LUCS : mod->BSIM4lucs = value->rValue; mod->BSIM4lucsGiven = TRUE; break; @@ -2114,13 +2116,13 @@ GENmodel *inMod) mod->BSIM4lvoffcvGiven = TRUE; break; - /* Width dependence */ + /* Width dependence */ case BSIM4_MOD_WCDSC : mod->BSIM4wcdsc = value->rValue; mod->BSIM4wcdscGiven = TRUE; break; - - + + case BSIM4_MOD_WCDSCB : mod->BSIM4wcdscb = value->rValue; mod->BSIM4wcdscbGiven = TRUE; @@ -2170,7 +2172,11 @@ GENmodel *inMod) case BSIM4_MOD_WKETA: mod->BSIM4wketa = value->rValue; mod->BSIM4wketaGiven = TRUE; - break; + break; + case BSIM4_MOD_WKETAC: + mod->BSIM4wketac = value->rValue; + mod->BSIM4wketacGiven = TRUE; + break; case BSIM4_MOD_WNSUB: mod->BSIM4wnsub = value->rValue; mod->BSIM4wnsubGiven = TRUE; @@ -2272,40 +2278,40 @@ GENmodel *inMod) case BSIM4_MOD_WDVTP5: mod->BSIM4wdvtp5 = value->rValue; mod->BSIM4wdvtp5Given = TRUE; - break; + break; case BSIM4_MOD_WW0: mod->BSIM4ww0 = value->rValue; mod->BSIM4ww0Given = TRUE; break; - case BSIM4_MOD_WDVT0: + case BSIM4_MOD_WDVT0: mod->BSIM4wdvt0 = value->rValue; mod->BSIM4wdvt0Given = TRUE; break; - case BSIM4_MOD_WDVT1: + case BSIM4_MOD_WDVT1: mod->BSIM4wdvt1 = value->rValue; mod->BSIM4wdvt1Given = TRUE; break; - case BSIM4_MOD_WDVT2: + case BSIM4_MOD_WDVT2: mod->BSIM4wdvt2 = value->rValue; mod->BSIM4wdvt2Given = TRUE; break; - case BSIM4_MOD_WDVT0W: + case BSIM4_MOD_WDVT0W: mod->BSIM4wdvt0w = value->rValue; mod->BSIM4wdvt0wGiven = TRUE; break; - case BSIM4_MOD_WDVT1W: + case BSIM4_MOD_WDVT1W: mod->BSIM4wdvt1w = value->rValue; mod->BSIM4wdvt1wGiven = TRUE; break; - case BSIM4_MOD_WDVT2W: + case BSIM4_MOD_WDVT2W: mod->BSIM4wdvt2w = value->rValue; mod->BSIM4wdvt2wGiven = TRUE; break; - case BSIM4_MOD_WDROUT: + case BSIM4_MOD_WDROUT: mod->BSIM4wdrout = value->rValue; mod->BSIM4wdroutGiven = TRUE; break; - case BSIM4_MOD_WDSUB: + case BSIM4_MOD_WDSUB: mod->BSIM4wdsub = value->rValue; mod->BSIM4wdsubGiven = TRUE; break; @@ -2357,15 +2363,15 @@ GENmodel *inMod) mod->BSIM4wtvoff = value->rValue; mod->BSIM4wtvoffGiven = TRUE; break; - case BSIM4_MOD_WTNFACTOR: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_WTNFACTOR: /* v4.7 temp dep of leakage current */ mod->BSIM4wtnfactor = value->rValue; mod->BSIM4wtnfactorGiven = TRUE; break; - case BSIM4_MOD_WTETA0: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_WTETA0: /* v4.7 temp dep of leakage current */ mod->BSIM4wteta0 = value->rValue; mod->BSIM4wteta0Given = TRUE; break; - case BSIM4_MOD_WTVOFFCV: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_WTVOFFCV: /* v4.7 temp dep of leakage current */ mod->BSIM4wtvoffcv = value->rValue; mod->BSIM4wtvoffcvGiven = TRUE; break; @@ -2396,7 +2402,7 @@ GENmodel *inMod) case BSIM4_MOD_WRDSW: mod->BSIM4wrdsw = value->rValue; mod->BSIM4wrdswGiven = TRUE; - break; + break; case BSIM4_MOD_WRDW: mod->BSIM4wrdw = value->rValue; mod->BSIM4wrdwGiven = TRUE; @@ -2408,51 +2414,51 @@ GENmodel *inMod) case BSIM4_MOD_WPRWB: mod->BSIM4wprwb = value->rValue; mod->BSIM4wprwbGiven = TRUE; - break; + break; case BSIM4_MOD_WPRWG: mod->BSIM4wprwg = value->rValue; mod->BSIM4wprwgGiven = TRUE; - break; + break; case BSIM4_MOD_WPRT: mod->BSIM4wprt = value->rValue; mod->BSIM4wprtGiven = TRUE; - break; + break; case BSIM4_MOD_WETA0: mod->BSIM4weta0 = value->rValue; mod->BSIM4weta0Given = TRUE; - break; + break; case BSIM4_MOD_WETAB: mod->BSIM4wetab = value->rValue; mod->BSIM4wetabGiven = TRUE; - break; + break; case BSIM4_MOD_WPCLM: mod->BSIM4wpclm = value->rValue; mod->BSIM4wpclmGiven = TRUE; - break; + break; case BSIM4_MOD_WPDIBL1: mod->BSIM4wpdibl1 = value->rValue; mod->BSIM4wpdibl1Given = TRUE; - break; + break; case BSIM4_MOD_WPDIBL2: mod->BSIM4wpdibl2 = value->rValue; mod->BSIM4wpdibl2Given = TRUE; - break; + break; case BSIM4_MOD_WPDIBLB: mod->BSIM4wpdiblb = value->rValue; mod->BSIM4wpdiblbGiven = TRUE; - break; + break; case BSIM4_MOD_WPSCBE1: mod->BSIM4wpscbe1 = value->rValue; mod->BSIM4wpscbe1Given = TRUE; - break; + break; case BSIM4_MOD_WPSCBE2: mod->BSIM4wpscbe2 = value->rValue; mod->BSIM4wpscbe2Given = TRUE; - break; + break; case BSIM4_MOD_WPVAG: mod->BSIM4wpvag = value->rValue; mod->BSIM4wpvagGiven = TRUE; - break; + break; case BSIM4_MOD_WWR : mod->BSIM4wwr = value->rValue; mod->BSIM4wwrGiven = TRUE; @@ -2505,15 +2511,15 @@ GENmodel *inMod) mod->BSIM4wegidl = value->rValue; mod->BSIM4wegidlGiven = TRUE; break; - case BSIM4_MOD_WFGIDL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_WFGIDL : /* v4.7 New GIDL/GISL */ mod->BSIM4wfgidl = value->rValue; mod->BSIM4wfgidlGiven = TRUE; break; - case BSIM4_MOD_WKGIDL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_WKGIDL : /* v4.7 New GIDL/GISL */ mod->BSIM4wkgidl = value->rValue; mod->BSIM4wkgidlGiven = TRUE; break; - case BSIM4_MOD_WRGIDL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_WRGIDL : /* v4.7 New GIDL/GISL */ mod->BSIM4wrgidl = value->rValue; mod->BSIM4wrgidlGiven = TRUE; break; @@ -2533,15 +2539,15 @@ GENmodel *inMod) mod->BSIM4wegisl = value->rValue; mod->BSIM4wegislGiven = TRUE; break; - case BSIM4_MOD_WFGISL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_WFGISL : /* v4.7 New GIDL/GISL */ mod->BSIM4wfgisl = value->rValue; mod->BSIM4wfgislGiven = TRUE; break; - case BSIM4_MOD_WKGISL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_WKGISL : /* v4.7 New GIDL/GISL */ mod->BSIM4wkgisl = value->rValue; mod->BSIM4wkgislGiven = TRUE; break; - case BSIM4_MOD_WRGISL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_WRGISL : /* v4.7 New GIDL/GISL */ mod->BSIM4wrgisl = value->rValue; mod->BSIM4wrgislGiven = TRUE; break; @@ -2677,7 +2683,7 @@ GENmodel *inMod) mod->BSIM4weu = value->rValue; mod->BSIM4weuGiven = TRUE; break; - case BSIM4_MOD_WUCS : + case BSIM4_MOD_WUCS : mod->BSIM4wucs = value->rValue; mod->BSIM4wucsGiven = TRUE; break; @@ -2734,7 +2740,7 @@ GENmodel *inMod) mod->BSIM4wvoffcvGiven = TRUE; break; - /* Cross-term dependence */ + /* Cross-term dependence */ case BSIM4_MOD_PCDSC : mod->BSIM4pcdsc = value->rValue; mod->BSIM4pcdscGiven = TRUE; @@ -2790,7 +2796,11 @@ GENmodel *inMod) case BSIM4_MOD_PKETA: mod->BSIM4pketa = value->rValue; mod->BSIM4pketaGiven = TRUE; - break; + break; + case BSIM4_MOD_PKETAC: + mod->BSIM4pketac = value->rValue; + mod->BSIM4pketacGiven = TRUE; + break; case BSIM4_MOD_PNSUB: mod->BSIM4pnsub = value->rValue; mod->BSIM4pnsubGiven = TRUE; @@ -2897,35 +2907,35 @@ GENmodel *inMod) mod->BSIM4pw0 = value->rValue; mod->BSIM4pw0Given = TRUE; break; - case BSIM4_MOD_PDVT0: + case BSIM4_MOD_PDVT0: mod->BSIM4pdvt0 = value->rValue; mod->BSIM4pdvt0Given = TRUE; break; - case BSIM4_MOD_PDVT1: + case BSIM4_MOD_PDVT1: mod->BSIM4pdvt1 = value->rValue; mod->BSIM4pdvt1Given = TRUE; break; - case BSIM4_MOD_PDVT2: + case BSIM4_MOD_PDVT2: mod->BSIM4pdvt2 = value->rValue; mod->BSIM4pdvt2Given = TRUE; break; - case BSIM4_MOD_PDVT0W: + case BSIM4_MOD_PDVT0W: mod->BSIM4pdvt0w = value->rValue; mod->BSIM4pdvt0wGiven = TRUE; break; - case BSIM4_MOD_PDVT1W: + case BSIM4_MOD_PDVT1W: mod->BSIM4pdvt1w = value->rValue; mod->BSIM4pdvt1wGiven = TRUE; break; - case BSIM4_MOD_PDVT2W: + case BSIM4_MOD_PDVT2W: mod->BSIM4pdvt2w = value->rValue; mod->BSIM4pdvt2wGiven = TRUE; break; - case BSIM4_MOD_PDROUT: + case BSIM4_MOD_PDROUT: mod->BSIM4pdrout = value->rValue; mod->BSIM4pdroutGiven = TRUE; break; - case BSIM4_MOD_PDSUB: + case BSIM4_MOD_PDSUB: mod->BSIM4pdsub = value->rValue; mod->BSIM4pdsubGiven = TRUE; break; @@ -2965,7 +2975,7 @@ GENmodel *inMod) mod->BSIM4pute = value->rValue; mod->BSIM4puteGiven = TRUE; break; - case BSIM4_MOD_PUCSTE : + case BSIM4_MOD_PUCSTE : mod->BSIM4pucste = value->rValue; mod->BSIM4pucsteGiven = TRUE; break; @@ -2977,15 +2987,15 @@ GENmodel *inMod) mod->BSIM4ptvoff = value->rValue; mod->BSIM4ptvoffGiven = TRUE; break; - case BSIM4_MOD_PTNFACTOR: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_PTNFACTOR: /* v4.7 temp dep of leakage current */ mod->BSIM4ptnfactor = value->rValue; mod->BSIM4ptnfactorGiven = TRUE; break; - case BSIM4_MOD_PTETA0: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_PTETA0: /* v4.7 temp dep of leakage current */ mod->BSIM4pteta0 = value->rValue; mod->BSIM4pteta0Given = TRUE; break; - case BSIM4_MOD_PTVOFFCV: /* v4.7 temp dep of leakage current */ + case BSIM4_MOD_PTVOFFCV: /* v4.7 temp dep of leakage current */ mod->BSIM4ptvoffcv = value->rValue; mod->BSIM4ptvoffcvGiven = TRUE; break; @@ -3016,7 +3026,7 @@ GENmodel *inMod) case BSIM4_MOD_PRDSW: mod->BSIM4prdsw = value->rValue; mod->BSIM4prdswGiven = TRUE; - break; + break; case BSIM4_MOD_PRDW: mod->BSIM4prdw = value->rValue; mod->BSIM4prdwGiven = TRUE; @@ -3028,51 +3038,51 @@ GENmodel *inMod) case BSIM4_MOD_PPRWB: mod->BSIM4pprwb = value->rValue; mod->BSIM4pprwbGiven = TRUE; - break; + break; case BSIM4_MOD_PPRWG: mod->BSIM4pprwg = value->rValue; mod->BSIM4pprwgGiven = TRUE; - break; + break; case BSIM4_MOD_PPRT: mod->BSIM4pprt = value->rValue; mod->BSIM4pprtGiven = TRUE; - break; + break; case BSIM4_MOD_PETA0: mod->BSIM4peta0 = value->rValue; mod->BSIM4peta0Given = TRUE; - break; + break; case BSIM4_MOD_PETAB: mod->BSIM4petab = value->rValue; mod->BSIM4petabGiven = TRUE; - break; + break; case BSIM4_MOD_PPCLM: mod->BSIM4ppclm = value->rValue; mod->BSIM4ppclmGiven = TRUE; - break; + break; case BSIM4_MOD_PPDIBL1: mod->BSIM4ppdibl1 = value->rValue; mod->BSIM4ppdibl1Given = TRUE; - break; + break; case BSIM4_MOD_PPDIBL2: mod->BSIM4ppdibl2 = value->rValue; mod->BSIM4ppdibl2Given = TRUE; - break; + break; case BSIM4_MOD_PPDIBLB: mod->BSIM4ppdiblb = value->rValue; mod->BSIM4ppdiblbGiven = TRUE; - break; + break; case BSIM4_MOD_PPSCBE1: mod->BSIM4ppscbe1 = value->rValue; mod->BSIM4ppscbe1Given = TRUE; - break; + break; case BSIM4_MOD_PPSCBE2: mod->BSIM4ppscbe2 = value->rValue; mod->BSIM4ppscbe2Given = TRUE; - break; + break; case BSIM4_MOD_PPVAG: mod->BSIM4ppvag = value->rValue; mod->BSIM4ppvagGiven = TRUE; - break; + break; case BSIM4_MOD_PWR : mod->BSIM4pwr = value->rValue; mod->BSIM4pwrGiven = TRUE; @@ -3125,15 +3135,15 @@ GENmodel *inMod) mod->BSIM4pegidl = value->rValue; mod->BSIM4pegidlGiven = TRUE; break; - case BSIM4_MOD_PFGIDL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_PFGIDL : /* v4.7 New GIDL/GISL */ mod->BSIM4pfgidl = value->rValue; mod->BSIM4pfgidlGiven = TRUE; break; - case BSIM4_MOD_PKGIDL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_PKGIDL : /* v4.7 New GIDL/GISL */ mod->BSIM4pkgidl = value->rValue; mod->BSIM4pkgidlGiven = TRUE; break; - case BSIM4_MOD_PRGIDL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_PRGIDL : /* v4.7 New GIDL/GISL */ mod->BSIM4prgidl = value->rValue; mod->BSIM4prgidlGiven = TRUE; break; @@ -3153,15 +3163,15 @@ GENmodel *inMod) mod->BSIM4pegisl = value->rValue; mod->BSIM4pegislGiven = TRUE; break; - case BSIM4_MOD_PFGISL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_PFGISL : /* v4.7 New GIDL/GISL */ mod->BSIM4pfgisl = value->rValue; mod->BSIM4pfgislGiven = TRUE; break; - case BSIM4_MOD_PKGISL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_PKGISL : /* v4.7 New GIDL/GISL */ mod->BSIM4pkgisl = value->rValue; mod->BSIM4pkgislGiven = TRUE; break; - case BSIM4_MOD_PRGISL : /* v4.7 New GIDL/GISL */ + case BSIM4_MOD_PRGISL : /* v4.7 New GIDL/GISL */ mod->BSIM4prgisl = value->rValue; mod->BSIM4prgislGiven = TRUE; break; @@ -3297,7 +3307,7 @@ GENmodel *inMod) mod->BSIM4peu = value->rValue; mod->BSIM4peuGiven = TRUE; break; - case BSIM4_MOD_PUCS : + case BSIM4_MOD_PUCS : mod->BSIM4pucs = value->rValue; mod->BSIM4pucsGiven = TRUE; break; @@ -3608,15 +3618,6 @@ GENmodel *inMod) mod->BSIM4kfGiven = TRUE; break; - case BSIM4_MOD_GIDLCLAMP: - mod->BSIM4gidlclamp = value->rValue; - mod->BSIM4gidlclampGiven = TRUE; - break; - case BSIM4_MOD_IDOVVDSC: - mod->BSIM4idovvdsc = value->rValue; - mod->BSIM4idovvdscGiven = TRUE; - break; - case BSIM4_MOD_VGS_MAX: mod->BSIM4vgsMax = value->rValue; mod->BSIM4vgsMaxGiven = TRUE; @@ -3681,3 +3682,4 @@ GENmodel *inMod) } + diff --git a/src/spicelib/devices/bsim4/b4noi.c b/src/spicelib/devices/bsim4/b4noi.c index 3f3801d72..473dea60d 100644 --- a/src/spicelib/devices/bsim4/b4noi.c +++ b/src/spicelib/devices/bsim4/b4noi.c @@ -1,29 +1,25 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* Licensed under Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the license at http://opensource.org/licenses/ECL-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc */ #include "ngspice/ngspice.h" @@ -50,7 +46,7 @@ double freq, double temp) { struct bsim4SizeDependParam *pParam; double cd, esat, DelClm, EffFreq, N0, Nl, Leff, Leffsq; -double T0=0.0, T1, T2, T3, T4, T5, T6, T7, T8, T9, Ssi; +double T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, Ssi; pParam = here->pParam; cd = fabs(here->BSIM4cd); @@ -59,10 +55,10 @@ double T0=0.0, T1, T2, T3, T4, T5, T6, T7, T8, T9, Ssi; esat = 2.0 * here->BSIM4vsattemp / here->BSIM4ueff; if(model->BSIM4em<=0.0) DelClm = 0.0; /* flicker noise modified -JX */ else { - T0 = ((((Vds - here->BSIM4Vdseff) / pParam->BSIM4litl) - + model->BSIM4em) / esat); - DelClm = pParam->BSIM4litl * log (MAX(T0, N_MINLOG)); - if (DelClm < 0.0) DelClm = 0.0; /* bugfix */ + T0 = ((((Vds - here->BSIM4Vdseff) / pParam->BSIM4litl) + + model->BSIM4em) / esat); + DelClm = pParam->BSIM4litl * log (MAX(T0, N_MINLOG)); + if (DelClm < 0.0) DelClm = 0.0; /* bugfix */ } EffFreq = pow(freq, model->BSIM4ef); T1 = CHARGE * CHARGE * CONSTboltz * cd * temp * here->BSIM4ueff; @@ -85,7 +81,6 @@ double T0=0.0, T1, T2, T3, T4, T5, T6, T7, T8, T9, Ssi; return Ssi; } - int BSIM4noise ( int mode, int operation, @@ -94,8 +89,6 @@ CKTcircuit *ckt, Ndata *data, double *OnDens) { -NOISEAN *job = (NOISEAN *) ckt->CKTcurJob; - BSIM4model *model = (BSIM4model *)inModel; BSIM4instance *here; struct bsim4SizeDependParam *pParam; @@ -113,91 +106,87 @@ double eta, Leff, Lvsat, gamma, delta, epsilon, GammaGd0=0.0; double npart_c, sigrat=0.0, C0, omega, ctnoi=0.0; int i; - -double m; +double mult_i, mult_fn; /* define the names of the noise sources */ static char *BSIM4nNames[BSIM4NSRCS] = { /* Note that we have to keep the order */ - ".rd", /* noise due to rd */ - ".rs", /* noise due to rs */ + ".rd", /* noise due to rd */ + ".rs", /* noise due to rs */ ".rg", /* noise due to rgeltd */ ".rbps", /* noise due to rbps */ ".rbpd", /* noise due to rbpd */ ".rbpb", /* noise due to rbpb */ ".rbsb", /* noise due to rbsb */ ".rbdb", /* noise due to rbdb */ - ".id", /* noise due to id (for tnoiMod2: uncorrelated portion only) */ - ".1overf", /* flicker (1/f) noise */ + ".id", /* noise due to id (for tnoiMod2: uncorrelated portion only) */ + ".1overf", /* flicker (1/f) noise */ ".igs", /* shot noise due to IGS */ ".igd", /* shot noise due to IGD */ ".igb", /* shot noise due to IGB */ ".corl", /* contribution of correlated drain and induced gate noise */ - "" /* total transistor noise */ + "" /* total transistor noise */ }; for (; model != NULL; model = BSIM4nextModel(model)) - { - if(model->BSIM4tnoiMod != 2) { - noizDens[BSIM4CORLNOIZ] = 0.0; - lnNdens[BSIM4CORLNOIZ] = N_MINLOG; - } + { for (here = BSIM4instances(model); here != NULL; here = BSIM4nextInstance(here)) - { pParam = here->pParam; - switch (operation) - { case N_OPEN: - /* see if we have to to produce a summary report */ - /* if so, name all the noise generators */ + { pParam = here->pParam; + switch (operation) + { case N_OPEN: + /* see if we have to to produce a summary report */ + /* if so, name all the noise generators */ - if (job->NStpsSm != 0) - { switch (mode) - { case N_DENS: - for (i = 0; i < BSIM4NSRCS; i++) - { NOISE_ADD_OUTVAR(ckt, data, "onoise.%s%s", here->BSIM4name, BSIM4nNames[i]); - } - break; - case INT_NOIZ: - for (i = 0; i < BSIM4NSRCS; i++) - { NOISE_ADD_OUTVAR(ckt, data, "onoise_total.%s%s", here->BSIM4name, BSIM4nNames[i]); - NOISE_ADD_OUTVAR(ckt, data, "inoise_total.%s%s", here->BSIM4name, BSIM4nNames[i]); - } - break; - } + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) + { switch (mode) + { case N_DENS: + for (i = 0; i < BSIM4NSRCS; i++) + { NOISE_ADD_OUTVAR(ckt, data, "onoise.%s%s", here->BSIM4name, BSIM4nNames[i]); } break; - case N_CALC: - m = here->BSIM4m; - switch (mode) - { case N_DENS: - if (model->BSIM4tnoiMod == 0) - { if (model->BSIM4rdsMod == 0) - { gspr = here->BSIM4sourceConductance; + case INT_NOIZ: + for (i = 0; i < BSIM4NSRCS; i++) + { NOISE_ADD_OUTVAR(ckt, data, "onoise_total.%s%s", here->BSIM4name, BSIM4nNames[i]); + NOISE_ADD_OUTVAR(ckt, data, "inoise_total.%s%s", here->BSIM4name, BSIM4nNames[i]); + } + break; + } + } + break; + case N_CALC: + mult_i = here->BSIM4mult_i; + mult_fn = here->BSIM4mult_fn; + switch (mode) + { case N_DENS: + if (model->BSIM4tnoiMod == 0) + { if (model->BSIM4rdsMod == 0) + { gspr = here->BSIM4sourceConductance; gdpr = here->BSIM4drainConductance; - if (here->BSIM4grdsw > 0.0) - tmp = 1.0 / here->BSIM4grdsw; /* tmp used below */ - else - tmp = 0.0; - } - else - { gspr = here->BSIM4gstot; + if (here->BSIM4grdsw > 0.0) + tmp = 1.0 / here->BSIM4grdsw; /* tmp used below */ + else + tmp = 0.0; + } + else + { gspr = here->BSIM4gstot; gdpr = here->BSIM4gdtot; tmp = 0.0; - } - } - else if(model->BSIM4tnoiMod == 1) - { T5 = here->BSIM4Vgsteff / here->BSIM4EsatL; - T5 *= T5; - npart_beta = model->BSIM4rnoia * (1.0 + T5 - * model->BSIM4tnoia * pParam->BSIM4leff); - npart_theta = model->BSIM4rnoib * (1.0 + T5 + } + } + else if(model->BSIM4tnoiMod == 1) + { T5 = here->BSIM4Vgsteff / here->BSIM4EsatL; + T5 *= T5; + npart_beta = model->BSIM4rnoia * (1.0 + T5 + * model->BSIM4tnoia * pParam->BSIM4leff); + npart_theta = model->BSIM4rnoib * (1.0 + T5 * model->BSIM4tnoib * pParam->BSIM4leff); - if(npart_theta > 0.9) - npart_theta = 0.9; - if(npart_theta > 0.9 * npart_beta) - npart_theta = 0.9 * npart_beta; //4.6.2 + if(npart_theta > 0.9) + npart_theta = 0.9; + if(npart_theta > 0.9 * npart_beta) + npart_theta = 0.9 * npart_beta; //4.6.2 - if (model->BSIM4rdsMod == 0) + if (model->BSIM4rdsMod == 0) { gspr = here->BSIM4sourceConductance; gdpr = here->BSIM4drainConductance; } @@ -206,17 +195,17 @@ double m; gdpr = here->BSIM4gdtot; } - if ((*(ckt->CKTstates[0] + here->BSIM4vds)) >= 0.0) - gspr = gspr * (1.0 + npart_theta * npart_theta * gspr + if ((*(ckt->CKTstates[0] + here->BSIM4vds)) >= 0.0) + gspr = gspr * (1.0 + npart_theta * npart_theta * gspr + / here->BSIM4IdovVds); + else + gdpr = gdpr * (1.0 + npart_theta * npart_theta * gdpr / here->BSIM4IdovVds); - else - gdpr = gdpr * (1.0 + npart_theta * npart_theta * gdpr - / here->BSIM4IdovVds); - } - else - { /* tnoiMod=2 (v4.7) */ + } + else + { /* tnoiMod=2 (v4.7) */ - if (model->BSIM4rdsMod == 0) + if (model->BSIM4rdsMod == 0) { gspr = here->BSIM4sourceConductance; gdpr = here->BSIM4drainConductance; } @@ -225,119 +214,119 @@ double m; gdpr = here->BSIM4gdtot; } - } + } - NevalSrc(&noizDens[BSIM4RDNOIZ], - &lnNdens[BSIM4RDNOIZ], ckt, THERMNOISE, - here->BSIM4dNodePrime, here->BSIM4dNode, - gdpr * m); + NevalSrc(&noizDens[BSIM4RDNOIZ], + &lnNdens[BSIM4RDNOIZ], ckt, THERMNOISE, + here->BSIM4dNodePrime, here->BSIM4dNode, + gdpr * mult_i); - NevalSrc(&noizDens[BSIM4RSNOIZ], - &lnNdens[BSIM4RSNOIZ], ckt, THERMNOISE, - here->BSIM4sNodePrime, here->BSIM4sNode, - gspr * m); + NevalSrc(&noizDens[BSIM4RSNOIZ], + &lnNdens[BSIM4RSNOIZ], ckt, THERMNOISE, + here->BSIM4sNodePrime, here->BSIM4sNode, + gspr * mult_i); - if (here->BSIM4rgateMod == 1) - { NevalSrc(&noizDens[BSIM4RGNOIZ], + if (here->BSIM4rgateMod == 1) + { NevalSrc(&noizDens[BSIM4RGNOIZ], &lnNdens[BSIM4RGNOIZ], ckt, THERMNOISE, here->BSIM4gNodePrime, here->BSIM4gNodeExt, - here->BSIM4grgeltd * m); - } - else if (here->BSIM4rgateMod == 2) - { - T0 = 1.0 + here->BSIM4grgeltd/here->BSIM4gcrg; - T1 = T0 * T0; - NevalSrc(&noizDens[BSIM4RGNOIZ], + here->BSIM4grgeltd * mult_i); + } + else if (here->BSIM4rgateMod == 2) + { + T0 = 1.0 + here->BSIM4grgeltd/here->BSIM4gcrg; + T1 = T0 * T0; + NevalSrc(&noizDens[BSIM4RGNOIZ], &lnNdens[BSIM4RGNOIZ], ckt, THERMNOISE, here->BSIM4gNodePrime, here->BSIM4gNodeExt, - here->BSIM4grgeltd * m / T1); - } - else if (here->BSIM4rgateMod == 3) - { NevalSrc(&noizDens[BSIM4RGNOIZ], + here->BSIM4grgeltd * mult_i/T1); + } + else if (here->BSIM4rgateMod == 3) + { NevalSrc(&noizDens[BSIM4RGNOIZ], &lnNdens[BSIM4RGNOIZ], ckt, THERMNOISE, here->BSIM4gNodeMid, here->BSIM4gNodeExt, - here->BSIM4grgeltd * m); - } - else - { noizDens[BSIM4RGNOIZ] = 0.0; + here->BSIM4grgeltd * mult_i); + } + else + { noizDens[BSIM4RGNOIZ] = 0.0; lnNdens[BSIM4RGNOIZ] = log(MAX(noizDens[BSIM4RGNOIZ], N_MINLOG)); - } + } - bodymode = 5; - if (here->BSIM4rbodyMod == 2) - { if( ( !model->BSIM4rbps0Given) || - ( !model->BSIM4rbpd0Given) ) - bodymode = 1; - else - if( (!model->BSIM4rbsbx0Given && !model->BSIM4rbsby0Given) || - (!model->BSIM4rbdbx0Given && !model->BSIM4rbdby0Given) ) - bodymode = 3; - } + bodymode = 5; + if (here->BSIM4rbodyMod == 2) + { if( ( !model->BSIM4rbps0Given) || + ( !model->BSIM4rbpd0Given) ) + bodymode = 1; + else + if( (!model->BSIM4rbsbx0Given && !model->BSIM4rbsby0Given) || + (!model->BSIM4rbdbx0Given && !model->BSIM4rbdby0Given) ) + bodymode = 3; + } if (here->BSIM4rbodyMod) { - if(bodymode == 5) - { - NevalSrc(&noizDens[BSIM4RBPSNOIZ], - &lnNdens[BSIM4RBPSNOIZ], ckt, THERMNOISE, - here->BSIM4bNodePrime, here->BSIM4sbNode, - here->BSIM4grbps * m); - NevalSrc(&noizDens[BSIM4RBPDNOIZ], - &lnNdens[BSIM4RBPDNOIZ], ckt, THERMNOISE, - here->BSIM4bNodePrime, here->BSIM4dbNode, - here->BSIM4grbpd * m); - NevalSrc(&noizDens[BSIM4RBPBNOIZ], - &lnNdens[BSIM4RBPBNOIZ], ckt, THERMNOISE, - here->BSIM4bNodePrime, here->BSIM4bNode, - here->BSIM4grbpb * m); - NevalSrc(&noizDens[BSIM4RBSBNOIZ], - &lnNdens[BSIM4RBSBNOIZ], ckt, THERMNOISE, - here->BSIM4bNode, here->BSIM4sbNode, - here->BSIM4grbsb * m); - NevalSrc(&noizDens[BSIM4RBDBNOIZ], - &lnNdens[BSIM4RBDBNOIZ], ckt, THERMNOISE, - here->BSIM4bNode, here->BSIM4dbNode, - here->BSIM4grbdb * m); - } - if(bodymode == 3) - { - NevalSrc(&noizDens[BSIM4RBPSNOIZ], - &lnNdens[BSIM4RBPSNOIZ], ckt, THERMNOISE, - here->BSIM4bNodePrime, here->BSIM4sbNode, - here->BSIM4grbps * m); - NevalSrc(&noizDens[BSIM4RBPDNOIZ], - &lnNdens[BSIM4RBPDNOIZ], ckt, THERMNOISE, - here->BSIM4bNodePrime, here->BSIM4dbNode, - here->BSIM4grbpd * m); - NevalSrc(&noizDens[BSIM4RBPBNOIZ], - &lnNdens[BSIM4RBPBNOIZ], ckt, THERMNOISE, - here->BSIM4bNodePrime, here->BSIM4bNode, - here->BSIM4grbpb * m); - noizDens[BSIM4RBSBNOIZ] = noizDens[BSIM4RBDBNOIZ] = 0.0; - lnNdens[BSIM4RBSBNOIZ] = - log(MAX(noizDens[BSIM4RBSBNOIZ], N_MINLOG)); - lnNdens[BSIM4RBDBNOIZ] = - log(MAX(noizDens[BSIM4RBDBNOIZ], N_MINLOG)); - } - if(bodymode == 1) - { - NevalSrc(&noizDens[BSIM4RBPBNOIZ], - &lnNdens[BSIM4RBPBNOIZ], ckt, THERMNOISE, - here->BSIM4bNodePrime, here->BSIM4bNode, - here->BSIM4grbpb * m); - noizDens[BSIM4RBPSNOIZ] = noizDens[BSIM4RBPDNOIZ] = 0.0; - noizDens[BSIM4RBSBNOIZ] = noizDens[BSIM4RBDBNOIZ] = 0.0; - lnNdens[BSIM4RBPSNOIZ] = - log(MAX(noizDens[BSIM4RBPSNOIZ], N_MINLOG)); - lnNdens[BSIM4RBPDNOIZ] = - log(MAX(noizDens[BSIM4RBPDNOIZ], N_MINLOG)); - lnNdens[BSIM4RBSBNOIZ] = - log(MAX(noizDens[BSIM4RBSBNOIZ], N_MINLOG)); - lnNdens[BSIM4RBDBNOIZ] = - log(MAX(noizDens[BSIM4RBDBNOIZ], N_MINLOG)); - } + if(bodymode == 5) + { + NevalSrc(&noizDens[BSIM4RBPSNOIZ], + &lnNdens[BSIM4RBPSNOIZ], ckt, THERMNOISE, + here->BSIM4bNodePrime, here->BSIM4sbNode, + here->BSIM4grbps * mult_i); + NevalSrc(&noizDens[BSIM4RBPDNOIZ], + &lnNdens[BSIM4RBPDNOIZ], ckt, THERMNOISE, + here->BSIM4bNodePrime, here->BSIM4dbNode, + here->BSIM4grbpd * mult_i); + NevalSrc(&noizDens[BSIM4RBPBNOIZ], + &lnNdens[BSIM4RBPBNOIZ], ckt, THERMNOISE, + here->BSIM4bNodePrime, here->BSIM4bNode, + here->BSIM4grbpb * mult_i); + NevalSrc(&noizDens[BSIM4RBSBNOIZ], + &lnNdens[BSIM4RBSBNOIZ], ckt, THERMNOISE, + here->BSIM4bNode, here->BSIM4sbNode, + here->BSIM4grbsb * mult_i); + NevalSrc(&noizDens[BSIM4RBDBNOIZ], + &lnNdens[BSIM4RBDBNOIZ], ckt, THERMNOISE, + here->BSIM4bNode, here->BSIM4dbNode, + here->BSIM4grbdb * mult_i); + } + if(bodymode == 3) + { + NevalSrc(&noizDens[BSIM4RBPSNOIZ], + &lnNdens[BSIM4RBPSNOIZ], ckt, THERMNOISE, + here->BSIM4bNodePrime, here->BSIM4sbNode, + here->BSIM4grbps * mult_i); + NevalSrc(&noizDens[BSIM4RBPDNOIZ], + &lnNdens[BSIM4RBPDNOIZ], ckt, THERMNOISE, + here->BSIM4bNodePrime, here->BSIM4dbNode, + here->BSIM4grbpd * mult_i); + NevalSrc(&noizDens[BSIM4RBPBNOIZ], + &lnNdens[BSIM4RBPBNOIZ], ckt, THERMNOISE, + here->BSIM4bNodePrime, here->BSIM4bNode, + here->BSIM4grbpb * mult_i); + noizDens[BSIM4RBSBNOIZ] = noizDens[BSIM4RBDBNOIZ] = 0.0; + lnNdens[BSIM4RBSBNOIZ] = + log(MAX(noizDens[BSIM4RBSBNOIZ], N_MINLOG)); + lnNdens[BSIM4RBDBNOIZ] = + log(MAX(noizDens[BSIM4RBDBNOIZ], N_MINLOG)); + } + if(bodymode == 1) + { + NevalSrc(&noizDens[BSIM4RBPBNOIZ], + &lnNdens[BSIM4RBPBNOIZ], ckt, THERMNOISE, + here->BSIM4bNodePrime, here->BSIM4bNode, + here->BSIM4grbpb * mult_i); + noizDens[BSIM4RBPSNOIZ] = noizDens[BSIM4RBPDNOIZ] = 0.0; + noizDens[BSIM4RBSBNOIZ] = noizDens[BSIM4RBDBNOIZ] = 0.0; + lnNdens[BSIM4RBPSNOIZ] = + log(MAX(noizDens[BSIM4RBPSNOIZ], N_MINLOG)); + lnNdens[BSIM4RBPDNOIZ] = + log(MAX(noizDens[BSIM4RBPDNOIZ], N_MINLOG)); + lnNdens[BSIM4RBSBNOIZ] = + log(MAX(noizDens[BSIM4RBSBNOIZ], N_MINLOG)); + lnNdens[BSIM4RBDBNOIZ] = + log(MAX(noizDens[BSIM4RBDBNOIZ], N_MINLOG)); + } } else { noizDens[BSIM4RBPSNOIZ] = noizDens[BSIM4RBPDNOIZ] = 0.0; @@ -355,13 +344,13 @@ double m; log(MAX(noizDens[BSIM4RBDBNOIZ], N_MINLOG)); } - if(model->BSIM4tnoiMod == 2) - { + if(model->BSIM4tnoiMod == 2) + { eta = 1.0 - here->BSIM4Vdseff * here->BSIM4AbovVgst2Vtm; T0 = 1.0 - eta; T1 = 1.0 + eta; T2 = T1 + 2.0 * here->BSIM4Abulk * model->BSIM4vtm / here->BSIM4Vgsteff; - Leff = pParam->BSIM4leff; + Leff = pParam->BSIM4leff; Lvsat = Leff * (1.0 + here->BSIM4Vdseff / here->BSIM4EsatL); T6 = Leff / Lvsat; /*Unwanted code for T5 commented*/ @@ -375,173 +364,179 @@ double m; delta = (T1 / T3 - (5.0 * T1 + T2) * T4 / (15.0 * T5) + T4 * T4 / (9.0 * T5 * T2)) / (6.0 * T6 * T6 * T6); T7 = T0 / T2; 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))) + { + npart_c = model->BSIM4rnoic * (1.0 + T8 + * model->BSIM4tnoic * Leff); + ctnoi = epsilon / sqrt(gamma * delta) + * (2.5316 * npart_c); - T8 = here->BSIM4Vgsteff / here->BSIM4EsatL; - T8 *= T8; - if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4))) { - npart_c = model->BSIM4rnoic * (1.0 + T8 - * model->BSIM4tnoic * Leff); - ctnoi = epsilon / sqrt(gamma * delta) - * (2.5316 * npart_c); + npart_beta = model->BSIM4rnoia * (1.0 + T8 + * model->BSIM4tnoia * Leff); + npart_theta = model->BSIM4rnoib * (1.0 + T8 + * model->BSIM4tnoib * Leff); + gamma = gamma * (3.0 * npart_beta * npart_beta); + delta = delta * (3.75 * npart_theta * npart_theta); - npart_beta = model->BSIM4rnoia * (1.0 + T8 - * model->BSIM4tnoia * Leff); - npart_theta = model->BSIM4rnoib * (1.0 + T8 - * model->BSIM4tnoib * Leff); - gamma = gamma * (3.0 * npart_beta * npart_beta); - delta = delta * (3.75 * npart_theta * npart_theta); - - GammaGd0 = gamma * here->BSIM4noiGd0; - C0 = here->BSIM4Coxeff * pParam->BSIM4weffCV * here->BSIM4nf * pParam->BSIM4leffCV; - T0 = C0 / here->BSIM4noiGd0; - sigrat = T0 * sqrt(delta / gamma); - } - else - { - npart_c = model->BSIM4rnoic * (1.0 + T8 - * model->BSIM4tnoic * Leff); - /* Limits added for rnoia, rnoib, rnoic, tnoia, tnoib and tnoic in BSIM4.8.1 */ - T9 = gamma * delta ; - if (T9 > 0) - ctnoi = epsilon / sqrt( gamma * delta) * (2.5316 * npart_c); - else - ctnoi = 1.0 ; - if (ctnoi > 1) - ctnoi=1; - if (ctnoi < 0) - ctnoi=0; - - npart_beta = model->BSIM4rnoia * (1.0 + T8 - * model->BSIM4tnoia * Leff); - npart_theta = model->BSIM4rnoib * (1.0 + T8 - * model->BSIM4tnoib * Leff); - gamma = gamma * (3.0 * npart_beta * npart_beta); - delta = delta * (3.75 * npart_theta * npart_theta); - - GammaGd0 = gamma * here->BSIM4noiGd0; - C0 = here->BSIM4Coxeff * pParam->BSIM4weffCV * here->BSIM4nf * pParam->BSIM4leffCV; - T0 = C0 / here->BSIM4noiGd0; - - if (gamma > 0 && delta > 0) - sigrat = T0 * sqrt(delta / gamma); - else - sigrat = 0.0; - } + GammaGd0 = gamma * here->BSIM4noiGd0; + C0 = here->BSIM4Coxeff * pParam->BSIM4weffCV * here->BSIM4nf * pParam->BSIM4leffCV; + T0 = C0 / here->BSIM4noiGd0; + sigrat = T0 * sqrt(delta / gamma); } + else + {npart_c = model->BSIM4rnoic * (1.0 + T8 + * model->BSIM4tnoic * Leff); + /* Limits added for rnoia, rnoib, rnoic, tnoia, tnoib and tnoic in BSIM4.8.1 */ + T9 = gamma * delta ; + if (T9 > 0) + ctnoi = epsilon / sqrt( gamma * delta) * (2.5316 * npart_c); + else + ctnoi = 1.0 ; + if (ctnoi > 1) + ctnoi=1; + if (ctnoi < 0) + ctnoi=0; + npart_beta = model->BSIM4rnoia * (1.0 + T8 + * model->BSIM4tnoia * Leff); + npart_theta = model->BSIM4rnoib * (1.0 + T8 + * model->BSIM4tnoib * Leff); + gamma = gamma * (3.0 * npart_beta * npart_beta); + delta = delta * (3.75 * npart_theta * npart_theta); + + GammaGd0 = gamma * here->BSIM4noiGd0; + C0 = here->BSIM4Coxeff * pParam->BSIM4weffCV * here->BSIM4nf * pParam->BSIM4leffCV; + T0 = C0 / here->BSIM4noiGd0; + + if (gamma > 0 && delta > 0) + sigrat = T0 * sqrt(delta / gamma); + else + sigrat = 0.0; + } + } switch(model->BSIM4tnoiMod) - { case 0: - if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4))) { - T0 = here->BSIM4ueff * fabs(here->BSIM4qinv); - T1 = T0 * tmp + pParam->BSIM4leff - * pParam->BSIM4leff; - NevalSrc(&noizDens[BSIM4IDNOIZ], - &lnNdens[BSIM4IDNOIZ], ckt, - THERMNOISE, here->BSIM4dNodePrime, - here->BSIM4sNodePrime, - (T0 / T1) * model->BSIM4ntnoi * m); - } - else - { - T0 = here->BSIM4ueff * fabs(here->BSIM4qinv); - T1 = T0 * tmp + pParam->BSIM4leff - * pParam->BSIM4leff; - NevalSrc(&noizDens[BSIM4IDNOIZ], - &lnNdens[BSIM4IDNOIZ], ckt, - THERMNOISE, here->BSIM4dNodePrime, - here->BSIM4sNodePrime, - (T0 / T1) * model->BSIM4ntnoi * m); + { 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))) + { + T0 = here->BSIM4ueff * fabs(here->BSIM4qinv); + T1 = T0 * tmp + pParam->BSIM4leff + * pParam->BSIM4leff; + NevalSrc(&noizDens[BSIM4IDNOIZ], + &lnNdens[BSIM4IDNOIZ], ckt, + THERMNOISE, here->BSIM4dNodePrime, + here->BSIM4sNodePrime, + (T0 / T1) * model->BSIM4ntnoi * mult_i); + } + else + { + T0 = here->BSIM4ueff * fabs(here->BSIM4qinv); + T1 = T0 * tmp + pParam->BSIM4leff + * pParam->BSIM4leff; + NevalSrc(&noizDens[BSIM4IDNOIZ], + &lnNdens[BSIM4IDNOIZ], ckt, + THERMNOISE, here->BSIM4dNodePrime, + here->BSIM4sNodePrime, + (T0 / T1) * model->BSIM4ntnoi * mult_i); - noizDens[BSIM4CORLNOIZ] = 0.0; - lnNdens[BSIM4CORLNOIZ] = log(MAX(noizDens[BSIM4CORLNOIZ], N_MINLOG)); - } - break; - case 1: - if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4))) { - T0 = here->BSIM4gm + here->BSIM4gmbs + here->BSIM4gds; - T0 *= T0; - igsquare = npart_theta * npart_theta * T0 / here->BSIM4IdovVds; - T1 = npart_beta * (here->BSIM4gm - + here->BSIM4gmbs) + here->BSIM4gds; - T2 = T1 * T1 / here->BSIM4IdovVds; - NevalSrc(&noizDens[BSIM4IDNOIZ], - &lnNdens[BSIM4IDNOIZ], ckt, - THERMNOISE, here->BSIM4dNodePrime, - here->BSIM4sNodePrime, (T2 - igsquare) * m); - } - else - { - T0 = here->BSIM4gm + here->BSIM4gmbs + here->BSIM4gds; - T0 *= T0; - igsquare = npart_theta * npart_theta * T0 / here->BSIM4IdovVds; - T1 = npart_beta * (here->BSIM4gm - + here->BSIM4gmbs) + here->BSIM4gds; - T2 = T1 * T1 / here->BSIM4IdovVds; - NevalSrc(&noizDens[BSIM4IDNOIZ], - &lnNdens[BSIM4IDNOIZ], ckt, - THERMNOISE, here->BSIM4dNodePrime, - here->BSIM4sNodePrime, (T2 - igsquare) * m); + noizDens[BSIM4CORLNOIZ] = 0.0; + lnNdens[BSIM4CORLNOIZ] = log(MAX(noizDens[BSIM4CORLNOIZ], N_MINLOG)); + } + 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))) + { + T0 = here->BSIM4gm + here->BSIM4gmbs + here->BSIM4gds; + T0 *= T0; + igsquare = npart_theta * npart_theta * T0 / here->BSIM4IdovVds; + T1 = npart_beta * (here->BSIM4gm + + here->BSIM4gmbs) + here->BSIM4gds; + T2 = T1 * T1 / here->BSIM4IdovVds; + NevalSrc(&noizDens[BSIM4IDNOIZ], + &lnNdens[BSIM4IDNOIZ], ckt, + THERMNOISE, here->BSIM4dNodePrime, + here->BSIM4sNodePrime, (T2 - igsquare) * mult_i); + } + else + { + T0 = here->BSIM4gm + here->BSIM4gmbs + here->BSIM4gds; + T0 *= T0; + igsquare = npart_theta * npart_theta * T0 / here->BSIM4IdovVds; + T1 = npart_beta * (here->BSIM4gm + + here->BSIM4gmbs) + here->BSIM4gds; + T2 = T1 * T1 / here->BSIM4IdovVds; + NevalSrc(&noizDens[BSIM4IDNOIZ], + &lnNdens[BSIM4IDNOIZ], ckt, + THERMNOISE, here->BSIM4dNodePrime, + here->BSIM4sNodePrime, (T2 - igsquare) * mult_i); - noizDens[BSIM4CORLNOIZ] = 0.0; - lnNdens[BSIM4CORLNOIZ] = log(MAX(noizDens[BSIM4CORLNOIZ], N_MINLOG)); - } + noizDens[BSIM4CORLNOIZ] = 0.0; + lnNdens[BSIM4CORLNOIZ] = log(MAX(noizDens[BSIM4CORLNOIZ], N_MINLOG)); + } break; case 2: - T2 = GammaGd0; + T2 = GammaGd0; T3 = ctnoi * ctnoi; T4 = 1.0 - T3; NevalSrc(&noizDens[BSIM4IDNOIZ], &lnNdens[BSIM4IDNOIZ], ckt, THERMNOISE, here->BSIM4dNodePrime, - here->BSIM4sNodePrime, T2 * T4 * m); + here->BSIM4sNodePrime, T2 * T4 * mult_i); - /* Evaluate output noise due to two correlated noise sources */ - omega = 2.0 * M_PI * data->freq; - T5 = omega * sigrat; - T6 = T5 * T5; - T7 = T6 / (1.0 + T6); + /* Evaluate output noise due to two correlated noise sources */ + omega = 2.0 * M_PI * data->freq; + T5 = omega * sigrat; + T6 = T5 * T5; + T7 = T6 / (1.0 + T6); if (here->BSIM4mode >= 0) { NevalSrc2(&noizDens[BSIM4CORLNOIZ], &lnNdens[BSIM4CORLNOIZ], ckt, THERMNOISE, here->BSIM4dNodePrime, - here->BSIM4sNodePrime, T2 * T3 * m, - here->BSIM4gNodePrime, - here->BSIM4sNodePrime, - T2 * T7 * m, 0.5 * M_PI); - } - else - { + here->BSIM4sNodePrime, T2 * T3 * mult_i, + here->BSIM4gNodePrime, + here->BSIM4sNodePrime, + T2 * T7 * mult_i, 0.5 * M_PI); + } + else + { NevalSrc2(&noizDens[BSIM4CORLNOIZ], &lnNdens[BSIM4CORLNOIZ], ckt, THERMNOISE, here->BSIM4sNodePrime, - here->BSIM4dNodePrime, T2 * T3 * m, - here->BSIM4gNodePrime, - here->BSIM4dNodePrime, - T2 * T7 * m, 0.5 * M_PI); - } + here->BSIM4dNodePrime, T2 * T3 * mult_i, + here->BSIM4gNodePrime, + here->BSIM4dNodePrime, + T2 * T7 * mult_i, 0.5 * M_PI); + } break; - } + } - NevalSrc(&noizDens[BSIM4FLNOIZ], (double*) NULL, - ckt, N_GAIN, here->BSIM4dNodePrime, - here->BSIM4sNodePrime, (double) 0.0); + NevalSrc(&noizDens[BSIM4FLNOIZ], (double*) NULL, + ckt, N_GAIN, here->BSIM4dNodePrime, + here->BSIM4sNodePrime, (double) 0.0); switch(model->BSIM4fnoiMod) - { case 0: - noizDens[BSIM4FLNOIZ] *= m * model->BSIM4kf - * exp(model->BSIM4af - * log(MAX(fabs(here->BSIM4cd), - N_MINLOG))) - / (pow(data->freq, model->BSIM4ef) - * pParam->BSIM4leff - * pParam->BSIM4leff - * model->BSIM4coxe); - break; - case 1: - Vds = *(ckt->CKTstates[0] + here->BSIM4vds); - if (Vds < 0.0) - Vds = -Vds; + { case 0: + noizDens[BSIM4FLNOIZ] *= mult_fn * model->BSIM4kf + * exp(model->BSIM4af + * log(MAX(fabs(here->BSIM4cd), + N_MINLOG))) + / (pow(data->freq, model->BSIM4ef) + * pParam->BSIM4leff + * pParam->BSIM4leff + * model->BSIM4coxe); + break; + case 1: + Vds = *(ckt->CKTstates[0] + here->BSIM4vds); + if (Vds < 0.0) + Vds = -Vds; Ssi = Eval1ovFNoise(Vds, model, here, data->freq, ckt->CKTtemp); @@ -549,140 +544,141 @@ double m; * CONSTboltz * ckt->CKTtemp; T11 = pParam->BSIM4weff * here->BSIM4nf * pParam->BSIM4leff * pow(data->freq, model->BSIM4ef) * 1.0e10 - * here->BSIM4nstar * here->BSIM4nstar; + * here->BSIM4nstar * here->BSIM4nstar; Swi = T10 / T11 * here->BSIM4cd * here->BSIM4cd; T1 = Swi + Ssi; if (T1 > 0.0) - noizDens[BSIM4FLNOIZ] *= m * (Ssi * Swi) / T1; + noizDens[BSIM4FLNOIZ] *= mult_fn * (Ssi * Swi) / T1; else noizDens[BSIM4FLNOIZ] *= 0.0; - break; - } + break; + } - lnNdens[BSIM4FLNOIZ] = - log(MAX(noizDens[BSIM4FLNOIZ], N_MINLOG)); + lnNdens[BSIM4FLNOIZ] = + log(MAX(noizDens[BSIM4FLNOIZ], N_MINLOG)); if(here->BSIM4mode >= 0) { /* bugfix */ NevalSrc(&noizDens[BSIM4IGSNOIZ], &lnNdens[BSIM4IGSNOIZ], ckt, SHOTNOISE, here->BSIM4gNodePrime, here->BSIM4sNodePrime, - m * (here->BSIM4Igs + here->BSIM4Igcs)); + mult_i * (here->BSIM4Igs + here->BSIM4Igcs)); NevalSrc(&noizDens[BSIM4IGDNOIZ], &lnNdens[BSIM4IGDNOIZ], ckt, SHOTNOISE, here->BSIM4gNodePrime, here->BSIM4dNodePrime, - m * (here->BSIM4Igd + here->BSIM4Igcd)); - } else { + mult_i * (here->BSIM4Igd + here->BSIM4Igcd)); + } else { NevalSrc(&noizDens[BSIM4IGSNOIZ], &lnNdens[BSIM4IGSNOIZ], ckt, SHOTNOISE, here->BSIM4gNodePrime, here->BSIM4sNodePrime, - m * (here->BSIM4Igs + here->BSIM4Igcd)); + mult_i * (here->BSIM4Igs + here->BSIM4Igcd)); NevalSrc(&noizDens[BSIM4IGDNOIZ], &lnNdens[BSIM4IGDNOIZ], ckt, SHOTNOISE, here->BSIM4gNodePrime, here->BSIM4dNodePrime, - m * (here->BSIM4Igd + here->BSIM4Igcs)); + mult_i * (here->BSIM4Igd + here->BSIM4Igcs)); } NevalSrc(&noizDens[BSIM4IGBNOIZ], &lnNdens[BSIM4IGBNOIZ], ckt, SHOTNOISE, here->BSIM4gNodePrime, here->BSIM4bNodePrime, - m * here->BSIM4Igb); + mult_i * here->BSIM4Igb); - noizDens[BSIM4TOTNOIZ] = noizDens[BSIM4RDNOIZ] - + noizDens[BSIM4RSNOIZ] + noizDens[BSIM4RGNOIZ] - + noizDens[BSIM4RBPSNOIZ] + noizDens[BSIM4RBPDNOIZ] - + noizDens[BSIM4RBPBNOIZ] - + noizDens[BSIM4RBSBNOIZ] + noizDens[BSIM4RBDBNOIZ] - + noizDens[BSIM4IDNOIZ] + noizDens[BSIM4FLNOIZ] + noizDens[BSIM4TOTNOIZ] = noizDens[BSIM4RDNOIZ] + + noizDens[BSIM4RSNOIZ] + noizDens[BSIM4RGNOIZ] + + noizDens[BSIM4RBPSNOIZ] + noizDens[BSIM4RBPDNOIZ] + + noizDens[BSIM4RBPBNOIZ] + + noizDens[BSIM4RBSBNOIZ] + noizDens[BSIM4RBDBNOIZ] + + noizDens[BSIM4IDNOIZ] + noizDens[BSIM4FLNOIZ] + noizDens[BSIM4IGSNOIZ] + noizDens[BSIM4IGDNOIZ] + noizDens[BSIM4IGBNOIZ] + noizDens[BSIM4CORLNOIZ]; - lnNdens[BSIM4TOTNOIZ] = - log(MAX(noizDens[BSIM4TOTNOIZ], N_MINLOG)); + lnNdens[BSIM4TOTNOIZ] = + log(MAX(noizDens[BSIM4TOTNOIZ], N_MINLOG)); - *OnDens += noizDens[BSIM4TOTNOIZ]; + *OnDens += noizDens[BSIM4TOTNOIZ]; - if (data->delFreq == 0.0) - { /* if we haven't done any previous - integration, we need to initialize our - "history" variables. - */ + if (data->delFreq == 0.0) + { /* if we haven't done any previous + integration, we need to initialize our + "history" variables. + */ - for (i = 0; i < BSIM4NSRCS; i++) - { here->BSIM4nVar[LNLSTDENS][i] = - lnNdens[i]; - } + for (i = 0; i < BSIM4NSRCS; i++) + { here->BSIM4nVar[LNLSTDENS][i] = + lnNdens[i]; + } - /* clear out our integration variables - if it's the first pass - */ - if (data->freq == - job->NstartFreq) - { for (i = 0; i < BSIM4NSRCS; i++) - { here->BSIM4nVar[OUTNOIZ][i] = 0.0; - here->BSIM4nVar[INNOIZ][i] = 0.0; - } - } - } - else - { /* data->delFreq != 0.0, - we have to integrate. - */ - for (i = 0; i < BSIM4NSRCS; i++) - { if (i != BSIM4TOTNOIZ) - { tempOnoise = Nintegrate(noizDens[i], - lnNdens[i], - here->BSIM4nVar[LNLSTDENS][i], - data); - tempInoise = Nintegrate(noizDens[i] - * data->GainSqInv, lnNdens[i] - + data->lnGainInv, - here->BSIM4nVar[LNLSTDENS][i] - + data->lnGainInv, data); - here->BSIM4nVar[LNLSTDENS][i] = - lnNdens[i]; - data->outNoiz += tempOnoise; - data->inNoise += tempInoise; - if (job->NStpsSm != 0) - { here->BSIM4nVar[OUTNOIZ][i] - += tempOnoise; - here->BSIM4nVar[OUTNOIZ][BSIM4TOTNOIZ] - += tempOnoise; - here->BSIM4nVar[INNOIZ][i] - += tempInoise; - here->BSIM4nVar[INNOIZ][BSIM4TOTNOIZ] - += tempInoise; + /* clear out our integration variables + if it's the first pass + */ + if (data->freq == + ((NOISEAN*) ckt->CKTcurJob)->NstartFreq) + { for (i = 0; i < BSIM4NSRCS; i++) + { here->BSIM4nVar[OUTNOIZ][i] = 0.0; + here->BSIM4nVar[INNOIZ][i] = 0.0; + } + } + } + else + { /* data->delFreq != 0.0, + we have to integrate. + */ + for (i = 0; i < BSIM4NSRCS; i++) + { if (i != BSIM4TOTNOIZ) + { tempOnoise = Nintegrate(noizDens[i], + lnNdens[i], + here->BSIM4nVar[LNLSTDENS][i], + data); + tempInoise = Nintegrate(noizDens[i] + * data->GainSqInv, lnNdens[i] + + data->lnGainInv, + here->BSIM4nVar[LNLSTDENS][i] + + data->lnGainInv, data); + here->BSIM4nVar[LNLSTDENS][i] = + lnNdens[i]; + data->outNoiz += tempOnoise; + data->inNoise += tempInoise; + if (((NOISEAN*) + ckt->CKTcurJob)->NStpsSm != 0) + { here->BSIM4nVar[OUTNOIZ][i] + += tempOnoise; + here->BSIM4nVar[OUTNOIZ][BSIM4TOTNOIZ] + += tempOnoise; + here->BSIM4nVar[INNOIZ][i] + += tempInoise; + here->BSIM4nVar[INNOIZ][BSIM4TOTNOIZ] + += tempInoise; } - } - } - } - if (data->prtSummary) - { for (i = 0; i < BSIM4NSRCS; i++) - { /* print a summary report */ - data->outpVector[data->outNumber++] - = noizDens[i]; - } - } - break; - case INT_NOIZ: - /* already calculated, just output */ - if (job->NStpsSm != 0) - { for (i = 0; i < BSIM4NSRCS; i++) - { data->outpVector[data->outNumber++] - = here->BSIM4nVar[OUTNOIZ][i]; - data->outpVector[data->outNumber++] - = here->BSIM4nVar[INNOIZ][i]; - } - } - break; + } + } + } + if (data->prtSummary) + { for (i = 0; i < BSIM4NSRCS; i++) + { /* print a summary report */ + data->outpVector[data->outNumber++] + = noizDens[i]; + } } break; - case N_CLOSE: - /* do nothing, the main calling routine will close */ - return (OK); - break; /* the plots */ - } /* switch (operation) */ - } /* for here */ + case INT_NOIZ: + /* already calculated, just output */ + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) + { for (i = 0; i < BSIM4NSRCS; i++) + { data->outpVector[data->outNumber++] + = here->BSIM4nVar[OUTNOIZ][i]; + data->outpVector[data->outNumber++] + = here->BSIM4nVar[INNOIZ][i]; + } + } + break; + } + break; + case N_CLOSE: + /* do nothing, the main calling routine will close */ + return (OK); + break; /* the plots */ + } /* switch (operation) */ + } /* for here */ } /* for model */ return(OK); diff --git a/src/spicelib/devices/bsim4/b4par.c b/src/spicelib/devices/bsim4/b4par.c index 8ceb9eac4..1ecd4af88 100644 --- a/src/spicelib/devices/bsim4/b4par.c +++ b/src/spicelib/devices/bsim4/b4par.c @@ -1,29 +1,25 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* Licensed under Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the license at http://opensource.org/licenses/ECL-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc */ #include "ngspice/ngspice.h" @@ -49,9 +45,9 @@ IFvalue *select) if (!cp_getvar("scale", CP_REAL, &scale, 0)) scale = 1; - switch (param) { - case BSIM4_W: - here->BSIM4w = value->rValue * scale; + switch(param) + { case BSIM4_W: + here->BSIM4w = value->rValue * scale; here->BSIM4wGiven = TRUE; break; case BSIM4_L: @@ -62,6 +58,18 @@ IFvalue *select) here->BSIM4m = value->rValue; here->BSIM4mGiven = TRUE; break; + case BSIM4_MULT_I: + here->BSIM4mult_i = value->rValue; + here->BSIM4mult_iGiven = TRUE; + break; + case BSIM4_MULT_Q: + here->BSIM4mult_q = value->rValue; + here->BSIM4mult_qGiven = TRUE; + break; + case BSIM4_MULT_FN: + here->BSIM4mult_fn = value->rValue; + here->BSIM4mult_fnGiven = TRUE; + break; case BSIM4_NF: here->BSIM4nf = value->rValue; here->BSIM4nfGiven = TRUE; @@ -149,14 +157,6 @@ 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; @@ -204,8 +204,8 @@ IFvalue *select) case BSIM4_IC: /* FALLTHROUGH added to suppress GCC warning due to * -Wimplicit-fallthrough flag */ - switch (value->v.numValue) { - case 3: + switch(value->v.numValue) + { case 3: here->BSIM4icVBS = *(value->v.vec.rVec+2); here->BSIM4icVBSGiven = TRUE; /* FALLTHROUGH */ diff --git a/src/spicelib/devices/bsim4/b4pzld.c b/src/spicelib/devices/bsim4/b4pzld.c index bc608c950..970f78889 100644 --- a/src/spicelib/devices/bsim4/b4pzld.c +++ b/src/spicelib/devices/bsim4/b4pzld.c @@ -1,31 +1,26 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* Licensed under Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the license at http://opensource.org/licenses/ECL-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -*/ +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc +*/ #include "ngspice/ngspice.h" #include "ngspice/cktdefs.h" #include "ngspice/complex.h" @@ -64,14 +59,12 @@ double T0=0.0, T1, CoxWL, qcheq, Cdg, Cdd, Cds, Csg, Csd, Css; double ScalingFactor = 1.0e-9; struct bsim4SizeDependParam *pParam; double ggidld, ggidlg, ggidlb, ggislg, ggislb, ggisls; - -double m; +double m, mult_i, mult_q; for (; model != NULL; model = BSIM4nextModel(model)) { for (here = BSIM4instances(model); here!= NULL; here = BSIM4nextInstance(here)) - { - pParam = here->pParam; + { pParam = here->pParam; capbd = here->BSIM4capbd; capbs = here->BSIM4capbs; cgso = here->BSIM4cgso; @@ -224,7 +217,7 @@ double m; xcdgb = xcddb = xcdsb = xcdbb = 0.0; xcsgb = xcsdb = xcssb = xcsbb = 0.0; - xgtg = here->BSIM4gtg; + xgtg = here->BSIM4gtg; xgtd = here->BSIM4gtd; xgts = here->BSIM4gts; xgtb = here->BSIM4gtb; @@ -234,46 +227,46 @@ double m; xcqsb = here->BSIM4cqsb; xcqbb = here->BSIM4cqbb; - CoxWL = model->BSIM4coxe * here->pParam->BSIM4weffCV + CoxWL = model->BSIM4coxe * here->pParam->BSIM4weffCV * here->BSIM4nf * here->pParam->BSIM4leffCV; - qcheq = -(here->BSIM4qgate + here->BSIM4qbulk); - if (fabs(qcheq) <= 1.0e-5 * CoxWL) - { if (model->BSIM4xpart < 0.5) - { dxpart = 0.4; - } - else if (model->BSIM4xpart > 0.5) - { dxpart = 0.0; - } - else - { dxpart = 0.5; - } - ddxpart_dVd = ddxpart_dVg = ddxpart_dVb - = ddxpart_dVs = 0.0; - } - else - { dxpart = here->BSIM4qdrn / qcheq; - Cdd = here->BSIM4cddb; - Csd = -(here->BSIM4cgdb + here->BSIM4cddb - + here->BSIM4cbdb); - ddxpart_dVd = (Cdd - dxpart * (Cdd + Csd)) / qcheq; - Cdg = here->BSIM4cdgb; - Csg = -(here->BSIM4cggb + here->BSIM4cdgb - + here->BSIM4cbgb); - ddxpart_dVg = (Cdg - dxpart * (Cdg + Csg)) / qcheq; + qcheq = -(here->BSIM4qgate + here->BSIM4qbulk); + if (fabs(qcheq) <= 1.0e-5 * CoxWL) + { if (model->BSIM4xpart < 0.5) + { dxpart = 0.4; + } + else if (model->BSIM4xpart > 0.5) + { dxpart = 0.0; + } + else + { dxpart = 0.5; + } + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb + = ddxpart_dVs = 0.0; + } + else + { dxpart = here->BSIM4qdrn / qcheq; + Cdd = here->BSIM4cddb; + Csd = -(here->BSIM4cgdb + here->BSIM4cddb + + here->BSIM4cbdb); + ddxpart_dVd = (Cdd - dxpart * (Cdd + Csd)) / qcheq; + Cdg = here->BSIM4cdgb; + Csg = -(here->BSIM4cggb + here->BSIM4cdgb + + here->BSIM4cbgb); + ddxpart_dVg = (Cdg - dxpart * (Cdg + Csg)) / qcheq; - Cds = here->BSIM4cdsb; - Css = -(here->BSIM4cgsb + here->BSIM4cdsb - + here->BSIM4cbsb); - ddxpart_dVs = (Cds - dxpart * (Cds + Css)) / qcheq; + Cds = here->BSIM4cdsb; + Css = -(here->BSIM4cgsb + here->BSIM4cdsb + + here->BSIM4cbsb); + ddxpart_dVs = (Cds - dxpart * (Cds + Css)) / qcheq; - ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg - + ddxpart_dVs); - } - sxpart = 1.0 - dxpart; - dsxpart_dVd = -ddxpart_dVd; - dsxpart_dVg = -ddxpart_dVg; - dsxpart_dVs = -ddxpart_dVs; - dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg + dsxpart_dVs); + ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg + + ddxpart_dVs); + } + sxpart = 1.0 - dxpart; + dsxpart_dVd = -ddxpart_dVd; + dsxpart_dVg = -ddxpart_dVg; + dsxpart_dVs = -ddxpart_dVs; + dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg + dsxpart_dVs); } } else @@ -432,47 +425,47 @@ double m; xcqsb = here->BSIM4cqdb; xcqbb = here->BSIM4cqbb; - CoxWL = model->BSIM4coxe * here->pParam->BSIM4weffCV + CoxWL = model->BSIM4coxe * here->pParam->BSIM4weffCV * here->BSIM4nf * here->pParam->BSIM4leffCV; - qcheq = -(here->BSIM4qgate + here->BSIM4qbulk); - if (fabs(qcheq) <= 1.0e-5 * CoxWL) - { if (model->BSIM4xpart < 0.5) - { sxpart = 0.4; - } - else if (model->BSIM4xpart > 0.5) - { sxpart = 0.0; - } - else - { sxpart = 0.5; - } - dsxpart_dVd = dsxpart_dVg = dsxpart_dVb - = dsxpart_dVs = 0.0; - } - else - { sxpart = here->BSIM4qdrn / qcheq; - Css = here->BSIM4cddb; - Cds = -(here->BSIM4cgdb + here->BSIM4cddb - + here->BSIM4cbdb); - dsxpart_dVs = (Css - sxpart * (Css + Cds)) / qcheq; - Csg = here->BSIM4cdgb; - Cdg = -(here->BSIM4cggb + here->BSIM4cdgb - + here->BSIM4cbgb); - dsxpart_dVg = (Csg - sxpart * (Csg + Cdg)) / qcheq; - - Csd = here->BSIM4cdsb; - Cdd = -(here->BSIM4cgsb + here->BSIM4cdsb - + here->BSIM4cbsb); - dsxpart_dVd = (Csd - sxpart * (Csd + Cdd)) / qcheq; - - dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg - + dsxpart_dVs); - } - dxpart = 1.0 - sxpart; - ddxpart_dVd = -dsxpart_dVd; - ddxpart_dVg = -dsxpart_dVg; - ddxpart_dVs = -dsxpart_dVs; - ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg + ddxpart_dVs); + qcheq = -(here->BSIM4qgate + here->BSIM4qbulk); + if (fabs(qcheq) <= 1.0e-5 * CoxWL) + { if (model->BSIM4xpart < 0.5) + { sxpart = 0.4; } + else if (model->BSIM4xpart > 0.5) + { sxpart = 0.0; + } + else + { sxpart = 0.5; + } + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb + = dsxpart_dVs = 0.0; + } + else + { sxpart = here->BSIM4qdrn / qcheq; + Css = here->BSIM4cddb; + Cds = -(here->BSIM4cgdb + here->BSIM4cddb + + here->BSIM4cbdb); + dsxpart_dVs = (Css - sxpart * (Css + Cds)) / qcheq; + Csg = here->BSIM4cdgb; + Cdg = -(here->BSIM4cggb + here->BSIM4cdgb + + here->BSIM4cbgb); + dsxpart_dVg = (Csg - sxpart * (Csg + Cdg)) / qcheq; + + Csd = here->BSIM4cdsb; + Cdd = -(here->BSIM4cgsb + here->BSIM4cdsb + + here->BSIM4cbsb); + dsxpart_dVd = (Csd - sxpart * (Csd + Cdd)) / qcheq; + + dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg + + dsxpart_dVs); + } + dxpart = 1.0 - sxpart; + ddxpart_dVd = -dsxpart_dVd; + ddxpart_dVg = -dsxpart_dVg; + ddxpart_dVs = -dsxpart_dVs; + ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg + ddxpart_dVs); + } } if (model->BSIM4rdsMod == 1) @@ -501,6 +494,8 @@ double m; * Loading PZ matrix */ m = here->BSIM4m; + mult_i = here->BSIM4mult_i; + mult_q = here->BSIM4mult_q; if (!model->BSIM4rdsMod) { gdpr = here->BSIM4drainConductance; @@ -519,165 +514,165 @@ double m; geltd = here->BSIM4grgeltd; if (here->BSIM4rgateMod == 1) - { *(here->BSIM4GEgePtr) += m * geltd; - *(here->BSIM4GPgePtr) -= m * geltd; - *(here->BSIM4GEgpPtr) -= m * geltd; + { *(here->BSIM4GEgePtr) += mult_i * geltd; + *(here->BSIM4GPgePtr) -= mult_i * geltd; + *(here->BSIM4GEgpPtr) -= mult_i * geltd; - *(here->BSIM4GPgpPtr ) += m * xcggb * s->real; - *(here->BSIM4GPgpPtr +1) += m * xcggb * s->imag; - *(here->BSIM4GPgpPtr) += m * (geltd - xgtg + gIgtotg); - *(here->BSIM4GPdpPtr ) += m * xcgdb * s->real; - *(here->BSIM4GPdpPtr +1) += m * xcgdb * s->imag; - *(here->BSIM4GPdpPtr) -= m * (xgtd - gIgtotd); - *(here->BSIM4GPspPtr ) += m * xcgsb * s->real; - *(here->BSIM4GPspPtr +1) += m * xcgsb * s->imag; - *(here->BSIM4GPspPtr) -= m * (xgts - gIgtots); - *(here->BSIM4GPbpPtr ) += m * xcgbb * s->real; - *(here->BSIM4GPbpPtr +1) += m * xcgbb * s->imag; - *(here->BSIM4GPbpPtr) -= m * (xgtb - gIgtotb); + *(here->BSIM4GPgpPtr ) += mult_q * xcggb * s->real; + *(here->BSIM4GPgpPtr +1) += mult_q * xcggb * s->imag; + *(here->BSIM4GPgpPtr) += mult_i * (geltd + gIgtotg) - mult_q * xgtg; + *(here->BSIM4GPdpPtr ) += mult_q * xcgdb * s->real; + *(here->BSIM4GPdpPtr +1) += mult_q * xcgdb * s->imag; + *(here->BSIM4GPdpPtr) -= mult_q * xgtd - mult_i * gIgtotd; + *(here->BSIM4GPspPtr ) += mult_q * xcgsb * s->real; + *(here->BSIM4GPspPtr +1) += mult_q * xcgsb * s->imag; + *(here->BSIM4GPspPtr) -= mult_q * xgts - mult_i * gIgtots; + *(here->BSIM4GPbpPtr ) += mult_q * xcgbb * s->real; + *(here->BSIM4GPbpPtr +1) += mult_q * xcgbb * s->imag; + *(here->BSIM4GPbpPtr) -= mult_q * xgtb - mult_i * gIgtotb; } else if (here->BSIM4rgateMod == 2) - { *(here->BSIM4GEgePtr) += m * gcrg; - *(here->BSIM4GEgpPtr) += m * gcrgg; - *(here->BSIM4GEdpPtr) += m * gcrgd; - *(here->BSIM4GEspPtr) += m * gcrgs; - *(here->BSIM4GEbpPtr) += m * gcrgb; + { *(here->BSIM4GEgePtr) += mult_i * gcrg; + *(here->BSIM4GEgpPtr) += mult_i * gcrgg; + *(here->BSIM4GEdpPtr) += mult_i * gcrgd; + *(here->BSIM4GEspPtr) += mult_i * gcrgs; + *(here->BSIM4GEbpPtr) += mult_i * gcrgb; - *(here->BSIM4GPgePtr) -= m * gcrg; - *(here->BSIM4GPgpPtr ) += m * xcggb * s->real; - *(here->BSIM4GPgpPtr +1) += m * xcggb * s->imag; - *(here->BSIM4GPgpPtr) -= m * (gcrgg + xgtg - gIgtotg); - *(here->BSIM4GPdpPtr ) += m * xcgdb * s->real; - *(here->BSIM4GPdpPtr +1) += m * xcgdb * s->imag; - *(here->BSIM4GPdpPtr) -= m * (gcrgd + xgtd - gIgtotd); - *(here->BSIM4GPspPtr ) += m * xcgsb * s->real; - *(here->BSIM4GPspPtr +1) += m * xcgsb * s->imag; - *(here->BSIM4GPspPtr) -= m * (gcrgs + xgts - gIgtots); - *(here->BSIM4GPbpPtr ) += m * xcgbb * s->real; - *(here->BSIM4GPbpPtr +1) += m * xcgbb * s->imag; - *(here->BSIM4GPbpPtr) -= m * (gcrgb + xgtb - gIgtotb); + *(here->BSIM4GPgePtr) -= mult_i * gcrg; + *(here->BSIM4GPgpPtr ) += mult_q * xcggb * s->real; + *(here->BSIM4GPgpPtr +1) += mult_q * xcggb * s->imag; + *(here->BSIM4GPgpPtr) -= mult_i * (gcrgg - gIgtotg) + mult_q * xgtg; + *(here->BSIM4GPdpPtr ) += mult_q * xcgdb * s->real; + *(here->BSIM4GPdpPtr +1) += mult_q * xcgdb * s->imag; + *(here->BSIM4GPdpPtr) -= mult_i * (gcrgd - gIgtotd) + mult_q * xgtd; + *(here->BSIM4GPspPtr ) += mult_q * xcgsb * s->real; + *(here->BSIM4GPspPtr +1) += mult_q * xcgsb * s->imag; + *(here->BSIM4GPspPtr) -= mult_i * (gcrgs - gIgtots) + mult_q * xgts; + *(here->BSIM4GPbpPtr ) += mult_q * xcgbb * s->real; + *(here->BSIM4GPbpPtr +1) += mult_q * xcgbb * s->imag; + *(here->BSIM4GPbpPtr) -= mult_i * (gcrgb - gIgtotb) + mult_q * xgtb; } else if (here->BSIM4rgateMod == 3) - { *(here->BSIM4GEgePtr) += m * geltd; - *(here->BSIM4GEgmPtr) -= m * geltd; - *(here->BSIM4GMgePtr) -= m * geltd; - *(here->BSIM4GMgmPtr) += m * (geltd + gcrg); - *(here->BSIM4GMgmPtr ) += m * xcgmgmb * s->real; - *(here->BSIM4GMgmPtr +1) += m * xcgmgmb * s->imag; - - *(here->BSIM4GMdpPtr) += m * gcrgd; - *(here->BSIM4GMdpPtr ) += m * xcgmdb * s->real; - *(here->BSIM4GMdpPtr +1) += m * xcgmdb * s->imag; - *(here->BSIM4GMgpPtr) += m * gcrgg; - *(here->BSIM4GMspPtr) += m * gcrgs; - *(here->BSIM4GMspPtr ) += m * xcgmsb * s->real; - *(here->BSIM4GMspPtr +1) += m * xcgmsb * s->imag; - *(here->BSIM4GMbpPtr) += m * gcrgb; - *(here->BSIM4GMbpPtr ) += m * xcgmbb * s->real; - *(here->BSIM4GMbpPtr +1) += m * xcgmbb * s->imag; - - *(here->BSIM4DPgmPtr ) += m * xcdgmb * s->real; - *(here->BSIM4DPgmPtr +1) += m * xcdgmb * s->imag; - *(here->BSIM4GPgmPtr) -= m * gcrg; - *(here->BSIM4SPgmPtr ) += m * xcsgmb * s->real; - *(here->BSIM4SPgmPtr +1) += m * xcsgmb * s->imag; - *(here->BSIM4BPgmPtr ) += m * xcbgmb * s->real; - *(here->BSIM4BPgmPtr +1) += m * xcbgmb * s->imag; - - *(here->BSIM4GPgpPtr) -= m * (gcrgg + xgtg - gIgtotg); - *(here->BSIM4GPgpPtr ) += m * xcggb * s->real; - *(here->BSIM4GPgpPtr +1) += m * xcggb * s->imag; - *(here->BSIM4GPdpPtr) -= m * (gcrgd + xgtd - gIgtotd); - *(here->BSIM4GPdpPtr ) += m * xcgdb * s->real; - *(here->BSIM4GPdpPtr +1) += m * xcgdb * s->imag; - *(here->BSIM4GPspPtr) -= m * (gcrgs + xgts - gIgtots); - *(here->BSIM4GPspPtr ) += m * xcgsb * s->real; - *(here->BSIM4GPspPtr +1) += m * xcgsb * s->imag; - *(here->BSIM4GPbpPtr) -= m * (gcrgb + xgtb - gIgtotb); - *(here->BSIM4GPbpPtr ) += m * xcgbb * s->real; - *(here->BSIM4GPbpPtr +1) += m * xcgbb * s->imag; + { *(here->BSIM4GEgePtr) += mult_i * geltd; + *(here->BSIM4GEgmPtr) -= mult_i * geltd; + *(here->BSIM4GMgePtr) -= mult_i * geltd; + *(here->BSIM4GMgmPtr) += mult_i * (geltd + gcrg); + *(here->BSIM4GMgmPtr ) += mult_q * xcgmgmb * s->real; + *(here->BSIM4GMgmPtr +1) += mult_q * xcgmgmb * s->imag; + + *(here->BSIM4GMdpPtr) += mult_i * gcrgd; + *(here->BSIM4GMdpPtr ) += mult_q * xcgmdb * s->real; + *(here->BSIM4GMdpPtr +1) += mult_q * xcgmdb * s->imag; + *(here->BSIM4GMgpPtr) += mult_i * gcrgg; + *(here->BSIM4GMspPtr) += mult_i * gcrgs; + *(here->BSIM4GMspPtr ) += mult_q * xcgmsb * s->real; + *(here->BSIM4GMspPtr +1) += mult_q * xcgmsb * s->imag; + *(here->BSIM4GMbpPtr) += mult_i * gcrgb; + *(here->BSIM4GMbpPtr ) += mult_q * xcgmbb * s->real; + *(here->BSIM4GMbpPtr +1) += mult_q * xcgmbb * s->imag; + + *(here->BSIM4DPgmPtr ) += mult_q * xcdgmb * s->real; + *(here->BSIM4DPgmPtr +1) += mult_q * xcdgmb * s->imag; + *(here->BSIM4GPgmPtr) -= mult_i * gcrg; + *(here->BSIM4SPgmPtr ) += mult_q * xcsgmb * s->real; + *(here->BSIM4SPgmPtr +1) += mult_q * xcsgmb * s->imag; + *(here->BSIM4BPgmPtr ) += mult_q * xcbgmb * s->real; + *(here->BSIM4BPgmPtr +1) += mult_q * xcbgmb * s->imag; + + *(here->BSIM4GPgpPtr) -= mult_i * (gcrgg - gIgtotg) + mult_q * xgtg; + *(here->BSIM4GPgpPtr ) += mult_q * xcggb * s->real; + *(here->BSIM4GPgpPtr +1) += mult_q * xcggb * s->imag; + *(here->BSIM4GPdpPtr) -= mult_i * (gcrgd - gIgtotd) + mult_q * xgtd; + *(here->BSIM4GPdpPtr ) += mult_q * xcgdb * s->real; + *(here->BSIM4GPdpPtr +1) += mult_q * xcgdb * s->imag; + *(here->BSIM4GPspPtr) -= mult_i * (gcrgs - gIgtots) + mult_q * xgts; + *(here->BSIM4GPspPtr ) += mult_q * xcgsb * s->real; + *(here->BSIM4GPspPtr +1) += mult_q * xcgsb * s->imag; + *(here->BSIM4GPbpPtr) -= mult_i * (gcrgb - gIgtotb) + mult_q * xgtb; + *(here->BSIM4GPbpPtr ) += mult_q * xcgbb * s->real; + *(here->BSIM4GPbpPtr +1) += mult_q * xcgbb * s->imag; } else - { *(here->BSIM4GPdpPtr ) += m * xcgdb * s->real; - *(here->BSIM4GPdpPtr +1) += m * xcgdb * s->imag; - *(here->BSIM4GPdpPtr) -= m * (xgtd - gIgtotd); - *(here->BSIM4GPgpPtr ) += m * xcggb * s->real; - *(here->BSIM4GPgpPtr +1) += m * xcggb * s->imag; - *(here->BSIM4GPgpPtr) -= m * (xgtg - gIgtotg); - *(here->BSIM4GPspPtr ) += m * xcgsb * s->real; - *(here->BSIM4GPspPtr +1) += m * xcgsb * s->imag; - *(here->BSIM4GPspPtr) -= m * (xgts - gIgtots); - *(here->BSIM4GPbpPtr ) += m * xcgbb * s->real; - *(here->BSIM4GPbpPtr +1) += m * xcgbb * s->imag; - *(here->BSIM4GPbpPtr) -= m * (xgtb - gIgtotb); + { *(here->BSIM4GPdpPtr ) += mult_q * xcgdb * s->real; + *(here->BSIM4GPdpPtr +1) += mult_q * xcgdb * s->imag; + *(here->BSIM4GPdpPtr) -= mult_q * xgtd - mult_i * gIgtotd; + *(here->BSIM4GPgpPtr ) += mult_q * xcggb * s->real; + *(here->BSIM4GPgpPtr +1) += mult_q * xcggb * s->imag; + *(here->BSIM4GPgpPtr) -= mult_q * xgtg - mult_i * gIgtotg; + *(here->BSIM4GPspPtr ) += mult_q * xcgsb * s->real; + *(here->BSIM4GPspPtr +1) += mult_q * xcgsb * s->imag; + *(here->BSIM4GPspPtr) -= mult_q * xgts - mult_i * gIgtots; + *(here->BSIM4GPbpPtr ) += mult_q * xcgbb * s->real; + *(here->BSIM4GPbpPtr +1) += mult_q * xcgbb * s->imag; + *(here->BSIM4GPbpPtr) -= mult_q * xgtb - mult_i * gIgtotb; } if (model->BSIM4rdsMod) - { (*(here->BSIM4DgpPtr) += m * gdtotg); - (*(here->BSIM4DspPtr) += m * gdtots); - (*(here->BSIM4DbpPtr) += m * gdtotb); - (*(here->BSIM4SdpPtr) += m * gstotd); - (*(here->BSIM4SgpPtr) += m * gstotg); - (*(here->BSIM4SbpPtr) += m * gstotb); + { (*(here->BSIM4DgpPtr) += mult_i * gdtotg); + (*(here->BSIM4DspPtr) += mult_i * gdtots); + (*(here->BSIM4DbpPtr) += mult_i * gdtotb); + (*(here->BSIM4SdpPtr) += mult_i * gstotd); + (*(here->BSIM4SgpPtr) += mult_i * gstotg); + (*(here->BSIM4SbpPtr) += mult_i * gstotb); } - *(here->BSIM4DPdpPtr ) += m * xcddb * s->real; - *(here->BSIM4DPdpPtr +1) += m * xcddb * s->imag; - *(here->BSIM4DPdpPtr) += m * (gdpr + gds + here->BSIM4gbd - - gdtotd + RevSum + gbdpdp - gIdtotd - + dxpart * xgtd + T1 * ddxpart_dVd); - *(here->BSIM4DPdPtr) -= m * (gdpr + gdtot); - *(here->BSIM4DPgpPtr ) += m * xcdgb * s->real; - *(here->BSIM4DPgpPtr +1) += m * xcdgb * s->imag; - *(here->BSIM4DPgpPtr) += m * (Gm - gdtotg + gbdpg - gIdtotg - + T1 * ddxpart_dVg + dxpart * xgtg); - *(here->BSIM4DPspPtr ) += m * xcdsb * s->real; - *(here->BSIM4DPspPtr +1) += m * xcdsb * s->imag; - *(here->BSIM4DPspPtr) -= m * (gds + FwdSum + gdtots - gbdpsp + gIdtots - - T1 * ddxpart_dVs - dxpart * xgts); - *(here->BSIM4DPbpPtr ) += m * xcdbb * s->real; - *(here->BSIM4DPbpPtr +1) += m * xcdbb * s->imag; - *(here->BSIM4DPbpPtr) -= m * (gjbd + gdtotb - Gmbs - gbdpb + gIdtotb - - T1 * ddxpart_dVb - dxpart * xgtb); + *(here->BSIM4DPdpPtr ) += mult_q * xcddb * s->real; + *(here->BSIM4DPdpPtr +1) += mult_q * xcddb * s->imag; + *(here->BSIM4DPdpPtr) += mult_i * (gdpr + gds + here->BSIM4gbd + - gdtotd + RevSum + gbdpdp - gIdtotd) + + mult_q * (dxpart * xgtd + T1 * ddxpart_dVd); + *(here->BSIM4DPdPtr) -= mult_i * (gdpr + gdtot); + *(here->BSIM4DPgpPtr ) += mult_q * xcdgb * s->real; + *(here->BSIM4DPgpPtr +1) += mult_q * xcdgb * s->imag; + *(here->BSIM4DPgpPtr) += mult_i * (Gm - gdtotg + gbdpg - gIdtotg) + + mult_q * (T1 * ddxpart_dVg + dxpart * xgtg); + *(here->BSIM4DPspPtr ) += mult_q * xcdsb * s->real; + *(here->BSIM4DPspPtr +1) += mult_q * xcdsb * s->imag; + *(here->BSIM4DPspPtr) -= mult_i * (gds + FwdSum + gdtots - gbdpsp + gIdtots) + - mult_q * (T1 * ddxpart_dVs + dxpart * xgts); + *(here->BSIM4DPbpPtr ) += mult_q * xcdbb * s->real; + *(here->BSIM4DPbpPtr +1) += mult_q * xcdbb * s->imag; + *(here->BSIM4DPbpPtr) -= mult_i * (gjbd + gdtotb - Gmbs - gbdpb + gIdtotb) + - mult_q * T1 * (ddxpart_dVb + dxpart * xgtb); - *(here->BSIM4DdpPtr) -= m * (gdpr - gdtotd); - *(here->BSIM4DdPtr) += m * (gdpr + gdtot); + *(here->BSIM4DdpPtr) -= mult_i * (gdpr - gdtotd); + *(here->BSIM4DdPtr) += mult_i * (gdpr + gdtot); - *(here->BSIM4SPdpPtr ) += m * xcsdb * s->real; - *(here->BSIM4SPdpPtr +1) += m * xcsdb * s->imag; - *(here->BSIM4SPdpPtr) -= m * (gds + gstotd + RevSum - gbspdp + gIstotd - - T1 * dsxpart_dVd - sxpart * xgtd); - *(here->BSIM4SPgpPtr ) += m * xcsgb * s->real; - *(here->BSIM4SPgpPtr +1) += m * xcsgb * s->imag; - *(here->BSIM4SPgpPtr) -= m * (Gm + gstotg - gbspg + gIstotg - - T1 * dsxpart_dVg - sxpart * xgtg); - *(here->BSIM4SPspPtr ) += m * xcssb * s->real; - *(here->BSIM4SPspPtr +1) += m * xcssb * s->imag; - *(here->BSIM4SPspPtr) += m * (gspr + gds + here->BSIM4gbs - gIstots - - gstots + FwdSum + gbspsp - + sxpart * xgts + T1 * dsxpart_dVs); - *(here->BSIM4SPsPtr) -= m * (gspr + gstot); - *(here->BSIM4SPbpPtr ) += m * xcsbb * s->real; - *(here->BSIM4SPbpPtr +1) += m * xcsbb * s->imag; - *(here->BSIM4SPbpPtr) -= m * (gjbs + gstotb + Gmbs - gbspb + gIstotb - - T1 * dsxpart_dVb - sxpart * xgtb); + *(here->BSIM4SPdpPtr ) += mult_q * xcsdb * s->real; + *(here->BSIM4SPdpPtr +1) += mult_q * xcsdb * s->imag; + *(here->BSIM4SPdpPtr) -= mult_i * (gds + gstotd + RevSum - gbspdp + gIstotd) + - mult_q * (T1 * dsxpart_dVd + sxpart * xgtd); + *(here->BSIM4SPgpPtr ) += mult_q * xcsgb * s->real; + *(here->BSIM4SPgpPtr +1) += mult_q * xcsgb * s->imag; + *(here->BSIM4SPgpPtr) -= mult_i * (Gm + gstotg - gbspg + gIstotg) + - mult_q * (T1 * dsxpart_dVg + sxpart * xgtg); + *(here->BSIM4SPspPtr ) += mult_q * xcssb * s->real; + *(here->BSIM4SPspPtr +1) += mult_q * xcssb * s->imag; + *(here->BSIM4SPspPtr) += mult_i * (gspr + gds + here->BSIM4gbs - gIstots + - gstots + FwdSum + gbspsp) + + mult_q * (sxpart * xgts + T1 * dsxpart_dVs); + *(here->BSIM4SPsPtr) -= mult_i * (gspr + gstot); + *(here->BSIM4SPbpPtr ) += mult_q * xcsbb * s->real; + *(here->BSIM4SPbpPtr +1) += mult_q * xcsbb * s->imag; + *(here->BSIM4SPbpPtr) -= mult_i * (gjbs + gstotb + Gmbs - gbspb + gIstotb) + - mult_q * (T1 * dsxpart_dVb + sxpart * xgtb); - *(here->BSIM4SspPtr) -= m * (gspr - gstots); - *(here->BSIM4SsPtr) += m * (gspr + gstot); + *(here->BSIM4SspPtr) -= mult_i * (gspr - gstots); + *(here->BSIM4SsPtr) += mult_i * (gspr + gstot); - *(here->BSIM4BPdpPtr ) += m * xcbdb * s->real; - *(here->BSIM4BPdpPtr +1) += m * xcbdb * s->imag; - *(here->BSIM4BPdpPtr) -= m * (gjbd - gbbdp + gIbtotd); - *(here->BSIM4BPgpPtr ) += m * xcbgb * s->real; - *(here->BSIM4BPgpPtr +1) += m * xcbgb * s->imag; - *(here->BSIM4BPgpPtr) -= m * (here->BSIM4gbgs + gIbtotg); - *(here->BSIM4BPspPtr ) += m * xcbsb * s->real; - *(here->BSIM4BPspPtr +1) += m * xcbsb * s->imag; - *(here->BSIM4BPspPtr) -= m * (gjbs - gbbsp + gIbtots); - *(here->BSIM4BPbpPtr ) += m * xcbbb * s->real; - *(here->BSIM4BPbpPtr +1) += m * xcbbb * s->imag; - *(here->BSIM4BPbpPtr) += m * (gjbd + gjbs - here->BSIM4gbbs - - gIbtotb); + *(here->BSIM4BPdpPtr ) += mult_q * xcbdb * s->real; + *(here->BSIM4BPdpPtr +1) += mult_q * xcbdb * s->imag; + *(here->BSIM4BPdpPtr) -= mult_i * (gjbd - gbbdp + gIbtotd); + *(here->BSIM4BPgpPtr ) += mult_q * xcbgb * s->real; + *(here->BSIM4BPgpPtr +1) += mult_q * xcbgb * s->imag; + *(here->BSIM4BPgpPtr) -= mult_i * (here->BSIM4gbgs + gIbtotg); + *(here->BSIM4BPspPtr ) += mult_q * xcbsb * s->real; + *(here->BSIM4BPspPtr +1) += mult_q * xcbsb * s->imag; + *(here->BSIM4BPspPtr) -= mult_i * (gjbs - gbbsp + gIbtots); + *(here->BSIM4BPbpPtr ) += mult_q * xcbbb * s->real; + *(here->BSIM4BPbpPtr +1) += mult_q * xcbbb * s->imag; + *(here->BSIM4BPbpPtr) += mult_i * (gjbd + gjbs - here->BSIM4gbbs + - gIbtotb); ggidld = here->BSIM4ggidld; ggidlg = here->BSIM4ggidlg; ggidlb = here->BSIM4ggidlb; @@ -686,63 +681,63 @@ double m; ggislb = here->BSIM4ggislb; /* stamp gidl */ - (*(here->BSIM4DPdpPtr) += m * ggidld); - (*(here->BSIM4DPgpPtr) += m * ggidlg); - (*(here->BSIM4DPspPtr) -= m * ((ggidlg + ggidld) + ggidlb)); - (*(here->BSIM4DPbpPtr) += m * ggidlb); - (*(here->BSIM4BPdpPtr) -= m * ggidld); - (*(here->BSIM4BPgpPtr) -= m * ggidlg); - (*(here->BSIM4BPspPtr) += m * ((ggidlg + ggidld) + ggidlb)); - (*(here->BSIM4BPbpPtr) -= m * ggidlb); + (*(here->BSIM4DPdpPtr) += mult_i * ggidld); + (*(here->BSIM4DPgpPtr) += mult_i * ggidlg); + (*(here->BSIM4DPspPtr) -= mult_i * ((ggidlg + ggidld) + ggidlb)); + (*(here->BSIM4DPbpPtr) += mult_i * ggidlb); + (*(here->BSIM4BPdpPtr) -= mult_i * ggidld); + (*(here->BSIM4BPgpPtr) -= mult_i * ggidlg); + (*(here->BSIM4BPspPtr) += mult_i * ((ggidlg + ggidld) + ggidlb)); + (*(here->BSIM4BPbpPtr) -= mult_i * ggidlb); /* stamp gisl */ - (*(here->BSIM4SPdpPtr) -= m * ((ggisls + ggislg) + ggislb)); - (*(here->BSIM4SPgpPtr) += m * ggislg); - (*(here->BSIM4SPspPtr) += m * ggisls); - (*(here->BSIM4SPbpPtr) += m * ggislb); - (*(here->BSIM4BPdpPtr) += m * ((ggislg + ggisls) + ggislb)); - (*(here->BSIM4BPgpPtr) -= m * ggislg); - (*(here->BSIM4BPspPtr) -= m * ggisls); - (*(here->BSIM4BPbpPtr) -= m * ggislb); + (*(here->BSIM4SPdpPtr) -= mult_i * ((ggisls + ggislg) + ggislb)); + (*(here->BSIM4SPgpPtr) += mult_i * ggislg); + (*(here->BSIM4SPspPtr) += mult_i * ggisls); + (*(here->BSIM4SPbpPtr) += mult_i * ggislb); + (*(here->BSIM4BPdpPtr) += mult_i * ((ggislg + ggisls) + ggislb)); + (*(here->BSIM4BPgpPtr) -= mult_i * ggislg); + (*(here->BSIM4BPspPtr) -= mult_i * ggisls); + (*(here->BSIM4BPbpPtr) -= mult_i * ggislb); if (here->BSIM4rbodyMod) - { (*(here->BSIM4DPdbPtr ) += m * xcdbdb * s->real); - (*(here->BSIM4DPdbPtr +1) += m * xcdbdb * s->imag); - (*(here->BSIM4DPdbPtr) -= m * here->BSIM4gbd); - (*(here->BSIM4SPsbPtr ) += m * xcsbsb * s->real); - (*(here->BSIM4SPsbPtr +1) += m * xcsbsb * s->imag); - (*(here->BSIM4SPsbPtr) -= m * here->BSIM4gbs); + { (*(here->BSIM4DPdbPtr ) += mult_q * xcdbdb * s->real); + (*(here->BSIM4DPdbPtr +1) += mult_q * xcdbdb * s->imag); + (*(here->BSIM4DPdbPtr) -= mult_i * here->BSIM4gbd); + (*(here->BSIM4SPsbPtr ) += mult_q * xcsbsb * s->real); + (*(here->BSIM4SPsbPtr +1) += mult_q * xcsbsb * s->imag); + (*(here->BSIM4SPsbPtr) -= mult_i * here->BSIM4gbs); - (*(here->BSIM4DBdpPtr ) += m * xcdbdb * s->real); - (*(here->BSIM4DBdpPtr +1) += m * xcdbdb * s->imag); - (*(here->BSIM4DBdpPtr) -= m * here->BSIM4gbd); - (*(here->BSIM4DBdbPtr ) -= m * xcdbdb * s->real); - (*(here->BSIM4DBdbPtr +1) -= m * xcdbdb * s->imag); - (*(here->BSIM4DBdbPtr) += m * (here->BSIM4gbd + here->BSIM4grbpd + (*(here->BSIM4DBdpPtr ) += mult_q * xcdbdb * s->real); + (*(here->BSIM4DBdpPtr +1) += mult_q * xcdbdb * s->imag); + (*(here->BSIM4DBdpPtr) -= mult_i * here->BSIM4gbd); + (*(here->BSIM4DBdbPtr ) -= mult_q * xcdbdb * s->real); + (*(here->BSIM4DBdbPtr +1) -= mult_q * xcdbdb * s->imag); + (*(here->BSIM4DBdbPtr) += mult_i * (here->BSIM4gbd + here->BSIM4grbpd + here->BSIM4grbdb)); - (*(here->BSIM4DBbpPtr) -= m * here->BSIM4grbpd); - (*(here->BSIM4DBbPtr) -= m * here->BSIM4grbdb); + (*(here->BSIM4DBbpPtr) -= mult_i * here->BSIM4grbpd); + (*(here->BSIM4DBbPtr) -= mult_i * here->BSIM4grbdb); - (*(here->BSIM4BPdbPtr) -= m * here->BSIM4grbpd); - (*(here->BSIM4BPbPtr) -= m * here->BSIM4grbpb); - (*(here->BSIM4BPsbPtr) -= m * here->BSIM4grbps); - (*(here->BSIM4BPbpPtr) += m * (here->BSIM4grbpd + here->BSIM4grbps - + here->BSIM4grbpb)); + (*(here->BSIM4BPdbPtr) -= mult_i * here->BSIM4grbpd); + (*(here->BSIM4BPbPtr) -= mult_i * here->BSIM4grbpb); + (*(here->BSIM4BPsbPtr) -= mult_i * here->BSIM4grbps); + (*(here->BSIM4BPbpPtr) += mult_i * (here->BSIM4grbpd + here->BSIM4grbps + + here->BSIM4grbpb)); /* WDL: (-here->BSIM4gbbs) already added to BPbpPtr */ - (*(here->BSIM4SBspPtr ) += m * xcsbsb * s->real); - (*(here->BSIM4SBspPtr +1) += m * xcsbsb * s->imag); - (*(here->BSIM4SBspPtr) -= m * here->BSIM4gbs); - (*(here->BSIM4SBbpPtr) -= m * here->BSIM4grbps); - (*(here->BSIM4SBbPtr) -= m * here->BSIM4grbsb); - (*(here->BSIM4SBsbPtr ) -= m * xcsbsb * s->real); - (*(here->BSIM4SBsbPtr +1) -= m * xcsbsb * s->imag); - (*(here->BSIM4SBsbPtr) += m * (here->BSIM4gbs - + here->BSIM4grbps + here->BSIM4grbsb)); + (*(here->BSIM4SBspPtr ) += mult_q * xcsbsb * s->real); + (*(here->BSIM4SBspPtr +1) += mult_q * xcsbsb * s->imag); + (*(here->BSIM4SBspPtr) -= mult_i * here->BSIM4gbs); + (*(here->BSIM4SBbpPtr) -= mult_i * here->BSIM4grbps); + (*(here->BSIM4SBbPtr) -= mult_i * here->BSIM4grbsb); + (*(here->BSIM4SBsbPtr ) -= mult_q * xcsbsb * s->real); + (*(here->BSIM4SBsbPtr +1) -= mult_q * xcsbsb * s->imag); + (*(here->BSIM4SBsbPtr) += mult_i * (here->BSIM4gbs + + here->BSIM4grbps + here->BSIM4grbsb)); - (*(here->BSIM4BdbPtr) -= m * here->BSIM4grbdb); - (*(here->BSIM4BbpPtr) -= m * here->BSIM4grbpb); - (*(here->BSIM4BsbPtr) -= m * here->BSIM4grbsb); - (*(here->BSIM4BbPtr) += m * (here->BSIM4grbsb + here->BSIM4grbdb + (*(here->BSIM4BdbPtr) -= mult_i * here->BSIM4grbdb); + (*(here->BSIM4BbpPtr) -= mult_i * here->BSIM4grbpb); + (*(here->BSIM4BsbPtr) -= mult_i * here->BSIM4grbsb); + (*(here->BSIM4BbPtr) += mult_i * (here->BSIM4grbsb + here->BSIM4grbdb + here->BSIM4grbpb)); } diff --git a/src/spicelib/devices/bsim4/b4set.c b/src/spicelib/devices/bsim4/b4set.c index 1736b52df..05185af03 100644 --- a/src/spicelib/devices/bsim4/b4set.c +++ b/src/spicelib/devices/bsim4/b4set.c @@ -1,29 +1,25 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* Licensed under Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the license at http://opensource.org/licenses/ECL-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc */ #include "ngspice/ngspice.h" @@ -80,9 +76,9 @@ BSIM4instance **InstArray; for( ; model != NULL; model = BSIM4nextModel(model)) { /* process defaults of model parameters */ if (!model->BSIM4typeGiven) - model->BSIM4type = NMOS; + model->BSIM4type = NMOS; - if (!model->BSIM4mobModGiven) + if (!model->BSIM4mobModGiven) model->BSIM4mobMod = 0; else if ((model->BSIM4mobMod != 0) && (model->BSIM4mobMod != 1)&& (model->BSIM4mobMod != 2)&& (model->BSIM4mobMod != 3) && (model->BSIM4mobMod != 4) && (model->BSIM4mobMod != 5) && (model->BSIM4mobMod != 6)) /* Synopsys 08/30/2013 modify */ @@ -90,9 +86,9 @@ BSIM4instance **InstArray; printf("Warning: mobMod has been set to its default value: 0.\n"); } - if (!model->BSIM4binUnitGiven) + if (!model->BSIM4binUnitGiven) model->BSIM4binUnit = 1; - if (!model->BSIM4paramChkGiven) + if (!model->BSIM4paramChkGiven) model->BSIM4paramChk = 1; if (!model->BSIM4dioModGiven) @@ -103,9 +99,9 @@ BSIM4instance **InstArray; printf("Warning: dioMod has been set to its default value: 1.\n"); } - if (!model->BSIM4cvchargeModGiven) + if (!model->BSIM4cvchargeModGiven) model->BSIM4cvchargeMod = 0; - if (!model->BSIM4capModGiven) + if (!model->BSIM4capModGiven) model->BSIM4capMod = 2; else if ((model->BSIM4capMod != 0) && (model->BSIM4capMod != 1) && (model->BSIM4capMod != 2)) @@ -144,13 +140,7 @@ BSIM4instance **InstArray; if (!model->BSIM4geoModGiven) model->BSIM4geoMod = 0; - if (!model->BSIM4rgeoModGiven) - model->BSIM4rgeoMod = 0; - else if ((model->BSIM4rgeoMod != 0) && (model->BSIM4rgeoMod != 1)) - { model->BSIM4rgeoMod = 1; - printf("Warning: rgeoMod has been set to its default value: 1.\n"); - } - if (!model->BSIM4fnoiModGiven) + if (!model->BSIM4fnoiModGiven) model->BSIM4fnoiMod = 1; else if ((model->BSIM4fnoiMod != 0) && (model->BSIM4fnoiMod != 1)) { model->BSIM4fnoiMod = 1; @@ -164,7 +154,7 @@ BSIM4instance **InstArray; } if (!model->BSIM4trnqsModGiven) - model->BSIM4trnqsMod = 0; + model->BSIM4trnqsMod = 0; else if ((model->BSIM4trnqsMod != 0) && (model->BSIM4trnqsMod != 1)) { model->BSIM4trnqsMod = 0; printf("Warning: trnqsMod has been set to its default value: 0.\n"); @@ -176,14 +166,14 @@ BSIM4instance **InstArray; printf("Warning: acnqsMod has been set to its default value: 0.\n"); } - if (!model->BSIM4mtrlModGiven) + if (!model->BSIM4mtrlModGiven) model->BSIM4mtrlMod = 0; else if((model->BSIM4mtrlMod != 0) && (model->BSIM4mtrlMod != 1)) { model->BSIM4mtrlMod = 0; printf("Warning: mtrlMod has been set to its default value: 0.\n"); } - if (!model->BSIM4mtrlCompatModGiven) + if (!model->BSIM4mtrlCompatModGiven) model->BSIM4mtrlCompatMod = 0; else if((model->BSIM4mtrlCompatMod != 0) && (model->BSIM4mtrlCompatMod != 1)) { @@ -194,7 +184,7 @@ BSIM4instance **InstArray; if (!model->BSIM4igcModGiven) model->BSIM4igcMod = 0; else if ((model->BSIM4igcMod != 0) && (model->BSIM4igcMod != 1) - && (model->BSIM4igcMod != 2)) + && (model->BSIM4igcMod != 2)) { model->BSIM4igcMod = 0; printf("Warning: igcMod has been set to its default value: 0.\n"); } @@ -206,14 +196,13 @@ BSIM4instance **InstArray; } if (!model->BSIM4tempModGiven) model->BSIM4tempMod = 0; - else if ((model->BSIM4tempMod != 0) && (model->BSIM4tempMod != 1) - && (model->BSIM4tempMod != 2) && (model->BSIM4tempMod != 3)) + else if ((model->BSIM4tempMod != 0) && (model->BSIM4tempMod != 1) + && (model->BSIM4tempMod != 2) && (model->BSIM4tempMod != 3)) { model->BSIM4tempMod = 0; printf("Warning: tempMod has been set to its default value: 0.\n"); } - - if (!model->BSIM4versionGiven) - model->BSIM4version = copy("4.8.2"); + if (!model->BSIM4versionGiven) + model->BSIM4version = copy("4.8.3"); if (!model->BSIM4toxrefGiven) model->BSIM4toxref = 30.0e-10; if (!model->BSIM4eotGiven) @@ -225,7 +214,7 @@ BSIM4instance **InstArray; if (!model->BSIM4leffeotGiven) model->BSIM4leffeot = 1; if (!model->BSIM4weffeotGiven) - model->BSIM4weffeot = 10; + model->BSIM4weffeot = 10; if (!model->BSIM4adosGiven) model->BSIM4ados = 1.0; if (!model->BSIM4bdosGiven) @@ -240,11 +229,10 @@ BSIM4instance **InstArray; model->BSIM4dtox = 0.0; if (!model->BSIM4epsroxGiven) model->BSIM4epsrox = 3.9; - if (!model->BSIM4cdscGiven) model->BSIM4cdsc = 2.4e-4; /* unit Q/V/m^2 */ if (!model->BSIM4cdscbGiven) - model->BSIM4cdscb = 0.0; /* unit Q/V/m^2 */ + model->BSIM4cdscb = 0.0; /* unit Q/V/m^2 */ if (!model->BSIM4cdscdGiven) model->BSIM4cdscd = 0.0; /* unit Q/V/m^2 */ if (!model->BSIM4citGiven) @@ -254,11 +242,11 @@ BSIM4instance **InstArray; if (!model->BSIM4xjGiven) model->BSIM4xj = .15e-6; if (!model->BSIM4vsatGiven) - model->BSIM4vsat = 8.0e4; /* unit m/s */ + model->BSIM4vsat = 8.0e4; /* unit m/s */ if (!model->BSIM4atGiven) - model->BSIM4at = 3.3e4; /* unit m/s */ + model->BSIM4at = 3.3e4; /* unit m/s */ if (!model->BSIM4a0Given) - model->BSIM4a0 = 1.0; + model->BSIM4a0 = 1.0; if (!model->BSIM4agsGiven) model->BSIM4ags = 0.0; if (!model->BSIM4a1Given) @@ -267,24 +255,26 @@ BSIM4instance **InstArray; model->BSIM4a2 = 1.0; if (!model->BSIM4ketaGiven) model->BSIM4keta = -0.047; /* unit / V */ + if (!model->BSIM4ketacGiven) + model->BSIM4ketac = model->BSIM4keta; /* unit / V */ if (!model->BSIM4nsubGiven) model->BSIM4nsub = 6.0e16; /* unit 1/cm3 */ if (!model->BSIM4phigGiven) - model->BSIM4phig = 4.05; + model->BSIM4phig = 4.05; if (!model->BSIM4epsrgateGiven) - model->BSIM4epsrgate = 11.7; + model->BSIM4epsrgate = 11.7; if (!model->BSIM4easubGiven) - model->BSIM4easub = 4.05; + model->BSIM4easub = 4.05; if (!model->BSIM4epsrsubGiven) - model->BSIM4epsrsub = 11.7; + model->BSIM4epsrsub = 11.7; if (!model->BSIM4ni0subGiven) model->BSIM4ni0sub = 1.45e10; /* unit 1/cm3 */ if (!model->BSIM4bg0subGiven) model->BSIM4bg0sub = 1.16; /* unit eV */ if (!model->BSIM4tbgasubGiven) - model->BSIM4tbgasub = 7.02e-4; + model->BSIM4tbgasub = 7.02e-4; if (!model->BSIM4tbgbsubGiven) - model->BSIM4tbgbsub = 1108.0; + model->BSIM4tbgbsub = 1108.0; if (!model->BSIM4ndepGiven) model->BSIM4ndep = 1.7e17; /* unit 1/cm3 */ if (!model->BSIM4nsdGiven) @@ -304,20 +294,20 @@ BSIM4instance **InstArray; if (!model->BSIM4kt2Given) model->BSIM4kt2 = 0.022; /* No unit */ if (!model->BSIM4k3Given) - model->BSIM4k3 = 80.0; + model->BSIM4k3 = 80.0; if (!model->BSIM4k3bGiven) - model->BSIM4k3b = 0.0; + model->BSIM4k3b = 0.0; if (!model->BSIM4w0Given) - model->BSIM4w0 = 2.5e-6; + model->BSIM4w0 = 2.5e-6; if (!model->BSIM4lpe0Given) - model->BSIM4lpe0 = 1.74e-7; + model->BSIM4lpe0 = 1.74e-7; if (!model->BSIM4lpebGiven) model->BSIM4lpeb = 0.0; if (!model->BSIM4dvtp0Given) model->BSIM4dvtp0 = 0.0; if (!model->BSIM4dvtp1Given) model->BSIM4dvtp1 = 0.0; - if (!model->BSIM4dvtp2Given) /* New DIBL/Rout */ + if (!model->BSIM4dvtp2Given) /* New DIBL/Rout */ model->BSIM4dvtp2 = 0.0; if (!model->BSIM4dvtp3Given) model->BSIM4dvtp3 = 0.0; @@ -326,23 +316,23 @@ BSIM4instance **InstArray; if (!model->BSIM4dvtp5Given) model->BSIM4dvtp5 = 0.0; if (!model->BSIM4dvt0Given) - model->BSIM4dvt0 = 2.2; + model->BSIM4dvt0 = 2.2; if (!model->BSIM4dvt1Given) - model->BSIM4dvt1 = 0.53; + model->BSIM4dvt1 = 0.53; if (!model->BSIM4dvt2Given) - model->BSIM4dvt2 = -0.032; /* unit 1 / V */ + model->BSIM4dvt2 = -0.032; /* unit 1 / V */ if (!model->BSIM4dvt0wGiven) - model->BSIM4dvt0w = 0.0; + model->BSIM4dvt0w = 0.0; if (!model->BSIM4dvt1wGiven) - model->BSIM4dvt1w = 5.3e6; + model->BSIM4dvt1w = 5.3e6; if (!model->BSIM4dvt2wGiven) - model->BSIM4dvt2w = -0.032; + model->BSIM4dvt2w = -0.032; if (!model->BSIM4droutGiven) - model->BSIM4drout = 0.56; + model->BSIM4drout = 0.56; if (!model->BSIM4dsubGiven) - model->BSIM4dsub = model->BSIM4drout; + model->BSIM4dsub = model->BSIM4drout; if (!model->BSIM4vth0Given) model->BSIM4vth0 = (model->BSIM4type == NMOS) ? 0.7 : -0.7; if (!model->BSIM4vfbGiven) @@ -351,26 +341,28 @@ BSIM4instance **InstArray; model->BSIM4eu = (model->BSIM4type == NMOS) ? 1.67 : 1.0; 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))) - { /* check only for version <= 4.80 */ - if (!model->BSIM4uaGiven) + (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->BSIM4uaGiven) model->BSIM4ua = ((model->BSIM4mobMod == 2)) ? 1.0e-15 : 1.0e-9; /* unit m/V */ - if (!model->BSIM4ucGiven) - model->BSIM4uc = (model->BSIM4mobMod == 1) ? -0.0465 : -0.0465e-9; - if (!model->BSIM4uc1Given) - model->BSIM4uc1 = (model->BSIM4mobMod == 1) ? -0.056 : -0.056e-9; + if (!model->BSIM4ucGiven) + model->BSIM4uc = (model->BSIM4mobMod == 1) ? -0.0465 : -0.0465e-9; + if (!model->BSIM4uc1Given) + model->BSIM4uc1 = (model->BSIM4mobMod == 1) ? -0.056 : -0.056e-9; } else { - if (!model->BSIM4uaGiven) + if (!model->BSIM4uaGiven) model->BSIM4ua = ((model->BSIM4mobMod == 2 || model->BSIM4mobMod == 6)) ? 1.0e-15 : 1.0e-9; /* unit m/V */ - /*printf("warning:ua=%g",model->BSIM4ua);*/ - if (!model->BSIM4ucGiven) + if (!model->BSIM4ucGiven) model->BSIM4uc = (model->BSIM4mobMod == 1 || model->BSIM4mobMod == 5) ? -0.0465 : -0.0465e-9; - if (!model->BSIM4uc1Given) + if (!model->BSIM4uc1Given) model->BSIM4uc1 = (model->BSIM4mobMod == 1 || model->BSIM4mobMod == 5) ? -0.056 : -0.056e-9; } + if (!model->BSIM4ua1Given) model->BSIM4ua1 = 1.0e-9; /* unit m/V */ if (!model->BSIM4ubGiven) @@ -380,15 +372,15 @@ BSIM4instance **InstArray; if (!model->BSIM4udGiven) model->BSIM4ud = 0.0; /* unit m**(-2) */ if (!model->BSIM4ud1Given) - model->BSIM4ud1 = 0.0; + model->BSIM4ud1 = 0.0; if (!model->BSIM4upGiven) - model->BSIM4up = 0.0; + model->BSIM4up = 0.0; if (!model->BSIM4lpGiven) - model->BSIM4lp = 1.0e-8; + model->BSIM4lp = 1.0e-8; if (!model->BSIM4u0Given) model->BSIM4u0 = (model->BSIM4type == NMOS) ? 0.067 : 0.025; if (!model->BSIM4uteGiven) - model->BSIM4ute = -1.5; + model->BSIM4ute = -1.5; if (!model->BSIM4ucsteGiven) model->BSIM4ucste = -4.775e-3; if (!model->BSIM4voffGiven) @@ -409,7 +401,7 @@ BSIM4instance **InstArray; model->BSIM4pditsd = 0.0; if (!model->BSIM4pditslGiven) model->BSIM4pditsl = 0.0; - if (!model->BSIM4deltaGiven) + if (!model->BSIM4deltaGiven) model->BSIM4delta = 0.01; if (!model->BSIM4rdswminGiven) model->BSIM4rdswmin = 0.0; @@ -418,7 +410,7 @@ BSIM4instance **InstArray; if (!model->BSIM4rswminGiven) model->BSIM4rswmin = 0.0; if (!model->BSIM4rdswGiven) - model->BSIM4rdsw = 200.0; /* in ohm*um */ + model->BSIM4rdsw = 200.0; /* in ohm*um */ if (!model->BSIM4rdwGiven) model->BSIM4rdw = 100.0; if (!model->BSIM4rswGiven) @@ -426,45 +418,45 @@ BSIM4instance **InstArray; if (!model->BSIM4prwgGiven) model->BSIM4prwg = 1.0; /* in 1/V */ if (!model->BSIM4prwbGiven) - model->BSIM4prwb = 0.0; + model->BSIM4prwb = 0.0; if (!model->BSIM4prtGiven) - model->BSIM4prt = 0.0; + model->BSIM4prt = 0.0; if (!model->BSIM4eta0Given) - model->BSIM4eta0 = 0.08; /* no unit */ + model->BSIM4eta0 = 0.08; /* no unit */ if (!model->BSIM4etabGiven) - model->BSIM4etab = -0.07; /* unit 1/V */ + model->BSIM4etab = -0.07; /* unit 1/V */ if (!model->BSIM4pclmGiven) - model->BSIM4pclm = 1.3; /* no unit */ + model->BSIM4pclm = 1.3; /* no unit */ if (!model->BSIM4pdibl1Given) model->BSIM4pdibl1 = 0.39; /* no unit */ if (!model->BSIM4pdibl2Given) - model->BSIM4pdibl2 = 0.0086; /* no unit */ + model->BSIM4pdibl2 = 0.0086; /* no unit */ if (!model->BSIM4pdiblbGiven) - model->BSIM4pdiblb = 0.0; /* 1/V */ + model->BSIM4pdiblb = 0.0; /* 1/V */ if (!model->BSIM4pscbe1Given) - model->BSIM4pscbe1 = 4.24e8; + model->BSIM4pscbe1 = 4.24e8; if (!model->BSIM4pscbe2Given) - model->BSIM4pscbe2 = 1.0e-5; + model->BSIM4pscbe2 = 1.0e-5; if (!model->BSIM4pvagGiven) - model->BSIM4pvag = 0.0; - if (!model->BSIM4wrGiven) + model->BSIM4pvag = 0.0; + if (!model->BSIM4wrGiven) model->BSIM4wr = 1.0; - if (!model->BSIM4dwgGiven) + if (!model->BSIM4dwgGiven) model->BSIM4dwg = 0.0; - if (!model->BSIM4dwbGiven) + if (!model->BSIM4dwbGiven) model->BSIM4dwb = 0.0; if (!model->BSIM4b0Given) model->BSIM4b0 = 0.0; - if (!model->BSIM4b1Given) + if (!model->BSIM4b1Given) model->BSIM4b1 = 0.0; - if (!model->BSIM4alpha0Given) + if (!model->BSIM4alpha0Given) model->BSIM4alpha0 = 0.0; if (!model->BSIM4alpha1Given) model->BSIM4alpha1 = 0.0; - if (!model->BSIM4beta0Given) + if (!model->BSIM4beta0Given) model->BSIM4beta0 = 0.0; if (!model->BSIM4gidlModGiven) - model->BSIM4gidlMod = 0; /* v4.7 New GIDL/GISL */ + model->BSIM4gidlMod = 0; /* v4.7 New GIDL/GISL */ if (!model->BSIM4agidlGiven) model->BSIM4agidl = 0.0; if (!model->BSIM4bgidlGiven) @@ -473,11 +465,11 @@ BSIM4instance **InstArray; model->BSIM4cgidl = 0.5; /* V^3 */ if (!model->BSIM4egidlGiven) model->BSIM4egidl = 0.8; /* V */ - if (!model->BSIM4rgidlGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4rgidlGiven) /* v4.7 New GIDL/GISL */ model->BSIM4rgidl = 1.0; - if (!model->BSIM4kgidlGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4kgidlGiven) /* v4.7 New GIDL/GISL */ model->BSIM4kgidl = 0.0; - if (!model->BSIM4fgidlGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4fgidlGiven) /* v4.7 New GIDL/GISL */ /*model->BSIM4fgidl = 0.0;*/ /* Default value of fgdil set to 1 in BSIM4.8.0*/ model->BSIM4fgidl = 1.0; @@ -529,12 +521,13 @@ BSIM4instance **InstArray; model->BSIM4cgisl = model->BSIM4cgidl; if (!model->BSIM4egislGiven) model->BSIM4egisl = model->BSIM4egidl; - if (!model->BSIM4rgislGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4rgislGiven) /* v4.7 New GIDL/GISL */ model->BSIM4rgisl = model->BSIM4rgidl; - if (!model->BSIM4kgislGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4kgislGiven) /* v4.7 New GIDL/GISL */ model->BSIM4kgisl = model->BSIM4kgidl; - if (!model->BSIM4fgislGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4fgislGiven) /* v4.7 New GIDL/GISL */ model->BSIM4fgisl = model->BSIM4fgidl; + if (!model->BSIM4aigcGiven) model->BSIM4aigc = (model->BSIM4type == NMOS) ? 1.36e-2 : 9.80e-3; if (!model->BSIM4bigcGiven) @@ -625,9 +618,9 @@ BSIM4instance **InstArray; model->BSIM4rnoia = 0.577; if (!model->BSIM4rnoibGiven) model->BSIM4rnoib = 0.5164; - if (!model->BSIM4gidlclampGiven) + if (!model->BSIM4gidlclampGiven) model->BSIM4gidlclamp = -1e-5; - if (!model->BSIM4idovvdscGiven) + if (!model->BSIM4idovvdscGiven) model->BSIM4idovvdsc = 1e-9; if (!model->BSIM4rnoicGiven) model->BSIM4rnoic = 0.395; @@ -636,26 +629,26 @@ BSIM4instance **InstArray; if (!model->BSIM4lambdaGiven) model->BSIM4lambda = 0.0; if (!model->BSIM4vtlGiven) - model->BSIM4vtl = 2.0e5; /* unit m/s */ + model->BSIM4vtl = 2.0e5; /* unit m/s */ if (!model->BSIM4xnGiven) - model->BSIM4xn = 3.0; + model->BSIM4xn = 3.0; if (!model->BSIM4lcGiven) - model->BSIM4lc = 5.0e-9; - if (!model->BSIM4vfbsdoffGiven) - model->BSIM4vfbsdoff = 0.0; /* unit v */ + model->BSIM4lc = 5.0e-9; + if (!model->BSIM4vfbsdoffGiven) + model->BSIM4vfbsdoff = 0.0; /* unit v */ if (!model->BSIM4tvfbsdoffGiven) - model->BSIM4tvfbsdoff = 0.0; + model->BSIM4tvfbsdoff = 0.0; if (!model->BSIM4tvoffGiven) - model->BSIM4tvoff = 0.0; - if (!model->BSIM4tnfactorGiven) /* v4.7 temp dep of leakage current */ - model->BSIM4tnfactor = 0.0; - if (!model->BSIM4teta0Given) /* v4.7 temp dep of leakage current */ - model->BSIM4teta0 = 0.0; - if (!model->BSIM4tvoffcvGiven) /* v4.7 temp dep of leakage current */ - model->BSIM4tvoffcv = 0.0; - + model->BSIM4tvoff = 0.0; + if (!model->BSIM4tnfactorGiven) /* v4.7 temp dep of leakage current */ + model->BSIM4tnfactor = 0.0; + if (!model->BSIM4teta0Given) /* v4.7 temp dep of leakage current */ + model->BSIM4teta0 = 0.0; + if (!model->BSIM4tvoffcvGiven) /* v4.7 temp dep of leakage current */ + model->BSIM4tvoffcv = 0.0; + if (!model->BSIM4lintnoiGiven) - model->BSIM4lintnoi = 0.0; /* unit m */ + model->BSIM4lintnoi = 0.0; /* unit m */ if (!model->BSIM4xjbvsGiven) model->BSIM4xjbvs = 1.0; /* no unit */ @@ -738,19 +731,19 @@ BSIM4instance **InstArray; if (!model->BSIM4rbsdbynfGiven) model->BSIM4rbsdbynf = 0.0; - if (!model->BSIM4cgslGiven) + if (!model->BSIM4cgslGiven) model->BSIM4cgsl = 0.0; - if (!model->BSIM4cgdlGiven) + if (!model->BSIM4cgdlGiven) model->BSIM4cgdl = 0.0; - if (!model->BSIM4ckappasGiven) + if (!model->BSIM4ckappasGiven) model->BSIM4ckappas = 0.6; if (!model->BSIM4ckappadGiven) model->BSIM4ckappad = model->BSIM4ckappas; - if (!model->BSIM4clcGiven) + if (!model->BSIM4clcGiven) model->BSIM4clc = 0.1e-6; - if (!model->BSIM4cleGiven) + if (!model->BSIM4cleGiven) model->BSIM4cle = 0.6; - if (!model->BSIM4vfbcvGiven) + if (!model->BSIM4vfbcvGiven) model->BSIM4vfbcv = -1.0; if (!model->BSIM4acdeGiven) model->BSIM4acde = 1.0; @@ -789,7 +782,7 @@ BSIM4instance **InstArray; if (!model->BSIM4tpbswgGiven) model->BSIM4tpbswg = 0.0; - /* Length dependence */ + /* Length dependence */ if (!model->BSIM4lcdscGiven) model->BSIM4lcdsc = 0.0; if (!model->BSIM4lcdscbGiven) @@ -807,7 +800,7 @@ BSIM4instance **InstArray; if (!model->BSIM4latGiven) model->BSIM4lat = 0.0; if (!model->BSIM4la0Given) - model->BSIM4la0 = 0.0; + model->BSIM4la0 = 0.0; if (!model->BSIM4lagsGiven) model->BSIM4lags = 0.0; if (!model->BSIM4la1Given) @@ -816,6 +809,8 @@ BSIM4instance **InstArray; model->BSIM4la2 = 0.0; if (!model->BSIM4lketaGiven) model->BSIM4lketa = 0.0; + if (!model->BSIM4lketacGiven) + model->BSIM4lketac = model->BSIM4lketa; if (!model->BSIM4lnsubGiven) model->BSIM4lnsub = 0.0; if (!model->BSIM4lndepGiven) @@ -827,13 +822,13 @@ BSIM4instance **InstArray; if (!model->BSIM4lngateGiven) model->BSIM4lngate = 0.0; if (!model->BSIM4lvbmGiven) - model->BSIM4lvbm = 0.0; + model->BSIM4lvbm = 0.0; if (!model->BSIM4lxtGiven) - model->BSIM4lxt = 0.0; + model->BSIM4lxt = 0.0; if (!model->BSIM4lk1Given) model->BSIM4lk1 = 0.0; if (!model->BSIM4lkt1Given) - model->BSIM4lkt1 = 0.0; + model->BSIM4lkt1 = 0.0; if (!model->BSIM4lkt1lGiven) model->BSIM4lkt1l = 0.0; if (!model->BSIM4lkt2Given) @@ -841,20 +836,20 @@ BSIM4instance **InstArray; if (!model->BSIM4lk2Given) model->BSIM4lk2 = 0.0; if (!model->BSIM4lk3Given) - model->BSIM4lk3 = 0.0; + model->BSIM4lk3 = 0.0; if (!model->BSIM4lk3bGiven) - model->BSIM4lk3b = 0.0; + model->BSIM4lk3b = 0.0; if (!model->BSIM4lw0Given) - model->BSIM4lw0 = 0.0; + model->BSIM4lw0 = 0.0; if (!model->BSIM4llpe0Given) model->BSIM4llpe0 = 0.0; if (!model->BSIM4llpebGiven) - model->BSIM4llpeb = 0.0; + model->BSIM4llpeb = 0.0; if (!model->BSIM4ldvtp0Given) model->BSIM4ldvtp0 = 0.0; if (!model->BSIM4ldvtp1Given) model->BSIM4ldvtp1 = 0.0; - if (!model->BSIM4ldvtp2Given) /* New DIBL/Rout */ + if (!model->BSIM4ldvtp2Given) /* New DIBL/Rout */ model->BSIM4ldvtp2 = 0.0; if (!model->BSIM4ldvtp3Given) model->BSIM4ldvtp3 = 0.0; @@ -863,19 +858,19 @@ BSIM4instance **InstArray; if (!model->BSIM4ldvtp5Given) model->BSIM4ldvtp5 = 0.0; if (!model->BSIM4ldvt0Given) - model->BSIM4ldvt0 = 0.0; + model->BSIM4ldvt0 = 0.0; if (!model->BSIM4ldvt1Given) - model->BSIM4ldvt1 = 0.0; + model->BSIM4ldvt1 = 0.0; if (!model->BSIM4ldvt2Given) model->BSIM4ldvt2 = 0.0; if (!model->BSIM4ldvt0wGiven) - model->BSIM4ldvt0w = 0.0; + model->BSIM4ldvt0w = 0.0; if (!model->BSIM4ldvt1wGiven) - model->BSIM4ldvt1w = 0.0; + model->BSIM4ldvt1w = 0.0; if (!model->BSIM4ldvt2wGiven) model->BSIM4ldvt2w = 0.0; if (!model->BSIM4ldroutGiven) - model->BSIM4ldrout = 0.0; + model->BSIM4ldrout = 0.0; if (!model->BSIM4ldsubGiven) model->BSIM4ldsub = 0.0; if (!model->BSIM4lvth0Given) @@ -903,9 +898,9 @@ BSIM4instance **InstArray; if (!model->BSIM4lu0Given) model->BSIM4lu0 = 0.0; if (!model->BSIM4luteGiven) - model->BSIM4lute = 0.0; - if (!model->BSIM4lucsteGiven) - model->BSIM4lucste = 0.0; + model->BSIM4lute = 0.0; + if (!model->BSIM4lucsteGiven) + model->BSIM4lucste = 0.0; if (!model->BSIM4lvoffGiven) model->BSIM4lvoff = 0.0; if (!model->BSIM4lminvGiven) @@ -918,7 +913,7 @@ BSIM4instance **InstArray; model->BSIM4lpdits = 0.0; if (!model->BSIM4lpditsdGiven) model->BSIM4lpditsd = 0.0; - if (!model->BSIM4ldeltaGiven) + if (!model->BSIM4ldeltaGiven) model->BSIM4ldelta = 0.0; if (!model->BSIM4lrdswGiven) model->BSIM4lrdsw = 0.0; @@ -937,7 +932,7 @@ BSIM4instance **InstArray; if (!model->BSIM4letabGiven) model->BSIM4letab = -0.0; if (!model->BSIM4lpclmGiven) - model->BSIM4lpclm = 0.0; + model->BSIM4lpclm = 0.0; if (!model->BSIM4lpdibl1Given) model->BSIM4lpdibl1 = 0.0; if (!model->BSIM4lpdibl2Given) @@ -949,22 +944,22 @@ BSIM4instance **InstArray; if (!model->BSIM4lpscbe2Given) model->BSIM4lpscbe2 = 0.0; if (!model->BSIM4lpvagGiven) - model->BSIM4lpvag = 0.0; - if (!model->BSIM4lwrGiven) + model->BSIM4lpvag = 0.0; + if (!model->BSIM4lwrGiven) model->BSIM4lwr = 0.0; - if (!model->BSIM4ldwgGiven) + if (!model->BSIM4ldwgGiven) model->BSIM4ldwg = 0.0; - if (!model->BSIM4ldwbGiven) + if (!model->BSIM4ldwbGiven) model->BSIM4ldwb = 0.0; if (!model->BSIM4lb0Given) model->BSIM4lb0 = 0.0; - if (!model->BSIM4lb1Given) + if (!model->BSIM4lb1Given) model->BSIM4lb1 = 0.0; - if (!model->BSIM4lalpha0Given) + if (!model->BSIM4lalpha0Given) model->BSIM4lalpha0 = 0.0; if (!model->BSIM4lalpha1Given) model->BSIM4lalpha1 = 0.0; - if (!model->BSIM4lbeta0Given) + if (!model->BSIM4lbeta0Given) model->BSIM4lbeta0 = 0.0; if (!model->BSIM4lagidlGiven) model->BSIM4lagidl = 0.0; @@ -974,11 +969,11 @@ BSIM4instance **InstArray; model->BSIM4lcgidl = 0.0; if (!model->BSIM4legidlGiven) model->BSIM4legidl = 0.0; - if (!model->BSIM4lrgidlGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4lrgidlGiven) /* v4.7 New GIDL/GISL */ model->BSIM4lrgidl = 0.0; - if (!model->BSIM4lkgidlGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4lkgidlGiven) /* v4.7 New GIDL/GISL */ model->BSIM4lkgidl = 0.0; - if (!model->BSIM4lfgidlGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4lfgidlGiven) /* v4.7 New GIDL/GISL */ model->BSIM4lfgidl = 0.0; /*if (!model->BSIM4lagislGiven) { @@ -1006,7 +1001,7 @@ BSIM4instance **InstArray; if (model->BSIM4legidlGiven) model->BSIM4legisl = model->BSIM4legidl; else - model->BSIM4legisl = 0.0; + model->BSIM4legisl = 0.0; }*/ /*if (!model->BSIM4lrgislGiven) { @@ -1033,11 +1028,11 @@ BSIM4instance **InstArray; model->BSIM4lcgisl = model->BSIM4lcgidl; if (!model->BSIM4legislGiven) model->BSIM4legisl = model->BSIM4legidl; - if (!model->BSIM4lrgislGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4lrgislGiven) /* v4.7 New GIDL/GISL */ model->BSIM4lrgisl = model->BSIM4lrgidl; - if (!model->BSIM4lkgislGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4lkgislGiven) /* v4.7 New GIDL/GISL */ model->BSIM4lkgisl = model->BSIM4lkgidl; - if (!model->BSIM4lfgislGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4lfgislGiven) /* v4.7 New GIDL/GISL */ model->BSIM4lfgisl = model->BSIM4lfgidl; if (!model->BSIM4laigcGiven) @@ -1055,9 +1050,9 @@ BSIM4instance **InstArray; } else { - if (!model->BSIM4laigsdGiven) - model->BSIM4laigsd = 0.0; - model->BSIM4laigs = model->BSIM4laigd = model->BSIM4laigsd; + if (!model->BSIM4laigsdGiven) + model->BSIM4laigsd = 0.0; + model->BSIM4laigs = model->BSIM4laigd = model->BSIM4laigsd; } if (!model->BSIM4bigsdGiven && (model->BSIM4bigsGiven || model->BSIM4bigdGiven)) { @@ -1068,9 +1063,9 @@ BSIM4instance **InstArray; } else { - if (!model->BSIM4lbigsdGiven) - model->BSIM4lbigsd = 0.0; - model->BSIM4lbigs = model->BSIM4lbigd = model->BSIM4lbigsd; + if (!model->BSIM4lbigsdGiven) + model->BSIM4lbigsd = 0.0; + model->BSIM4lbigs = model->BSIM4lbigd = model->BSIM4lbigsd; } if (!model->BSIM4cigsdGiven && (model->BSIM4cigsGiven || model->BSIM4cigdGiven)) { @@ -1081,9 +1076,9 @@ BSIM4instance **InstArray; } else { - if (!model->BSIM4lcigsdGiven) - model->BSIM4lcigsd = 0.0; - model->BSIM4lcigs = model->BSIM4lcigd = model->BSIM4lcigsd; + if (!model->BSIM4lcigsdGiven) + model->BSIM4lcigsd = 0.0; + model->BSIM4lcigs = model->BSIM4lcigd = model->BSIM4lcigsd; } if (!model->BSIM4laigbaccGiven) model->BSIM4laigbacc = 0.0; @@ -1117,45 +1112,45 @@ BSIM4instance **InstArray; model->BSIM4lxrcrg2 = 0.0; if (!model->BSIM4leuGiven) model->BSIM4leu = 0.0; - if (!model->BSIM4lucsGiven) + if (!model->BSIM4lucsGiven) model->BSIM4lucs = 0.0; if (!model->BSIM4lvfbGiven) model->BSIM4lvfb = 0.0; if (!model->BSIM4llambdaGiven) model->BSIM4llambda = 0.0; if (!model->BSIM4lvtlGiven) - model->BSIM4lvtl = 0.0; + model->BSIM4lvtl = 0.0; if (!model->BSIM4lxnGiven) - model->BSIM4lxn = 0.0; + model->BSIM4lxn = 0.0; if (!model->BSIM4lvfbsdoffGiven) - model->BSIM4lvfbsdoff = 0.0; + model->BSIM4lvfbsdoff = 0.0; if (!model->BSIM4ltvfbsdoffGiven) - model->BSIM4ltvfbsdoff = 0.0; + model->BSIM4ltvfbsdoff = 0.0; if (!model->BSIM4ltvoffGiven) - model->BSIM4ltvoff = 0.0; - if (!model->BSIM4ltnfactorGiven) /* v4.7 temp dep of leakage current */ - model->BSIM4ltnfactor = 0.0; - if (!model->BSIM4lteta0Given) /* v4.7 temp dep of leakage current */ - model->BSIM4lteta0 = 0.0; - if (!model->BSIM4ltvoffcvGiven) /* v4.7 temp dep of leakage current */ - model->BSIM4ltvoffcv = 0.0; + model->BSIM4ltvoff = 0.0; + if (!model->BSIM4ltnfactorGiven) /* v4.7 temp dep of leakage current */ + model->BSIM4ltnfactor = 0.0; + if (!model->BSIM4lteta0Given) /* v4.7 temp dep of leakage current */ + model->BSIM4lteta0 = 0.0; + if (!model->BSIM4ltvoffcvGiven) /* v4.7 temp dep of leakage current */ + model->BSIM4ltvoffcv = 0.0; - if (!model->BSIM4lcgslGiven) + if (!model->BSIM4lcgslGiven) model->BSIM4lcgsl = 0.0; - if (!model->BSIM4lcgdlGiven) + if (!model->BSIM4lcgdlGiven) model->BSIM4lcgdl = 0.0; - if (!model->BSIM4lckappasGiven) + if (!model->BSIM4lckappasGiven) model->BSIM4lckappas = 0.0; if (!model->BSIM4lckappadGiven) model->BSIM4lckappad = 0.0; - if (!model->BSIM4lclcGiven) + if (!model->BSIM4lclcGiven) model->BSIM4lclc = 0.0; - if (!model->BSIM4lcleGiven) + if (!model->BSIM4lcleGiven) model->BSIM4lcle = 0.0; - if (!model->BSIM4lcfGiven) + if (!model->BSIM4lcfGiven) model->BSIM4lcf = 0.0; - if (!model->BSIM4lvfbcvGiven) + if (!model->BSIM4lvfbcvGiven) model->BSIM4lvfbcv = 0.0; if (!model->BSIM4lacdeGiven) model->BSIM4lacde = 0.0; @@ -1166,11 +1161,11 @@ BSIM4instance **InstArray; if (!model->BSIM4lvoffcvGiven) model->BSIM4lvoffcv = 0.0; - /* Width dependence */ + /* Width dependence */ if (!model->BSIM4wcdscGiven) model->BSIM4wcdsc = 0.0; if (!model->BSIM4wcdscbGiven) - model->BSIM4wcdscb = 0.0; + model->BSIM4wcdscb = 0.0; if (!model->BSIM4wcdscdGiven) model->BSIM4wcdscd = 0.0; if (!model->BSIM4wcitGiven) @@ -1184,7 +1179,7 @@ BSIM4instance **InstArray; if (!model->BSIM4watGiven) model->BSIM4wat = 0.0; if (!model->BSIM4wa0Given) - model->BSIM4wa0 = 0.0; + model->BSIM4wa0 = 0.0; if (!model->BSIM4wagsGiven) model->BSIM4wags = 0.0; if (!model->BSIM4wa1Given) @@ -1193,6 +1188,8 @@ BSIM4instance **InstArray; model->BSIM4wa2 = 0.0; if (!model->BSIM4wketaGiven) model->BSIM4wketa = 0.0; + if (!model->BSIM4wketacGiven) + model->BSIM4wketac = model->BSIM4wketa; if (!model->BSIM4wnsubGiven) model->BSIM4wnsub = 0.0; if (!model->BSIM4wndepGiven) @@ -1210,7 +1207,7 @@ BSIM4instance **InstArray; if (!model->BSIM4wk1Given) model->BSIM4wk1 = 0.0; if (!model->BSIM4wkt1Given) - model->BSIM4wkt1 = 0.0; + model->BSIM4wkt1 = 0.0; if (!model->BSIM4wkt1lGiven) model->BSIM4wkt1l = 0.0; if (!model->BSIM4wkt2Given) @@ -1218,20 +1215,20 @@ BSIM4instance **InstArray; if (!model->BSIM4wk2Given) model->BSIM4wk2 = 0.0; if (!model->BSIM4wk3Given) - model->BSIM4wk3 = 0.0; + model->BSIM4wk3 = 0.0; if (!model->BSIM4wk3bGiven) - model->BSIM4wk3b = 0.0; + model->BSIM4wk3b = 0.0; if (!model->BSIM4ww0Given) - model->BSIM4ww0 = 0.0; + model->BSIM4ww0 = 0.0; if (!model->BSIM4wlpe0Given) model->BSIM4wlpe0 = 0.0; if (!model->BSIM4wlpebGiven) - model->BSIM4wlpeb = 0.0; + model->BSIM4wlpeb = 0.0; if (!model->BSIM4wdvtp0Given) model->BSIM4wdvtp0 = 0.0; if (!model->BSIM4wdvtp1Given) model->BSIM4wdvtp1 = 0.0; - if (!model->BSIM4wdvtp2Given) /* New DIBL/Rout */ + if (!model->BSIM4wdvtp2Given) /* New DIBL/Rout */ model->BSIM4wdvtp2 = 0.0; if (!model->BSIM4wdvtp3Given) model->BSIM4wdvtp3 = 0.0; @@ -1240,23 +1237,23 @@ BSIM4instance **InstArray; if (!model->BSIM4wdvtp5Given) model->BSIM4wdvtp5 = 0.0; if (!model->BSIM4wdvt0Given) - model->BSIM4wdvt0 = 0.0; + model->BSIM4wdvt0 = 0.0; if (!model->BSIM4wdvt1Given) - model->BSIM4wdvt1 = 0.0; + model->BSIM4wdvt1 = 0.0; if (!model->BSIM4wdvt2Given) model->BSIM4wdvt2 = 0.0; if (!model->BSIM4wdvt0wGiven) - model->BSIM4wdvt0w = 0.0; + model->BSIM4wdvt0w = 0.0; if (!model->BSIM4wdvt1wGiven) - model->BSIM4wdvt1w = 0.0; + model->BSIM4wdvt1w = 0.0; if (!model->BSIM4wdvt2wGiven) model->BSIM4wdvt2w = 0.0; if (!model->BSIM4wdroutGiven) - model->BSIM4wdrout = 0.0; + model->BSIM4wdrout = 0.0; if (!model->BSIM4wdsubGiven) model->BSIM4wdsub = 0.0; if (!model->BSIM4wvth0Given) - model->BSIM4wvth0 = 0.0; + model->BSIM4wvth0 = 0.0; if (!model->BSIM4wuaGiven) model->BSIM4wua = 0.0; if (!model->BSIM4wua1Given) @@ -1280,11 +1277,11 @@ BSIM4instance **InstArray; if (!model->BSIM4wu0Given) model->BSIM4wu0 = 0.0; if (!model->BSIM4wuteGiven) - model->BSIM4wute = 0.0; + model->BSIM4wute = 0.0; if (!model->BSIM4wucsteGiven) - model->BSIM4wucste = 0.0; + model->BSIM4wucste = 0.0; if (!model->BSIM4wvoffGiven) - model->BSIM4wvoff = 0.0; + model->BSIM4wvoff = 0.0; if (!model->BSIM4wminvGiven) model->BSIM4wminv = 0.0; if (!model->BSIM4wminvcvGiven) @@ -1295,7 +1292,7 @@ BSIM4instance **InstArray; model->BSIM4wpdits = 0.0; if (!model->BSIM4wpditsdGiven) model->BSIM4wpditsd = 0.0; - if (!model->BSIM4wdeltaGiven) + if (!model->BSIM4wdeltaGiven) model->BSIM4wdelta = 0.0; if (!model->BSIM4wrdswGiven) model->BSIM4wrdsw = 0.0; @@ -1314,7 +1311,7 @@ BSIM4instance **InstArray; if (!model->BSIM4wetabGiven) model->BSIM4wetab = 0.0; if (!model->BSIM4wpclmGiven) - model->BSIM4wpclm = 0.0; + model->BSIM4wpclm = 0.0; if (!model->BSIM4wpdibl1Given) model->BSIM4wpdibl1 = 0.0; if (!model->BSIM4wpdibl2Given) @@ -1326,22 +1323,22 @@ BSIM4instance **InstArray; if (!model->BSIM4wpscbe2Given) model->BSIM4wpscbe2 = 0.0; if (!model->BSIM4wpvagGiven) - model->BSIM4wpvag = 0.0; - if (!model->BSIM4wwrGiven) + model->BSIM4wpvag = 0.0; + if (!model->BSIM4wwrGiven) model->BSIM4wwr = 0.0; - if (!model->BSIM4wdwgGiven) + if (!model->BSIM4wdwgGiven) model->BSIM4wdwg = 0.0; - if (!model->BSIM4wdwbGiven) + if (!model->BSIM4wdwbGiven) model->BSIM4wdwb = 0.0; if (!model->BSIM4wb0Given) model->BSIM4wb0 = 0.0; - if (!model->BSIM4wb1Given) + if (!model->BSIM4wb1Given) model->BSIM4wb1 = 0.0; - if (!model->BSIM4walpha0Given) + if (!model->BSIM4walpha0Given) model->BSIM4walpha0 = 0.0; if (!model->BSIM4walpha1Given) model->BSIM4walpha1 = 0.0; - if (!model->BSIM4wbeta0Given) + if (!model->BSIM4wbeta0Given) model->BSIM4wbeta0 = 0.0; if (!model->BSIM4wagidlGiven) model->BSIM4wagidl = 0.0; @@ -1351,13 +1348,12 @@ BSIM4instance **InstArray; model->BSIM4wcgidl = 0.0; if (!model->BSIM4wegidlGiven) model->BSIM4wegidl = 0.0; - if (!model->BSIM4wrgidlGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4wrgidlGiven) /* v4.7 New GIDL/GISL */ model->BSIM4wrgidl = 0.0; - if (!model->BSIM4wkgidlGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4wkgidlGiven) /* v4.7 New GIDL/GISL */ model->BSIM4wkgidl = 0.0; - if (!model->BSIM4wfgidlGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4wfgidlGiven) /* v4.7 New GIDL/GISL */ model->BSIM4wfgidl = 0.0; - /*if (!model->BSIM4wagislGiven) { if (model->BSIM4wagidlGiven) @@ -1384,7 +1380,7 @@ BSIM4instance **InstArray; if (model->BSIM4wegidlGiven) model->BSIM4wegisl = model->BSIM4wegidl; else - model->BSIM4wegisl = 0.0; + model->BSIM4wegisl = 0.0; }*/ /*if (!model->BSIM4wrgislGiven) { @@ -1404,18 +1400,18 @@ BSIM4instance **InstArray; /*Default value of wagisl, wbgisl, wcgisl, wegisl, wrgisl, wkgisl, and wfgisl are set as follows */ if (!model->BSIM4wagislGiven) - model->BSIM4wagisl = model->BSIM4wagidl; + model->BSIM4wagisl = model->BSIM4wagidl; if (!model->BSIM4wbgislGiven) model->BSIM4wbgisl = model->BSIM4wbgidl; if (!model->BSIM4wcgislGiven) model->BSIM4wcgisl = model->BSIM4wcgidl; if (!model->BSIM4wegislGiven) model->BSIM4wegisl = model->BSIM4wegidl; - if (!model->BSIM4wrgislGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4wrgislGiven) /* v4.7 New GIDL/GISL */ model->BSIM4wrgisl = model->BSIM4wrgidl; - if (!model->BSIM4wkgislGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4wkgislGiven) /* v4.7 New GIDL/GISL */ model->BSIM4wkgisl = model->BSIM4wkgidl; - if (!model->BSIM4wfgislGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4wfgislGiven) /* v4.7 New GIDL/GISL */ model->BSIM4wfgisl = model->BSIM4wfgidl; if (!model->BSIM4waigcGiven) @@ -1433,9 +1429,9 @@ BSIM4instance **InstArray; } else { - if (!model->BSIM4waigsdGiven) - model->BSIM4waigsd = 0.0; - model->BSIM4waigs = model->BSIM4waigd = model->BSIM4waigsd; + if (!model->BSIM4waigsdGiven) + model->BSIM4waigsd = 0.0; + model->BSIM4waigs = model->BSIM4waigd = model->BSIM4waigsd; } if (!model->BSIM4bigsdGiven && (model->BSIM4bigsGiven || model->BSIM4bigdGiven)) { @@ -1446,9 +1442,9 @@ BSIM4instance **InstArray; } else { - if (!model->BSIM4wbigsdGiven) - model->BSIM4wbigsd = 0.0; - model->BSIM4wbigs = model->BSIM4wbigd = model->BSIM4wbigsd; + if (!model->BSIM4wbigsdGiven) + model->BSIM4wbigsd = 0.0; + model->BSIM4wbigs = model->BSIM4wbigd = model->BSIM4wbigsd; } if (!model->BSIM4cigsdGiven && (model->BSIM4cigsGiven || model->BSIM4cigdGiven)) { @@ -1459,9 +1455,9 @@ BSIM4instance **InstArray; } else { - if (!model->BSIM4wcigsdGiven) - model->BSIM4wcigsd = 0.0; - model->BSIM4wcigs = model->BSIM4wcigd = model->BSIM4wcigsd; + if (!model->BSIM4wcigsdGiven) + model->BSIM4wcigsd = 0.0; + model->BSIM4wcigs = model->BSIM4wcigd = model->BSIM4wcigsd; } if (!model->BSIM4waigbaccGiven) model->BSIM4waigbacc = 0.0; @@ -1502,37 +1498,37 @@ BSIM4instance **InstArray; if (!model->BSIM4wlambdaGiven) model->BSIM4wlambda = 0.0; if (!model->BSIM4wvtlGiven) - model->BSIM4wvtl = 0.0; + model->BSIM4wvtl = 0.0; if (!model->BSIM4wxnGiven) - model->BSIM4wxn = 0.0; + model->BSIM4wxn = 0.0; if (!model->BSIM4wvfbsdoffGiven) - model->BSIM4wvfbsdoff = 0.0; + model->BSIM4wvfbsdoff = 0.0; if (!model->BSIM4wtvfbsdoffGiven) - model->BSIM4wtvfbsdoff = 0.0; + model->BSIM4wtvfbsdoff = 0.0; if (!model->BSIM4wtvoffGiven) - model->BSIM4wtvoff = 0.0; - if (!model->BSIM4wtnfactorGiven) /* v4.7 temp dep of leakage current */ - model->BSIM4wtnfactor = 0.0; - if (!model->BSIM4wteta0Given) /* v4.7 temp dep of leakage current */ - model->BSIM4wteta0 = 0.0; - if (!model->BSIM4wtvoffcvGiven) /* v4.7 temp dep of leakage current */ - model->BSIM4wtvoffcv = 0.0; + model->BSIM4wtvoff = 0.0; + if (!model->BSIM4wtnfactorGiven) /* v4.7 temp dep of leakage current */ + model->BSIM4wtnfactor = 0.0; + if (!model->BSIM4wteta0Given) /* v4.7 temp dep of leakage current */ + model->BSIM4wteta0 = 0.0; + if (!model->BSIM4wtvoffcvGiven) /* v4.7 temp dep of leakage current */ + model->BSIM4wtvoffcv = 0.0; - if (!model->BSIM4wcgslGiven) + if (!model->BSIM4wcgslGiven) model->BSIM4wcgsl = 0.0; - if (!model->BSIM4wcgdlGiven) + if (!model->BSIM4wcgdlGiven) model->BSIM4wcgdl = 0.0; - if (!model->BSIM4wckappasGiven) + if (!model->BSIM4wckappasGiven) model->BSIM4wckappas = 0.0; if (!model->BSIM4wckappadGiven) model->BSIM4wckappad = 0.0; - if (!model->BSIM4wcfGiven) + if (!model->BSIM4wcfGiven) model->BSIM4wcf = 0.0; - if (!model->BSIM4wclcGiven) + if (!model->BSIM4wclcGiven) model->BSIM4wclc = 0.0; - if (!model->BSIM4wcleGiven) + if (!model->BSIM4wcleGiven) model->BSIM4wcle = 0.0; - if (!model->BSIM4wvfbcvGiven) + if (!model->BSIM4wvfbcvGiven) model->BSIM4wvfbcv = 0.0; if (!model->BSIM4wacdeGiven) model->BSIM4wacde = 0.0; @@ -1543,11 +1539,11 @@ BSIM4instance **InstArray; if (!model->BSIM4wvoffcvGiven) model->BSIM4wvoffcv = 0.0; - /* Cross-term dependence */ + /* Cross-term dependence */ if (!model->BSIM4pcdscGiven) model->BSIM4pcdsc = 0.0; if (!model->BSIM4pcdscbGiven) - model->BSIM4pcdscb = 0.0; + model->BSIM4pcdscb = 0.0; if (!model->BSIM4pcdscdGiven) model->BSIM4pcdscd = 0.0; if (!model->BSIM4pcitGiven) @@ -1561,8 +1557,7 @@ BSIM4instance **InstArray; if (!model->BSIM4patGiven) model->BSIM4pat = 0.0; if (!model->BSIM4pa0Given) - model->BSIM4pa0 = 0.0; - + model->BSIM4pa0 = 0.0; if (!model->BSIM4pagsGiven) model->BSIM4pags = 0.0; if (!model->BSIM4pa1Given) @@ -1571,6 +1566,8 @@ BSIM4instance **InstArray; model->BSIM4pa2 = 0.0; if (!model->BSIM4pketaGiven) model->BSIM4pketa = 0.0; + if (!model->BSIM4pketacGiven) + model->BSIM4pketac = model->BSIM4pketa; if (!model->BSIM4pnsubGiven) model->BSIM4pnsub = 0.0; if (!model->BSIM4pndepGiven) @@ -1588,7 +1585,7 @@ BSIM4instance **InstArray; if (!model->BSIM4pk1Given) model->BSIM4pk1 = 0.0; if (!model->BSIM4pkt1Given) - model->BSIM4pkt1 = 0.0; + model->BSIM4pkt1 = 0.0; if (!model->BSIM4pkt1lGiven) model->BSIM4pkt1l = 0.0; if (!model->BSIM4pk2Given) @@ -1596,11 +1593,11 @@ BSIM4instance **InstArray; if (!model->BSIM4pkt2Given) model->BSIM4pkt2 = 0.0; if (!model->BSIM4pk3Given) - model->BSIM4pk3 = 0.0; + model->BSIM4pk3 = 0.0; if (!model->BSIM4pk3bGiven) - model->BSIM4pk3b = 0.0; + model->BSIM4pk3b = 0.0; if (!model->BSIM4pw0Given) - model->BSIM4pw0 = 0.0; + model->BSIM4pw0 = 0.0; if (!model->BSIM4plpe0Given) model->BSIM4plpe0 = 0.0; if (!model->BSIM4plpebGiven) @@ -1609,7 +1606,7 @@ BSIM4instance **InstArray; model->BSIM4pdvtp0 = 0.0; if (!model->BSIM4pdvtp1Given) model->BSIM4pdvtp1 = 0.0; - if (!model->BSIM4pdvtp2Given) /* New DIBL/Rout */ + if (!model->BSIM4pdvtp2Given) /* New DIBL/Rout */ model->BSIM4pdvtp2 = 0.0; if (!model->BSIM4pdvtp3Given) model->BSIM4pdvtp3 = 0.0; @@ -1618,19 +1615,19 @@ BSIM4instance **InstArray; if (!model->BSIM4pdvtp5Given) model->BSIM4pdvtp5 = 0.0; if (!model->BSIM4pdvt0Given) - model->BSIM4pdvt0 = 0.0; + model->BSIM4pdvt0 = 0.0; if (!model->BSIM4pdvt1Given) - model->BSIM4pdvt1 = 0.0; + model->BSIM4pdvt1 = 0.0; if (!model->BSIM4pdvt2Given) model->BSIM4pdvt2 = 0.0; if (!model->BSIM4pdvt0wGiven) - model->BSIM4pdvt0w = 0.0; + model->BSIM4pdvt0w = 0.0; if (!model->BSIM4pdvt1wGiven) - model->BSIM4pdvt1w = 0.0; + model->BSIM4pdvt1w = 0.0; if (!model->BSIM4pdvt2wGiven) model->BSIM4pdvt2w = 0.0; if (!model->BSIM4pdroutGiven) - model->BSIM4pdrout = 0.0; + model->BSIM4pdrout = 0.0; if (!model->BSIM4pdsubGiven) model->BSIM4pdsub = 0.0; if (!model->BSIM4pvth0Given) @@ -1658,9 +1655,9 @@ BSIM4instance **InstArray; if (!model->BSIM4pu0Given) model->BSIM4pu0 = 0.0; if (!model->BSIM4puteGiven) - model->BSIM4pute = 0.0; - if (!model->BSIM4pucsteGiven) - model->BSIM4pucste = 0.0; + model->BSIM4pute = 0.0; + if (!model->BSIM4pucsteGiven) + model->BSIM4pucste = 0.0; if (!model->BSIM4pvoffGiven) model->BSIM4pvoff = 0.0; if (!model->BSIM4pminvGiven) @@ -1673,7 +1670,7 @@ BSIM4instance **InstArray; model->BSIM4ppdits = 0.0; if (!model->BSIM4ppditsdGiven) model->BSIM4ppditsd = 0.0; - if (!model->BSIM4pdeltaGiven) + if (!model->BSIM4pdeltaGiven) model->BSIM4pdelta = 0.0; if (!model->BSIM4prdswGiven) model->BSIM4prdsw = 0.0; @@ -1692,7 +1689,7 @@ BSIM4instance **InstArray; if (!model->BSIM4petabGiven) model->BSIM4petab = 0.0; if (!model->BSIM4ppclmGiven) - model->BSIM4ppclm = 0.0; + model->BSIM4ppclm = 0.0; if (!model->BSIM4ppdibl1Given) model->BSIM4ppdibl1 = 0.0; if (!model->BSIM4ppdibl2Given) @@ -1704,22 +1701,22 @@ BSIM4instance **InstArray; if (!model->BSIM4ppscbe2Given) model->BSIM4ppscbe2 = 0.0; if (!model->BSIM4ppvagGiven) - model->BSIM4ppvag = 0.0; - if (!model->BSIM4pwrGiven) + model->BSIM4ppvag = 0.0; + if (!model->BSIM4pwrGiven) model->BSIM4pwr = 0.0; - if (!model->BSIM4pdwgGiven) + if (!model->BSIM4pdwgGiven) model->BSIM4pdwg = 0.0; - if (!model->BSIM4pdwbGiven) + if (!model->BSIM4pdwbGiven) model->BSIM4pdwb = 0.0; if (!model->BSIM4pb0Given) model->BSIM4pb0 = 0.0; - if (!model->BSIM4pb1Given) + if (!model->BSIM4pb1Given) model->BSIM4pb1 = 0.0; - if (!model->BSIM4palpha0Given) + if (!model->BSIM4palpha0Given) model->BSIM4palpha0 = 0.0; if (!model->BSIM4palpha1Given) model->BSIM4palpha1 = 0.0; - if (!model->BSIM4pbeta0Given) + if (!model->BSIM4pbeta0Given) model->BSIM4pbeta0 = 0.0; if (!model->BSIM4pagidlGiven) model->BSIM4pagidl = 0.0; @@ -1729,11 +1726,11 @@ BSIM4instance **InstArray; model->BSIM4pcgidl = 0.0; if (!model->BSIM4pegidlGiven) model->BSIM4pegidl = 0.0; - if (!model->BSIM4prgidlGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4prgidlGiven) /* v4.7 New GIDL/GISL */ model->BSIM4prgidl = 0.0; - if (!model->BSIM4pkgidlGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4pkgidlGiven) /* v4.7 New GIDL/GISL */ model->BSIM4pkgidl = 0.0; - if (!model->BSIM4pfgidlGiven) /* v4.7 New GIDL/GISL */ + if (!model->BSIM4pfgidlGiven) /* v4.7 New GIDL/GISL */ model->BSIM4pfgidl = 0.0; /*if (!model->BSIM4pagislGiven) @@ -1762,7 +1759,7 @@ BSIM4instance **InstArray; if (model->BSIM4pegidlGiven) model->BSIM4pegisl = model->BSIM4pegidl; else - model->BSIM4pegisl = 0.0; + model->BSIM4pegisl = 0.0; }*/ /*if (!model->BSIM4prgislGiven) @@ -1796,6 +1793,7 @@ BSIM4instance **InstArray; model->BSIM4pkgisl = model->BSIM4pkgidl; if (!model->BSIM4pfgislGiven) /* v4.7 New GIDL/GISL */ model->BSIM4pfgisl = model->BSIM4pfgidl; + if (!model->BSIM4paigcGiven) model->BSIM4paigc = 0.0; if (!model->BSIM4pbigcGiven) @@ -1811,9 +1809,9 @@ BSIM4instance **InstArray; } else { - if (!model->BSIM4paigsdGiven) - model->BSIM4paigsd = 0.0; - model->BSIM4paigs = model->BSIM4paigd = model->BSIM4paigsd; + if (!model->BSIM4paigsdGiven) + model->BSIM4paigsd = 0.0; + model->BSIM4paigs = model->BSIM4paigd = model->BSIM4paigsd; } if (!model->BSIM4bigsdGiven && (model->BSIM4bigsGiven || model->BSIM4bigdGiven)) { @@ -1824,9 +1822,9 @@ BSIM4instance **InstArray; } else { - if (!model->BSIM4pbigsdGiven) - model->BSIM4pbigsd = 0.0; - model->BSIM4pbigs = model->BSIM4pbigd = model->BSIM4pbigsd; + if (!model->BSIM4pbigsdGiven) + model->BSIM4pbigsd = 0.0; + model->BSIM4pbigs = model->BSIM4pbigd = model->BSIM4pbigsd; } if (!model->BSIM4cigsdGiven && (model->BSIM4cigsGiven || model->BSIM4cigdGiven)) { @@ -1837,9 +1835,9 @@ BSIM4instance **InstArray; } else { - if (!model->BSIM4pcigsdGiven) - model->BSIM4pcigsd = 0.0; - model->BSIM4pcigs = model->BSIM4pcigd = model->BSIM4pcigsd; + if (!model->BSIM4pcigsdGiven) + model->BSIM4pcigsd = 0.0; + model->BSIM4pcigs = model->BSIM4pcigd = model->BSIM4pcigsd; } if (!model->BSIM4paigbaccGiven) model->BSIM4paigbacc = 0.0; @@ -1873,44 +1871,43 @@ BSIM4instance **InstArray; model->BSIM4pxrcrg2 = 0.0; if (!model->BSIM4peuGiven) model->BSIM4peu = 0.0; - if (!model->BSIM4pucsGiven) + if (!model->BSIM4pucsGiven) model->BSIM4pucs = 0.0; if (!model->BSIM4pvfbGiven) model->BSIM4pvfb = 0.0; if (!model->BSIM4plambdaGiven) model->BSIM4plambda = 0.0; if (!model->BSIM4pvtlGiven) - model->BSIM4pvtl = 0.0; + model->BSIM4pvtl = 0.0; if (!model->BSIM4pxnGiven) - model->BSIM4pxn = 0.0; + model->BSIM4pxn = 0.0; if (!model->BSIM4pvfbsdoffGiven) - model->BSIM4pvfbsdoff = 0.0; + model->BSIM4pvfbsdoff = 0.0; if (!model->BSIM4ptvfbsdoffGiven) - model->BSIM4ptvfbsdoff = 0.0; + model->BSIM4ptvfbsdoff = 0.0; if (!model->BSIM4ptvoffGiven) - model->BSIM4ptvoff = 0.0; - if (!model->BSIM4ptnfactorGiven) /* v4.7 temp dep of leakage current */ - model->BSIM4ptnfactor = 0.0; - if (!model->BSIM4pteta0Given) /* v4.7 temp dep of leakage current */ - model->BSIM4pteta0 = 0.0; - if (!model->BSIM4ptvoffcvGiven) /* v4.7 temp dep of leakage current */ - model->BSIM4ptvoffcv = 0.0; - - if (!model->BSIM4pcgslGiven) + model->BSIM4ptvoff = 0.0; + if (!model->BSIM4ptnfactorGiven) /* v4.7 temp dep of leakage current */ + model->BSIM4ptnfactor = 0.0; + if (!model->BSIM4pteta0Given) /* v4.7 temp dep of leakage current */ + model->BSIM4pteta0 = 0.0; + if (!model->BSIM4ptvoffcvGiven) /* v4.7 temp dep of leakage current */ + model->BSIM4ptvoffcv = 0.0; + if (!model->BSIM4pcgslGiven) model->BSIM4pcgsl = 0.0; - if (!model->BSIM4pcgdlGiven) + if (!model->BSIM4pcgdlGiven) model->BSIM4pcgdl = 0.0; - if (!model->BSIM4pckappasGiven) + if (!model->BSIM4pckappasGiven) model->BSIM4pckappas = 0.0; if (!model->BSIM4pckappadGiven) model->BSIM4pckappad = 0.0; - if (!model->BSIM4pcfGiven) + if (!model->BSIM4pcfGiven) model->BSIM4pcf = 0.0; - if (!model->BSIM4pclcGiven) + if (!model->BSIM4pclcGiven) model->BSIM4pclc = 0.0; - if (!model->BSIM4pcleGiven) + if (!model->BSIM4pcleGiven) model->BSIM4pcle = 0.0; - if (!model->BSIM4pvfbcvGiven) + if (!model->BSIM4pvfbcvGiven) model->BSIM4pvfbcv = 0.0; if (!model->BSIM4pacdeGiven) model->BSIM4pacde = 0.0; @@ -1920,7 +1917,6 @@ BSIM4instance **InstArray; model->BSIM4pnoff = 0.0; if (!model->BSIM4pvoffcvGiven) model->BSIM4pvoffcv = 0.0; - if (!model->BSIM4gamma1Given) model->BSIM4gamma1 = 0.0; if (!model->BSIM4lgamma1Given) @@ -1947,67 +1943,67 @@ BSIM4instance **InstArray; model->BSIM4pvbx = 0.0; /* unit degree celcius */ - if (!model->BSIM4tnomGiven) - model->BSIM4tnom = ckt->CKTnomTemp; - if (!model->BSIM4LintGiven) + if (!model->BSIM4tnomGiven) + model->BSIM4tnom = ckt->CKTnomTemp; + if (!model->BSIM4LintGiven) model->BSIM4Lint = 0.0; - if (!model->BSIM4LlGiven) + if (!model->BSIM4LlGiven) model->BSIM4Ll = 0.0; if (!model->BSIM4LlcGiven) model->BSIM4Llc = model->BSIM4Ll; - if (!model->BSIM4LlnGiven) + if (!model->BSIM4LlnGiven) model->BSIM4Lln = 1.0; - if (!model->BSIM4LwGiven) + if (!model->BSIM4LwGiven) model->BSIM4Lw = 0.0; if (!model->BSIM4LwcGiven) model->BSIM4Lwc = model->BSIM4Lw; - if (!model->BSIM4LwnGiven) + if (!model->BSIM4LwnGiven) model->BSIM4Lwn = 1.0; - if (!model->BSIM4LwlGiven) + if (!model->BSIM4LwlGiven) model->BSIM4Lwl = 0.0; if (!model->BSIM4LwlcGiven) model->BSIM4Lwlc = model->BSIM4Lwl; - if (!model->BSIM4LminGiven) + if (!model->BSIM4LminGiven) model->BSIM4Lmin = 0.0; - if (!model->BSIM4LmaxGiven) + if (!model->BSIM4LmaxGiven) model->BSIM4Lmax = 1.0; - if (!model->BSIM4WintGiven) + if (!model->BSIM4WintGiven) model->BSIM4Wint = 0.0; - if (!model->BSIM4WlGiven) + if (!model->BSIM4WlGiven) model->BSIM4Wl = 0.0; if (!model->BSIM4WlcGiven) model->BSIM4Wlc = model->BSIM4Wl; - if (!model->BSIM4WlnGiven) + if (!model->BSIM4WlnGiven) model->BSIM4Wln = 1.0; - if (!model->BSIM4WwGiven) + if (!model->BSIM4WwGiven) model->BSIM4Ww = 0.0; if (!model->BSIM4WwcGiven) model->BSIM4Wwc = model->BSIM4Ww; - if (!model->BSIM4WwnGiven) + if (!model->BSIM4WwnGiven) model->BSIM4Wwn = 1.0; - if (!model->BSIM4WwlGiven) + if (!model->BSIM4WwlGiven) model->BSIM4Wwl = 0.0; if (!model->BSIM4WwlcGiven) model->BSIM4Wwlc = model->BSIM4Wwl; - if (!model->BSIM4WminGiven) + if (!model->BSIM4WminGiven) model->BSIM4Wmin = 0.0; - if (!model->BSIM4WmaxGiven) + if (!model->BSIM4WmaxGiven) model->BSIM4Wmax = 1.0; - if (!model->BSIM4dwcGiven) + if (!model->BSIM4dwcGiven) model->BSIM4dwc = model->BSIM4Wint; - if (!model->BSIM4dlcGiven) + if (!model->BSIM4dlcGiven) model->BSIM4dlc = model->BSIM4Lint; - if (!model->BSIM4xlGiven) + if (!model->BSIM4xlGiven) model->BSIM4xl = 0.0; - if (!model->BSIM4xwGiven) + if (!model->BSIM4xwGiven) model->BSIM4xw = 0.0; if (!model->BSIM4dlcigGiven) model->BSIM4dlcig = model->BSIM4Lint; if (!model->BSIM4dlcigdGiven) { - if (model->BSIM4dlcigGiven) + if (model->BSIM4dlcigGiven) model->BSIM4dlcigd = model->BSIM4dlcig; - else + else model->BSIM4dlcigd = model->BSIM4Lint; } if (!model->BSIM4dwjGiven) @@ -2085,8 +2081,8 @@ BSIM4instance **InstArray; model->BSIM4jtsswgs = 0.0; if (!model->BSIM4jtsswgdGiven) model->BSIM4jtsswgd = model->BSIM4jtsswgs; - if (!model->BSIM4jtweffGiven) - model->BSIM4jtweff = 0.0; + if (!model->BSIM4jtweffGiven) + model->BSIM4jtweff = 0.0; if (!model->BSIM4njtsGiven) model->BSIM4njts = 20.0; if (!model->BSIM4njtsswGiven) @@ -2098,21 +2094,21 @@ BSIM4instance **InstArray; if (model->BSIM4njtsGiven) model->BSIM4njtsd = model->BSIM4njts; else - model->BSIM4njtsd = 20.0; + model->BSIM4njtsd = 20.0; } if (!model->BSIM4njtsswdGiven) { if (model->BSIM4njtsswGiven) model->BSIM4njtsswd = model->BSIM4njtssw; else - model->BSIM4njtsswd = 20.0; + model->BSIM4njtsswd = 20.0; } if (!model->BSIM4njtsswgdGiven) { if (model->BSIM4njtsswgGiven) model->BSIM4njtsswgd = model->BSIM4njtsswg; else - model->BSIM4njtsswgd = 20.0; + model->BSIM4njtsswgd = 20.0; } if (!model->BSIM4xtssGiven) model->BSIM4xtss = 0.02; @@ -2137,21 +2133,21 @@ BSIM4instance **InstArray; if (model->BSIM4tnjtsGiven) model->BSIM4tnjtsd = model->BSIM4tnjts; else - model->BSIM4tnjtsd = 0.0; + model->BSIM4tnjtsd = 0.0; } if (!model->BSIM4tnjtsswdGiven) { if (model->BSIM4tnjtsswGiven) model->BSIM4tnjtsswd = model->BSIM4tnjtssw; else - model->BSIM4tnjtsswd = 0.0; + model->BSIM4tnjtsswd = 0.0; } if (!model->BSIM4tnjtsswgdGiven) { if (model->BSIM4tnjtsswgGiven) model->BSIM4tnjtsswgd = model->BSIM4tnjtsswg; - else - model->BSIM4tnjtsswgd = 0.0; + else + model->BSIM4tnjtsswgd = 0.0; } if (!model->BSIM4vtssGiven) model->BSIM4vtss = 10.0; @@ -2167,13 +2163,15 @@ BSIM4instance **InstArray; model->BSIM4vtsswgd = model->BSIM4vtsswgs; if (!model->BSIM4oxideTrapDensityAGiven) - { if (model->BSIM4type == NMOS) + { + if (model->BSIM4type == NMOS) model->BSIM4oxideTrapDensityA = 6.25e41; else model->BSIM4oxideTrapDensityA= 6.188e40; } if (!model->BSIM4oxideTrapDensityBGiven) - { if (model->BSIM4type == NMOS) + { + if (model->BSIM4type == NMOS) model->BSIM4oxideTrapDensityB = 3.125e26; else model->BSIM4oxideTrapDensityB = 1.5e25; @@ -2256,39 +2254,39 @@ BSIM4instance **InstArray; if (!model->BSIM4lodeta0Given) model->BSIM4lodeta0 = 1.0; - /* Well Proximity Effect */ + /* Well Proximity Effect */ if (!model->BSIM4webGiven) - model->BSIM4web = 0.0; + model->BSIM4web = 0.0; if (!model->BSIM4wecGiven) model->BSIM4wec = 0.0; if (!model->BSIM4kvth0weGiven) - model->BSIM4kvth0we = 0.0; + model->BSIM4kvth0we = 0.0; if (!model->BSIM4k2weGiven) - model->BSIM4k2we = 0.0; + model->BSIM4k2we = 0.0; if (!model->BSIM4ku0weGiven) - model->BSIM4ku0we = 0.0; + model->BSIM4ku0we = 0.0; if (!model->BSIM4screfGiven) model->BSIM4scref = 1.0E-6; /* m */ if (!model->BSIM4wpemodGiven) - model->BSIM4wpemod = 0; + model->BSIM4wpemod = 0; else if ((model->BSIM4wpemod != 0) && (model->BSIM4wpemod != 1)) { model->BSIM4wpemod = 0; printf("Warning: wpemod has been set to its default value: 0.\n"); } if (!model->BSIM4lkvth0weGiven) - model->BSIM4lkvth0we = 0; + model->BSIM4lkvth0we = 0; if (!model->BSIM4lk2weGiven) model->BSIM4lk2we = 0; if (!model->BSIM4lku0weGiven) model->BSIM4lku0we = 0; if (!model->BSIM4wkvth0weGiven) - model->BSIM4wkvth0we = 0; + model->BSIM4wkvth0we = 0; if (!model->BSIM4wk2weGiven) model->BSIM4wk2we = 0; if (!model->BSIM4wku0weGiven) model->BSIM4wku0we = 0; if (!model->BSIM4pkvth0weGiven) - model->BSIM4pkvth0we = 0; + model->BSIM4pkvth0we = 0; if (!model->BSIM4pk2weGiven) model->BSIM4pk2we = 0; if (!model->BSIM4pku0weGiven) @@ -2305,11 +2303,9 @@ BSIM4instance **InstArray; for (here = BSIM4instances(model); here != NULL ; here=BSIM4nextInstance(here)) - { - /* allocate a chunk of the state vector */ + { /* allocate a chunk of the state vector */ here->BSIM4states = *states; *states += BSIM4numStates; - /* perform the parameter defaulting */ if (!here->BSIM4lGiven) here->BSIM4l = 5.0e-6; @@ -2317,6 +2313,12 @@ BSIM4instance **InstArray; here->BSIM4w = 5.0e-6; if (!here->BSIM4mGiven) here->BSIM4m = 1.0; + if (!here->BSIM4mult_iGiven) + here->BSIM4mult_i = 1.0; + if (!here->BSIM4mult_qGiven) + here->BSIM4mult_q = 1.0; + if (!here->BSIM4mult_fnGiven) + here->BSIM4mult_fn = here->BSIM4mult_i; if (!here->BSIM4nfGiven) here->BSIM4nf = 1.0; if (!here->BSIM4minGiven) @@ -2352,29 +2354,30 @@ 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) 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; + /* Process instance model selectors, some * may override their global counterparts - */ + */ if (!here->BSIM4rbodyModGiven) here->BSIM4rbodyMod = model->BSIM4rbodyMod; else if ((here->BSIM4rbodyMod != 0) && (here->BSIM4rbodyMod != 1) && (here->BSIM4rbodyMod != 2)) { here->BSIM4rbodyMod = model->BSIM4rbodyMod; printf("Warning: rbodyMod has been set to its global value %d.\n", - model->BSIM4rbodyMod); + model->BSIM4rbodyMod); } if (!here->BSIM4rgateModGiven) here->BSIM4rgateMod = model->BSIM4rgateMod; else if ((here->BSIM4rgateMod != 0) && (here->BSIM4rgateMod != 1) - && (here->BSIM4rgateMod != 2) && (here->BSIM4rgateMod != 3)) + && (here->BSIM4rgateMod != 2) && (here->BSIM4rgateMod != 3)) { here->BSIM4rgateMod = model->BSIM4rgateMod; printf("Warning: rgateMod has been set to its global value %d.\n", model->BSIM4rgateMod); @@ -2382,15 +2385,8 @@ BSIM4instance **InstArray; if (!here->BSIM4geoModGiven) here->BSIM4geoMod = model->BSIM4geoMod; - if (!here->BSIM4rgeoModGiven) - here->BSIM4rgeoMod = model->BSIM4rgeoMod; - else if ((here->BSIM4rgeoMod != 0) && (here->BSIM4rgeoMod != 1)) - { here->BSIM4rgeoMod = model->BSIM4rgeoMod; - printf("Warning: rgeoMod has been set to its global value %d.\n", - model->BSIM4rgeoMod); - } - + here->BSIM4rgeoMod = 0; if (!here->BSIM4trnqsModGiven) here->BSIM4trnqsMod = model->BSIM4trnqsMod; else if ((here->BSIM4trnqsMod != 0) && (here->BSIM4trnqsMod != 1)) @@ -2439,7 +2435,7 @@ BSIM4instance **InstArray; } else if (!here->BSIM4drainSquaresGiven && (here->BSIM4rgeoMod != 0)) { - BSIM4RdseffGeo(here->BSIM4nf*here->BSIM4m, here->BSIM4geoMod, + BSIM4RdseffGeo(here->BSIM4nf, here->BSIM4geoMod, here->BSIM4rgeoMod, here->BSIM4min, here->BSIM4w, model->BSIM4sheetResistance, DMCGeff, DMCIeff, DMDGeff, 0, &Rtot); @@ -2447,8 +2443,7 @@ BSIM4instance **InstArray; createNode = 1; } } - if ( createNode != 0 ) - { if ( here->BSIM4dNodePrime == 0 ) + if ( createNode != 0 && (here->BSIM4dNodePrime == 0)) { error = CKTmkVolt(ckt,&tmp,here->BSIM4name,"drain"); if(error) return(error); here->BSIM4dNodePrime = tmp->number; @@ -2463,11 +2458,10 @@ BSIM4instance **InstArray; } } } - } else { here->BSIM4dNodePrime = here->BSIM4dNode; } - + /* process source series resistance */ createNode = 0; if ( (model->BSIM4rdsMod != 0) @@ -2475,7 +2469,7 @@ BSIM4instance **InstArray; { createNode = 1; } else if (model->BSIM4sheetResistance > 0) - { + { if (here->BSIM4sourceSquaresGiven && here->BSIM4sourceSquares > 0) { @@ -2483,16 +2477,15 @@ BSIM4instance **InstArray; } else if (!here->BSIM4sourceSquaresGiven && (here->BSIM4rgeoMod != 0)) { - BSIM4RdseffGeo(here->BSIM4nf*here->BSIM4m, here->BSIM4geoMod, + BSIM4RdseffGeo(here->BSIM4nf, here->BSIM4geoMod, here->BSIM4rgeoMod, here->BSIM4min, here->BSIM4w, model->BSIM4sheetResistance, DMCGeff, DMCIeff, DMDGeff, 1, &Rtot); if(Rtot > 0) createNode = 1; } - } - if ( createNode != 0 ) - { if ( here->BSIM4sNodePrime == 0 ) + } + if ( createNode != 0 && here->BSIM4sNodePrime == 0) { error = CKTmkVolt(ckt,&tmp,here->BSIM4name,"source"); if(error) return(error); here->BSIM4sNodePrime = tmp->number; @@ -2507,12 +2500,10 @@ BSIM4instance **InstArray; } } } - } else here->BSIM4sNodePrime = here->BSIM4sNode; - if ( here->BSIM4rgateMod > 0 ) - { if ( here->BSIM4gNodePrime == 0 ) + if ((here->BSIM4rgateMod > 0) && (here->BSIM4gNodePrime == 0)) { error = CKTmkVolt(ckt,&tmp,here->BSIM4name,"gate"); if(error) return(error); here->BSIM4gNodePrime = tmp->number; @@ -2527,20 +2518,17 @@ BSIM4instance **InstArray; } } } - } else here->BSIM4gNodePrime = here->BSIM4gNodeExt; - if ( here->BSIM4rgateMod == 3 ) - { if ( here->BSIM4gNodeMid == 0 ) + if ((here->BSIM4rgateMod == 3) && (here->BSIM4gNodeMid == 0)) { error = CKTmkVolt(ckt,&tmp,here->BSIM4name,"midgate"); if(error) return(error); here->BSIM4gNodeMid = tmp->number; } - } else here->BSIM4gNodeMid = here->BSIM4gNodeExt; - + /* internal body nodes for body resistance model */ if ((here->BSIM4rbodyMod ==1) || (here->BSIM4rbodyMod ==2)) @@ -2571,23 +2559,20 @@ BSIM4instance **InstArray; } } else - here->BSIM4dbNode = here->BSIM4bNodePrime = here->BSIM4sbNode - = here->BSIM4bNode; + here->BSIM4dbNode = here->BSIM4bNodePrime = here->BSIM4sbNode + = here->BSIM4bNode; /* NQS node */ - if ( here->BSIM4trnqsMod ) - { if ( here->BSIM4qNode == 0 ) + if ((here->BSIM4trnqsMod) && (here->BSIM4qNode == 0)) { error = CKTmkVolt(ckt,&tmp,here->BSIM4name,"charge"); if(error) return(error); here->BSIM4qNode = tmp->number; } - } - else + else here->BSIM4qNode = 0; - -/* set Sparse Matrix Pointers - * macro to make elements with built-in out-of-memory test */ +/* set Sparse Matrix Pointers +* macro to make elements with built-in out-of-memory test */ #define TSTALLOC(ptr,first,second) \ do { if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ return(E_NOMEM);\ @@ -2619,7 +2604,7 @@ do { if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NUL TSTALLOC(BSIM4SPdpPtr, BSIM4sNodePrime, BSIM4dNodePrime); TSTALLOC(BSIM4QqPtr, BSIM4qNode, BSIM4qNode); - TSTALLOC(BSIM4QbpPtr, BSIM4qNode, BSIM4bNodePrime) ; + TSTALLOC(BSIM4QbpPtr, BSIM4qNode, BSIM4bNodePrime); TSTALLOC(BSIM4QdpPtr, BSIM4qNode, BSIM4dNodePrime); TSTALLOC(BSIM4QspPtr, BSIM4qNode, BSIM4sNodePrime); TSTALLOC(BSIM4QgpPtr, BSIM4qNode, BSIM4gNodePrime); @@ -2645,7 +2630,7 @@ do { if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NUL TSTALLOC(BSIM4GEgmPtr, BSIM4gNodeExt, BSIM4gNodeMid); TSTALLOC(BSIM4SPgmPtr, BSIM4sNodePrime, BSIM4gNodeMid); TSTALLOC(BSIM4BPgmPtr, BSIM4bNodePrime, BSIM4gNodeMid); - } + } if ((here->BSIM4rbodyMod ==1) || (here->BSIM4rbodyMod ==2)) { TSTALLOC(BSIM4DPdbPtr, BSIM4dNodePrime, BSIM4dbNode); @@ -2718,14 +2703,13 @@ do { if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NUL #endif return(OK); -} +} int BSIM4unsetup( -GENmodel *inModel, -CKTcircuit *ckt) + GENmodel *inModel, + CKTcircuit *ckt) { -#ifndef HAS_BATCHSIM BSIM4model *model; BSIM4instance *here; @@ -2780,6 +2764,5 @@ CKTcircuit *ckt) here->BSIM4dNodePrime = 0; } } -#endif return OK; } diff --git a/src/spicelib/devices/bsim4/b4temp.c b/src/spicelib/devices/bsim4/b4temp.c index 1262811db..172bb74ad 100644 --- a/src/spicelib/devices/bsim4/b4temp.c +++ b/src/spicelib/devices/bsim4/b4temp.c @@ -1,31 +1,26 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* Licensed under Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the license at http://opensource.org/licenses/ECL-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -*/ +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc +*/ #include "ngspice/ngspice.h" #include "ngspice/smpdefs.h" #include "ngspice/cktdefs.h" @@ -94,91 +89,92 @@ double n,n0, Vgsteff, Vgs_eff, niter, toxpf, toxpi, Tcen, toxe, epsrox, vddeot; double vtfbphi2eot, phieot, TempRatioeot, Vtm0eot, Vtmeot,vbieot; int Size_Not_Found, i; +int Fatal_Flag = 0; /* loop through all the BSIM4 device models */ for (; model != NULL; model = BSIM4nextModel(model)) { Temp = ckt->CKTtemp; if (model->BSIM4SbulkJctPotential < 0.1) - { model->BSIM4SbulkJctPotential = 0.1; - fprintf(stderr, "Given pbs is less than 0.1. Pbs is set to 0.1.\n"); - } + { model->BSIM4SbulkJctPotential = 0.1; + fprintf(stderr, "Given pbs is less than 0.1. Pbs is set to 0.1.\n"); + } if (model->BSIM4SsidewallJctPotential < 0.1) - { model->BSIM4SsidewallJctPotential = 0.1; - fprintf(stderr, "Given pbsws is less than 0.1. Pbsws is set to 0.1.\n"); - } + { model->BSIM4SsidewallJctPotential = 0.1; + fprintf(stderr, "Given pbsws is less than 0.1. Pbsws is set to 0.1.\n"); + } if (model->BSIM4SGatesidewallJctPotential < 0.1) - { model->BSIM4SGatesidewallJctPotential = 0.1; - fprintf(stderr, "Given pbswgs is less than 0.1. Pbswgs is set to 0.1.\n"); - } + { model->BSIM4SGatesidewallJctPotential = 0.1; + fprintf(stderr, "Given pbswgs is less than 0.1. Pbswgs is set to 0.1.\n"); + } - if (model->BSIM4DbulkJctPotential < 0.1) - { model->BSIM4DbulkJctPotential = 0.1; - fprintf(stderr, "Given pbd is less than 0.1. Pbd is set to 0.1.\n"); - } - if (model->BSIM4DsidewallJctPotential < 0.1) - { model->BSIM4DsidewallJctPotential = 0.1; - fprintf(stderr, "Given pbswd is less than 0.1. Pbswd is set to 0.1.\n"); - } - if (model->BSIM4DGatesidewallJctPotential < 0.1) - { model->BSIM4DGatesidewallJctPotential = 0.1; - fprintf(stderr, "Given pbswgd is less than 0.1. Pbswgd is set to 0.1.\n"); - } + if (model->BSIM4DbulkJctPotential < 0.1) + { model->BSIM4DbulkJctPotential = 0.1; + fprintf(stderr, "Given pbd is less than 0.1. Pbd is set to 0.1.\n"); + } + if (model->BSIM4DsidewallJctPotential < 0.1) + { model->BSIM4DsidewallJctPotential = 0.1; + fprintf(stderr, "Given pbswd is less than 0.1. Pbswd is set to 0.1.\n"); + } + if (model->BSIM4DGatesidewallJctPotential < 0.1) + { model->BSIM4DGatesidewallJctPotential = 0.1; + fprintf(stderr, "Given pbswgd is less than 0.1. Pbswgd is set to 0.1.\n"); + } - if(model->BSIM4mtrlMod == 0) + if(model->BSIM4mtrlMod == 0) + { + if ((model->BSIM4toxeGiven) && (model->BSIM4toxpGiven) && (model->BSIM4dtoxGiven) + && (model->BSIM4toxe != (model->BSIM4toxp + model->BSIM4dtox))) + { printf("Warning: toxe, toxp and dtox all given and toxe != toxp + dtox; dtox ignored.\n"); + } + else if ((model->BSIM4toxeGiven) && (!model->BSIM4toxpGiven)) + { model->BSIM4toxp = model->BSIM4toxe - model->BSIM4dtox; + } + else if ((!model->BSIM4toxeGiven) && (model->BSIM4toxpGiven)) { - if ((model->BSIM4toxeGiven) && (model->BSIM4toxpGiven) && (model->BSIM4dtoxGiven) - && (model->BSIM4toxe != (model->BSIM4toxp + model->BSIM4dtox))) - { printf("Warning: toxe, toxp and dtox all given and toxe != toxp + dtox; dtox ignored.\n"); - } - else if ((model->BSIM4toxeGiven) && (!model->BSIM4toxpGiven)) - { model->BSIM4toxp = model->BSIM4toxe - model->BSIM4dtox; - } - else if ((!model->BSIM4toxeGiven) && (model->BSIM4toxpGiven)) - { - model->BSIM4toxe = model->BSIM4toxp + model->BSIM4dtox; - if (!model->BSIM4toxmGiven) /* v4.7 */ - model->BSIM4toxm = model->BSIM4toxe; - } - if (!model->BSIM4cfGiven) /* v4.8.2 */ - model->BSIM4cf = 2.0 * model->BSIM4epsrox * EPS0 / PI - * log(1.0 + 0.4e-6 / model->BSIM4toxe); + model->BSIM4toxe = model->BSIM4toxp + model->BSIM4dtox; + if (!model->BSIM4toxmGiven) /* v4.7 */ + model->BSIM4toxm = model->BSIM4toxe; } - else if(model->BSIM4mtrlCompatMod != 0) /* v4.7 */ + } + + else if(model->BSIM4mtrlCompatMod != 0) /* v4.7 */ + { + T0 = model->BSIM4epsrox / 3.9; + if ((model->BSIM4eotGiven) && (model->BSIM4toxpGiven) && (model->BSIM4dtoxGiven) + && (ABS(model->BSIM4eot * T0 - (model->BSIM4toxp + model->BSIM4dtox)) > 1.0e-20)) { - T0 = model->BSIM4epsrox / 3.9; - if ((model->BSIM4eotGiven) && (model->BSIM4toxpGiven) && (model->BSIM4dtoxGiven) - && (ABS(model->BSIM4eot * T0 - (model->BSIM4toxp + model->BSIM4dtox)) > 1.0e-20)) - { - printf("Warning: eot, toxp and dtox all given and eot * EPSROX / 3.9 != toxp + dtox; dtox ignored.\n"); - } - else if ((model->BSIM4eotGiven) && (!model->BSIM4toxpGiven)) - model->BSIM4toxp = T0 * model->BSIM4eot - model->BSIM4dtox; - else if ((!model->BSIM4eotGiven) && (model->BSIM4toxpGiven)){ - model->BSIM4eot = (model->BSIM4toxp + model->BSIM4dtox) / T0; - if (!model->BSIM4toxmGiven) - model->BSIM4toxm = model->BSIM4eot; - } + printf("Warning: eot, toxp and dtox all given and eot * EPSROX / 3.9 != toxp + dtox; dtox ignored.\n"); } + else if ((model->BSIM4eotGiven) && (!model->BSIM4toxpGiven)) + model->BSIM4toxp = T0 * model->BSIM4eot - model->BSIM4dtox; + else if ((!model->BSIM4eotGiven) && (model->BSIM4toxpGiven)){ + model->BSIM4eot = (model->BSIM4toxp + model->BSIM4dtox) / T0; + if (!model->BSIM4toxmGiven) + model->BSIM4toxm = model->BSIM4eot; + } + } - if(model->BSIM4mtrlMod) - { - epsrox = 3.9; - toxe = model->BSIM4eot; - epssub = EPS0 * model->BSIM4epsrsub; - } - else - { - epsrox = model->BSIM4epsrox; - toxe = model->BSIM4toxe; - epssub = EPSSI; - } + if(model->BSIM4mtrlMod) + { + epsrox = 3.9; + toxe = model->BSIM4eot; + epssub = EPS0 * model->BSIM4epsrsub; + } + else + { + epsrox = model->BSIM4epsrox; + toxe = model->BSIM4toxe; + epssub = EPSSI; + } + if(!model->BSIM4cfGiven) + model->BSIM4cf = 2.0 * epsrox * EPS0 / PI + * log(1.0 + 0.4e-6 /toxe); + model->BSIM4coxe = epsrox * EPS0 / toxe; + if(model->BSIM4mtrlMod == 0 || model->BSIM4mtrlCompatMod != 0) + model->BSIM4coxp = model->BSIM4epsrox * EPS0 / model->BSIM4toxp; - model->BSIM4coxe = epsrox * EPS0 / toxe; - if(model->BSIM4mtrlMod == 0 || model->BSIM4mtrlCompatMod != 0) - model->BSIM4coxp = model->BSIM4epsrox * EPS0 / model->BSIM4toxp; - - if (!model->BSIM4cgdoGiven) + if (!model->BSIM4cgdoGiven) { if (model->BSIM4dlcGiven && (model->BSIM4dlc > 0.0)) model->BSIM4cgdo = model->BSIM4dlc * model->BSIM4coxe - model->BSIM4cgdl ; @@ -194,60 +190,53 @@ int Size_Not_Found, i; } if (!model->BSIM4cgboGiven) model->BSIM4cgbo = 2.0 * model->BSIM4dwc * model->BSIM4coxe; - - struct bsim4SizeDependParam *p = model->pSizeDependParamKnot; - while (p) { - struct bsim4SizeDependParam *next_p = p->pNext; - FREE(p); - p = next_p; - } model->pSizeDependParamKnot = NULL; pLastKnot = NULL; - Tnom = model->BSIM4tnom; - TRatio = Temp / Tnom; + Tnom = model->BSIM4tnom; + TRatio = Temp / Tnom; - model->BSIM4vcrit = CONSTvt0 * log(CONSTvt0 / (CONSTroot2 * 1.0e-14)); + model->BSIM4vcrit = CONSTvt0 * log(CONSTvt0 / (CONSTroot2 * 1.0e-14)); model->BSIM4factor1 = sqrt(epssub / (epsrox * EPS0)* toxe); Vtm0 = model->BSIM4vtm0 = KboQ * Tnom; - if(model->BSIM4mtrlMod==0) - { - Eg0 = 1.16 - 7.02e-4 * Tnom * Tnom / (Tnom + 1108.0); + if(model->BSIM4mtrlMod==0) + { + Eg0 = 1.16 - 7.02e-4 * Tnom * Tnom / (Tnom + 1108.0); ni = 1.45e10 * (Tnom / 300.15) * sqrt(Tnom / 300.15) * exp(21.5565981 - Eg0 / (2.0 * Vtm0)); - } - else - { - Eg0 = model->BSIM4bg0sub - model->BSIM4tbgasub * Tnom * Tnom + } + else + { + Eg0 = model->BSIM4bg0sub - model->BSIM4tbgasub * Tnom * Tnom / (Tnom + model->BSIM4tbgbsub); - T0 = model->BSIM4bg0sub - model->BSIM4tbgasub * 90090.0225 + T0 = model->BSIM4bg0sub - model->BSIM4tbgasub * 90090.0225 / (300.15 + model->BSIM4tbgbsub); - ni = model->BSIM4ni0sub * (Tnom / 300.15) * sqrt(Tnom / 300.15) + ni = model->BSIM4ni0sub * (Tnom / 300.15) * sqrt(Tnom / 300.15) * exp((T0 - Eg0) / (2.0 * Vtm0)); - } + } - model->BSIM4Eg0 = Eg0; + model->BSIM4Eg0 = Eg0; model->BSIM4vtm = KboQ * Temp; - if(model->BSIM4mtrlMod == 0) - Eg = 1.16 - 7.02e-4 * Temp * Temp / (Temp + 1108.0); - else - Eg = model->BSIM4bg0sub - model->BSIM4tbgasub * Temp * Temp + if(model->BSIM4mtrlMod == 0) + Eg = 1.16 - 7.02e-4 * Temp * Temp / (Temp + 1108.0); + else + Eg = model->BSIM4bg0sub - model->BSIM4tbgasub * Temp * Temp / (Temp + model->BSIM4tbgbsub); - if (Temp != Tnom) - { T0 = Eg0 / Vtm0 - Eg / model->BSIM4vtm; - T1 = log(Temp / Tnom); - T2 = T0 + model->BSIM4SjctTempExponent * T1; - T3 = exp(T2 / model->BSIM4SjctEmissionCoeff); - model->BSIM4SjctTempSatCurDensity = model->BSIM4SjctSatCurDensity - * T3; - model->BSIM4SjctSidewallTempSatCurDensity - = model->BSIM4SjctSidewallSatCurDensity * T3; + if (Temp != Tnom) + { T0 = Eg0 / Vtm0 - Eg / model->BSIM4vtm; + T1 = log(Temp / Tnom); + T2 = T0 + model->BSIM4SjctTempExponent * T1; + T3 = exp(T2 / model->BSIM4SjctEmissionCoeff); + model->BSIM4SjctTempSatCurDensity = model->BSIM4SjctSatCurDensity + * T3; + model->BSIM4SjctSidewallTempSatCurDensity + = model->BSIM4SjctSidewallSatCurDensity * T3; model->BSIM4SjctGateSidewallTempSatCurDensity = model->BSIM4SjctGateSidewallSatCurDensity * T3; - T2 = T0 + model->BSIM4DjctTempExponent * T1; + T2 = T0 + model->BSIM4DjctTempExponent * T1; T3 = exp(T2 / model->BSIM4DjctEmissionCoeff); model->BSIM4DjctTempSatCurDensity = model->BSIM4DjctSatCurDensity * T3; @@ -255,11 +244,11 @@ int Size_Not_Found, i; = model->BSIM4DjctSidewallSatCurDensity * T3; model->BSIM4DjctGateSidewallTempSatCurDensity = model->BSIM4DjctGateSidewallSatCurDensity * T3; - } - else - { model->BSIM4SjctTempSatCurDensity = model->BSIM4SjctSatCurDensity; - model->BSIM4SjctSidewallTempSatCurDensity - = model->BSIM4SjctSidewallSatCurDensity; + } + else + { model->BSIM4SjctTempSatCurDensity = model->BSIM4SjctSatCurDensity; + model->BSIM4SjctSidewallTempSatCurDensity + = model->BSIM4SjctSidewallSatCurDensity; model->BSIM4SjctGateSidewallTempSatCurDensity = model->BSIM4SjctGateSidewallSatCurDensity; model->BSIM4DjctTempSatCurDensity = model->BSIM4DjctSatCurDensity; @@ -267,81 +256,81 @@ int Size_Not_Found, i; = model->BSIM4DjctSidewallSatCurDensity; model->BSIM4DjctGateSidewallTempSatCurDensity = model->BSIM4DjctGateSidewallSatCurDensity; - } + } - if (model->BSIM4SjctTempSatCurDensity < 0.0) - model->BSIM4SjctTempSatCurDensity = 0.0; - if (model->BSIM4SjctSidewallTempSatCurDensity < 0.0) - model->BSIM4SjctSidewallTempSatCurDensity = 0.0; - if (model->BSIM4SjctGateSidewallTempSatCurDensity < 0.0) - model->BSIM4SjctGateSidewallTempSatCurDensity = 0.0; - if (model->BSIM4DjctTempSatCurDensity < 0.0) - model->BSIM4DjctTempSatCurDensity = 0.0; - if (model->BSIM4DjctSidewallTempSatCurDensity < 0.0) - model->BSIM4DjctSidewallTempSatCurDensity = 0.0; - if (model->BSIM4DjctGateSidewallTempSatCurDensity < 0.0) - model->BSIM4DjctGateSidewallTempSatCurDensity = 0.0; + if (model->BSIM4SjctTempSatCurDensity < 0.0) + model->BSIM4SjctTempSatCurDensity = 0.0; + if (model->BSIM4SjctSidewallTempSatCurDensity < 0.0) + model->BSIM4SjctSidewallTempSatCurDensity = 0.0; + if (model->BSIM4SjctGateSidewallTempSatCurDensity < 0.0) + model->BSIM4SjctGateSidewallTempSatCurDensity = 0.0; + if (model->BSIM4DjctTempSatCurDensity < 0.0) + model->BSIM4DjctTempSatCurDensity = 0.0; + if (model->BSIM4DjctSidewallTempSatCurDensity < 0.0) + model->BSIM4DjctSidewallTempSatCurDensity = 0.0; + if (model->BSIM4DjctGateSidewallTempSatCurDensity < 0.0) + model->BSIM4DjctGateSidewallTempSatCurDensity = 0.0; - /* Temperature dependence of D/B and S/B diode capacitance begins */ - delTemp = ckt->CKTtemp - model->BSIM4tnom; - T0 = model->BSIM4tcj * delTemp; - if (T0 >= -1.0) - { model->BSIM4SunitAreaTempJctCap = model->BSIM4SunitAreaJctCap *(1.0 + T0); /*bug_fix -JX */ + /* Temperature dependence of D/B and S/B diode capacitance begins */ + delTemp = ckt->CKTtemp - model->BSIM4tnom; + T0 = model->BSIM4tcj * delTemp; + if (T0 >= -1.0) + { model->BSIM4SunitAreaTempJctCap = model->BSIM4SunitAreaJctCap *(1.0 + T0); /*bug_fix -JX */ model->BSIM4DunitAreaTempJctCap = model->BSIM4DunitAreaJctCap *(1.0 + T0); - } - else - { if (model->BSIM4SunitAreaJctCap > 0.0) - { model->BSIM4SunitAreaTempJctCap = 0.0; - fprintf(stderr, "Temperature effect has caused cjs to be negative. Cjs is clamped to zero.\n"); + } + else + { if (model->BSIM4SunitAreaJctCap > 0.0) + { model->BSIM4SunitAreaTempJctCap = 0.0; + fprintf(stderr, "Temperature effect has caused cjs to be negative. Cjs is clamped to zero.\n"); } - if (model->BSIM4DunitAreaJctCap > 0.0) + if (model->BSIM4DunitAreaJctCap > 0.0) { model->BSIM4DunitAreaTempJctCap = 0.0; fprintf(stderr, "Temperature effect has caused cjd to be negative. Cjd is clamped to zero.\n"); } - } + } T0 = model->BSIM4tcjsw * delTemp; - if (model->BSIM4SunitLengthSidewallJctCap < 0.0)/*4.6.2*/ - {model->BSIM4SunitLengthSidewallJctCap = 0.0; - fprintf(stderr, "CJSWS is negative. Cjsws is clamped to zero.\n");} - if (model->BSIM4DunitLengthSidewallJctCap < 0.0) - {model->BSIM4DunitLengthSidewallJctCap = 0.0; - fprintf(stderr, "CJSWD is negative. Cjswd is clamped to zero.\n");} - if (T0 >= -1.0) - { model->BSIM4SunitLengthSidewallTempJctCap = model->BSIM4SunitLengthSidewallJctCap *(1.0 + T0); + if (model->BSIM4SunitLengthSidewallJctCap < 0.0)/*4.6.2*/ + {model->BSIM4SunitLengthSidewallJctCap = 0.0; + fprintf(stderr, "CJSWS is negative. Cjsws is clamped to zero.\n");} + if (model->BSIM4DunitLengthSidewallJctCap < 0.0) + {model->BSIM4DunitLengthSidewallJctCap = 0.0; + fprintf(stderr, "CJSWD is negative. Cjswd is clamped to zero.\n");} + if (T0 >= -1.0) + { model->BSIM4SunitLengthSidewallTempJctCap = model->BSIM4SunitLengthSidewallJctCap *(1.0 + T0); model->BSIM4DunitLengthSidewallTempJctCap = model->BSIM4DunitLengthSidewallJctCap *(1.0 + T0); + } + else + { if (model->BSIM4SunitLengthSidewallJctCap > 0.0) + { model->BSIM4SunitLengthSidewallTempJctCap = 0.0; + fprintf(stderr, "Temperature effect has caused cjsws to be negative. Cjsws is clamped to zero.\n"); } - else - { if (model->BSIM4SunitLengthSidewallJctCap > 0.0) - { model->BSIM4SunitLengthSidewallTempJctCap = 0.0; - fprintf(stderr, "Temperature effect has caused cjsws to be negative. Cjsws is clamped to zero.\n"); - } - if (model->BSIM4DunitLengthSidewallJctCap > 0.0) + if (model->BSIM4DunitLengthSidewallJctCap > 0.0) { model->BSIM4DunitLengthSidewallTempJctCap = 0.0; fprintf(stderr, "Temperature effect has caused cjswd to be negative. Cjswd is clamped to zero.\n"); } - } + } T0 = model->BSIM4tcjswg * delTemp; - if (T0 >= -1.0) - { model->BSIM4SunitLengthGateSidewallTempJctCap = model->BSIM4SunitLengthGateSidewallJctCap *(1.0 + T0); + if (T0 >= -1.0) + { model->BSIM4SunitLengthGateSidewallTempJctCap = model->BSIM4SunitLengthGateSidewallJctCap *(1.0 + T0); model->BSIM4DunitLengthGateSidewallTempJctCap = model->BSIM4DunitLengthGateSidewallJctCap *(1.0 + T0); + } + else + { if (model->BSIM4SunitLengthGateSidewallJctCap > 0.0) + { model->BSIM4SunitLengthGateSidewallTempJctCap = 0.0; + fprintf(stderr, "Temperature effect has caused cjswgs to be negative. Cjswgs is clamped to zero.\n"); } - else - { if (model->BSIM4SunitLengthGateSidewallJctCap > 0.0) - { model->BSIM4SunitLengthGateSidewallTempJctCap = 0.0; - fprintf(stderr, "Temperature effect has caused cjswgs to be negative. Cjswgs is clamped to zero.\n"); - } - if (model->BSIM4DunitLengthGateSidewallJctCap > 0.0) + if (model->BSIM4DunitLengthGateSidewallJctCap > 0.0) { model->BSIM4DunitLengthGateSidewallTempJctCap = 0.0; fprintf(stderr, "Temperature effect has caused cjswgd to be negative. Cjswgd is clamped to zero.\n"); } - } + } model->BSIM4PhiBS = model->BSIM4SbulkJctPotential - - model->BSIM4tpb * delTemp; + - model->BSIM4tpb * delTemp; if (model->BSIM4PhiBS < 0.01) - { model->BSIM4PhiBS = 0.01; - fprintf(stderr, "Temperature effect has caused pbs to be less than 0.01. Pbs is clamped to 0.01.\n"); - } + { model->BSIM4PhiBS = 0.01; + fprintf(stderr, "Temperature effect has caused pbs to be less than 0.01. Pbs is clamped to 0.01.\n"); + } model->BSIM4PhiBD = model->BSIM4DbulkJctPotential - model->BSIM4tpb * delTemp; if (model->BSIM4PhiBD < 0.01) @@ -351,26 +340,26 @@ int Size_Not_Found, i; model->BSIM4PhiBSWS = model->BSIM4SsidewallJctPotential - model->BSIM4tpbsw * delTemp; - if (model->BSIM4PhiBSWS <= 0.01) - { model->BSIM4PhiBSWS = 0.01; - fprintf(stderr, "Temperature effect has caused pbsws to be less than 0.01. Pbsws is clamped to 0.01.\n"); - } + if (model->BSIM4PhiBSWS < 0.01) + { model->BSIM4PhiBSWS = 0.01; + fprintf(stderr, "Temperature effect has caused pbsws to be less than 0.01. Pbsws is clamped to 0.01.\n"); + } model->BSIM4PhiBSWD = model->BSIM4DsidewallJctPotential - model->BSIM4tpbsw * delTemp; - if (model->BSIM4PhiBSWD <= 0.01) + if (model->BSIM4PhiBSWD < 0.01) { model->BSIM4PhiBSWD = 0.01; fprintf(stderr, "Temperature effect has caused pbswd to be less than 0.01. Pbswd is clamped to 0.01.\n"); } - model->BSIM4PhiBSWGS = model->BSIM4SGatesidewallJctPotential + model->BSIM4PhiBSWGS = model->BSIM4SGatesidewallJctPotential - model->BSIM4tpbswg * delTemp; - if (model->BSIM4PhiBSWGS <= 0.01) - { model->BSIM4PhiBSWGS = 0.01; - fprintf(stderr, "Temperature effect has caused pbswgs to be less than 0.01. Pbswgs is clamped to 0.01.\n"); - } + if (model->BSIM4PhiBSWGS < 0.01) + { model->BSIM4PhiBSWGS = 0.01; + fprintf(stderr, "Temperature effect has caused pbswgs to be less than 0.01. Pbswgs is clamped to 0.01.\n"); + } model->BSIM4PhiBSWGD = model->BSIM4DGatesidewallJctPotential - model->BSIM4tpbswg * delTemp; - if (model->BSIM4PhiBSWGD <= 0.01) + if (model->BSIM4PhiBSWGD < 0.01) { model->BSIM4PhiBSWGD = 0.01; fprintf(stderr, "Temperature effect has caused pbswgd to be less than 0.01. Pbswgd is clamped to 0.01.\n"); } /* End of junction capacitance */ @@ -384,7 +373,7 @@ int Size_Not_Found, i; { model->BSIM4ijthsfwd = 0.0; fprintf(stderr, "Ijthsfwd reset to %g.\n", model->BSIM4ijthsfwd); } - if (model->BSIM4ijthdrev <= 0.0) + if (model->BSIM4ijthdrev <= 0.0) { model->BSIM4ijthdrev = 0.0; fprintf(stderr, "Ijthdrev reset to %g.\n", model->BSIM4ijthdrev); } @@ -425,33 +414,33 @@ int Size_Not_Found, i; /* loop through all the instances of the model */ for (here = BSIM4instances(model); here != NULL; here = BSIM4nextInstance(here)) - { - pSizeDependParamKnot = model->pSizeDependParamKnot; - Size_Not_Found = 1; - while ((pSizeDependParamKnot != NULL) && Size_Not_Found) - { if ((here->BSIM4l == pSizeDependParamKnot->Length) - && (here->BSIM4w == pSizeDependParamKnot->Width) - && (here->BSIM4nf == pSizeDependParamKnot->NFinger)) + { pSizeDependParamKnot = model->pSizeDependParamKnot; + Size_Not_Found = 1; + while ((pSizeDependParamKnot != NULL) && Size_Not_Found) + { if ((here->BSIM4l == pSizeDependParamKnot->Length) + && (here->BSIM4w == pSizeDependParamKnot->Width) + && (here->BSIM4nf == pSizeDependParamKnot->NFinger)) { Size_Not_Found = 0; - here->pParam = pSizeDependParamKnot; - pParam = here->pParam; /*bug-fix */ - } - else - { pLastKnot = pSizeDependParamKnot; - pSizeDependParamKnot = pSizeDependParamKnot->pNext; - } + here->pParam = pSizeDependParamKnot; + pParam = here->pParam; /*bug-fix */ + } + else + { pLastKnot = pSizeDependParamKnot; + pSizeDependParamKnot = pSizeDependParamKnot->pNext; + } } - /* stress effect */ - Ldrn = here->BSIM4l; - Wdrn = here->BSIM4w / here->BSIM4nf; + /* stress effect */ + Ldrn = here->BSIM4l; + Wdrn = here->BSIM4w / here->BSIM4nf; - if (Size_Not_Found) - { pParam = TMALLOC(struct bsim4SizeDependParam, 1); + if (Size_Not_Found) + { pParam = (struct bsim4SizeDependParam *)malloc( + sizeof(struct bsim4SizeDependParam)); if (pLastKnot == NULL) - model->pSizeDependParamKnot = pParam; + model->pSizeDependParamKnot = pParam; else - pLastKnot->pNext = pParam; + pLastKnot->pNext = pParam; pParam->pNext = NULL; here->pParam = pParam; @@ -482,130 +471,144 @@ int Size_Not_Found, i; pParam->BSIM4leff = Lnew - 2.0 * pParam->BSIM4dl; if (pParam->BSIM4leff <= 0.0) - { - SPfrontEnd->IFerrorf(ERR_FATAL, + { IFuid namarray[2]; + namarray[0] = model->BSIM4modName; + namarray[1] = here->BSIM4name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, "BSIM4: mosfet %s, model %s: Effective channel length <= 0", - model->BSIM4modName, here->BSIM4name); + namarray); return(E_BADPARM); } pParam->BSIM4weff = Wnew - 2.0 * pParam->BSIM4dw; if (pParam->BSIM4weff <= 0.0) - { - SPfrontEnd->IFerrorf(ERR_FATAL, + { IFuid namarray[2]; + namarray[0] = model->BSIM4modName; + namarray[1] = here->BSIM4name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, "BSIM4: mosfet %s, model %s: Effective channel width <= 0", - model->BSIM4modName, here->BSIM4name); + namarray); return(E_BADPARM); } pParam->BSIM4leffCV = Lnew - 2.0 * pParam->BSIM4dlc; if (pParam->BSIM4leffCV <= 0.0) - { - SPfrontEnd->IFerrorf(ERR_FATAL, + { IFuid namarray[2]; + namarray[0] = model->BSIM4modName; + namarray[1] = here->BSIM4name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, "BSIM4: mosfet %s, model %s: Effective channel length for C-V <= 0", - model->BSIM4modName, here->BSIM4name); + namarray); return(E_BADPARM); } pParam->BSIM4weffCV = Wnew - 2.0 * pParam->BSIM4dwc; if (pParam->BSIM4weffCV <= 0.0) - { - SPfrontEnd->IFerrorf(ERR_FATAL, + { IFuid namarray[2]; + namarray[0] = model->BSIM4modName; + namarray[1] = here->BSIM4name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, "BSIM4: mosfet %s, model %s: Effective channel width for C-V <= 0", - model->BSIM4modName, here->BSIM4name); + namarray); return(E_BADPARM); } pParam->BSIM4weffCJ = Wnew - 2.0 * pParam->BSIM4dwj; if (pParam->BSIM4weffCJ <= 0.0) - { - SPfrontEnd->IFerrorf(ERR_FATAL, + { IFuid namarray[2]; + namarray[0] = model->BSIM4modName; + namarray[1] = here->BSIM4name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, "BSIM4: mosfet %s, model %s: Effective channel width for S/D junctions <= 0", - model->BSIM4modName, here->BSIM4name); + namarray); return(E_BADPARM); } - if (model->BSIM4binUnit == 1) - { Inv_L = 1.0e-6 / pParam->BSIM4leff; - Inv_W = 1.0e-6 / pParam->BSIM4weff; - Inv_LW = 1.0e-12 / (pParam->BSIM4leff - * pParam->BSIM4weff); - } - else - { Inv_L = 1.0 / pParam->BSIM4leff; - Inv_W = 1.0 / pParam->BSIM4weff; - Inv_LW = 1.0 / (pParam->BSIM4leff - * pParam->BSIM4weff); - } - pParam->BSIM4cdsc = model->BSIM4cdsc - + model->BSIM4lcdsc * Inv_L - + model->BSIM4wcdsc * Inv_W - + model->BSIM4pcdsc * Inv_LW; - pParam->BSIM4cdscb = model->BSIM4cdscb - + model->BSIM4lcdscb * Inv_L - + model->BSIM4wcdscb * Inv_W - + model->BSIM4pcdscb * Inv_LW; + if (model->BSIM4binUnit == 1) + { Inv_L = 1.0e-6 / pParam->BSIM4leff; + Inv_W = 1.0e-6 / pParam->BSIM4weff; + Inv_LW = 1.0e-12 / (pParam->BSIM4leff + * pParam->BSIM4weff); + } + else + { Inv_L = 1.0 / pParam->BSIM4leff; + Inv_W = 1.0 / pParam->BSIM4weff; + Inv_LW = 1.0 / (pParam->BSIM4leff + * pParam->BSIM4weff); + } + pParam->BSIM4cdsc = model->BSIM4cdsc + + model->BSIM4lcdsc * Inv_L + + model->BSIM4wcdsc * Inv_W + + model->BSIM4pcdsc * Inv_LW; + pParam->BSIM4cdscb = model->BSIM4cdscb + + model->BSIM4lcdscb * Inv_L + + model->BSIM4wcdscb * Inv_W + + model->BSIM4pcdscb * Inv_LW; - pParam->BSIM4cdscd = model->BSIM4cdscd - + model->BSIM4lcdscd * Inv_L - + model->BSIM4wcdscd * Inv_W - + model->BSIM4pcdscd * Inv_LW; + pParam->BSIM4cdscd = model->BSIM4cdscd + + model->BSIM4lcdscd * Inv_L + + model->BSIM4wcdscd * Inv_W + + model->BSIM4pcdscd * Inv_LW; - pParam->BSIM4cit = model->BSIM4cit - + model->BSIM4lcit * Inv_L - + model->BSIM4wcit * Inv_W - + model->BSIM4pcit * Inv_LW; - pParam->BSIM4nfactor = model->BSIM4nfactor - + model->BSIM4lnfactor * Inv_L - + model->BSIM4wnfactor * Inv_W - + model->BSIM4pnfactor * Inv_LW; - pParam->BSIM4tnfactor = model->BSIM4tnfactor /* v4.7 */ - + model->BSIM4ltnfactor * Inv_L - + model->BSIM4wtnfactor * Inv_W - + model->BSIM4ptnfactor * Inv_LW; - pParam->BSIM4xj = model->BSIM4xj - + model->BSIM4lxj * Inv_L - + model->BSIM4wxj * Inv_W - + model->BSIM4pxj * Inv_LW; - pParam->BSIM4vsat = model->BSIM4vsat - + model->BSIM4lvsat * Inv_L - + model->BSIM4wvsat * Inv_W - + model->BSIM4pvsat * Inv_LW; - pParam->BSIM4at = model->BSIM4at - + model->BSIM4lat * Inv_L - + model->BSIM4wat * Inv_W - + model->BSIM4pat * Inv_LW; - pParam->BSIM4a0 = model->BSIM4a0 - + model->BSIM4la0 * Inv_L - + model->BSIM4wa0 * Inv_W - + model->BSIM4pa0 * Inv_LW; + pParam->BSIM4cit = model->BSIM4cit + + model->BSIM4lcit * Inv_L + + model->BSIM4wcit * Inv_W + + model->BSIM4pcit * Inv_LW; + pParam->BSIM4nfactor = model->BSIM4nfactor + + model->BSIM4lnfactor * Inv_L + + model->BSIM4wnfactor * Inv_W + + model->BSIM4pnfactor * Inv_LW; + pParam->BSIM4tnfactor = model->BSIM4tnfactor /* v4.7 */ + + model->BSIM4ltnfactor * Inv_L + + model->BSIM4wtnfactor * Inv_W + + model->BSIM4ptnfactor * Inv_LW; + pParam->BSIM4xj = model->BSIM4xj + + model->BSIM4lxj * Inv_L + + model->BSIM4wxj * Inv_W + + model->BSIM4pxj * Inv_LW; + pParam->BSIM4vsat = model->BSIM4vsat + + model->BSIM4lvsat * Inv_L + + model->BSIM4wvsat * Inv_W + + model->BSIM4pvsat * Inv_LW; + pParam->BSIM4at = model->BSIM4at + + model->BSIM4lat * Inv_L + + model->BSIM4wat * Inv_W + + model->BSIM4pat * Inv_LW; + pParam->BSIM4a0 = model->BSIM4a0 + + model->BSIM4la0 * Inv_L + + model->BSIM4wa0 * Inv_W + + model->BSIM4pa0 * Inv_LW; - pParam->BSIM4ags = model->BSIM4ags - + model->BSIM4lags * Inv_L - + model->BSIM4wags * Inv_W - + model->BSIM4pags * Inv_LW; + pParam->BSIM4ags = model->BSIM4ags + + model->BSIM4lags * Inv_L + + model->BSIM4wags * Inv_W + + model->BSIM4pags * Inv_LW; - pParam->BSIM4a1 = model->BSIM4a1 - + model->BSIM4la1 * Inv_L - + model->BSIM4wa1 * Inv_W - + model->BSIM4pa1 * Inv_LW; - pParam->BSIM4a2 = model->BSIM4a2 - + model->BSIM4la2 * Inv_L - + model->BSIM4wa2 * Inv_W - + model->BSIM4pa2 * Inv_LW; - pParam->BSIM4keta = model->BSIM4keta - + model->BSIM4lketa * Inv_L - + model->BSIM4wketa * Inv_W - + model->BSIM4pketa * Inv_LW; - pParam->BSIM4nsub = model->BSIM4nsub - + model->BSIM4lnsub * Inv_L - + model->BSIM4wnsub * Inv_W - + model->BSIM4pnsub * Inv_LW; - pParam->BSIM4ndep = model->BSIM4ndep - + model->BSIM4lndep * Inv_L - + model->BSIM4wndep * Inv_W - + model->BSIM4pndep * Inv_LW; + pParam->BSIM4a1 = model->BSIM4a1 + + model->BSIM4la1 * Inv_L + + model->BSIM4wa1 * Inv_W + + model->BSIM4pa1 * Inv_LW; + pParam->BSIM4a2 = model->BSIM4a2 + + model->BSIM4la2 * Inv_L + + model->BSIM4wa2 * Inv_W + + model->BSIM4pa2 * Inv_LW; + pParam->BSIM4keta = model->BSIM4keta + + model->BSIM4lketa * Inv_L + + model->BSIM4wketa * Inv_W + + model->BSIM4pketa * Inv_LW; + pParam->BSIM4ketac = model->BSIM4ketac + + model->BSIM4lketac * Inv_L + + model->BSIM4wketac * Inv_W + + model->BSIM4pketac * Inv_LW; + pParam->BSIM4nsub = model->BSIM4nsub + + model->BSIM4lnsub * Inv_L + + model->BSIM4wnsub * Inv_W + + model->BSIM4pnsub * Inv_LW; + pParam->BSIM4ndep = model->BSIM4ndep + + model->BSIM4lndep * Inv_L + + model->BSIM4wndep * Inv_W + + model->BSIM4pndep * Inv_LW; pParam->BSIM4nsd = model->BSIM4nsd + model->BSIM4lnsd * Inv_L + model->BSIM4wnsd * Inv_W @@ -614,70 +617,70 @@ int Size_Not_Found, i; + model->BSIM4lphin * Inv_L + model->BSIM4wphin * Inv_W + model->BSIM4pphin * Inv_LW; - pParam->BSIM4ngate = model->BSIM4ngate - + model->BSIM4lngate * Inv_L - + model->BSIM4wngate * Inv_W - + model->BSIM4pngate * Inv_LW; - pParam->BSIM4gamma1 = model->BSIM4gamma1 - + model->BSIM4lgamma1 * Inv_L - + model->BSIM4wgamma1 * Inv_W - + model->BSIM4pgamma1 * Inv_LW; - pParam->BSIM4gamma2 = model->BSIM4gamma2 - + model->BSIM4lgamma2 * Inv_L - + model->BSIM4wgamma2 * Inv_W - + model->BSIM4pgamma2 * Inv_LW; - pParam->BSIM4vbx = model->BSIM4vbx - + model->BSIM4lvbx * Inv_L - + model->BSIM4wvbx * Inv_W - + model->BSIM4pvbx * Inv_LW; - pParam->BSIM4vbm = model->BSIM4vbm - + model->BSIM4lvbm * Inv_L - + model->BSIM4wvbm * Inv_W - + model->BSIM4pvbm * Inv_LW; - pParam->BSIM4xt = model->BSIM4xt - + model->BSIM4lxt * Inv_L - + model->BSIM4wxt * Inv_W - + model->BSIM4pxt * Inv_LW; + pParam->BSIM4ngate = model->BSIM4ngate + + model->BSIM4lngate * Inv_L + + model->BSIM4wngate * Inv_W + + model->BSIM4pngate * Inv_LW; + pParam->BSIM4gamma1 = model->BSIM4gamma1 + + model->BSIM4lgamma1 * Inv_L + + model->BSIM4wgamma1 * Inv_W + + model->BSIM4pgamma1 * Inv_LW; + pParam->BSIM4gamma2 = model->BSIM4gamma2 + + model->BSIM4lgamma2 * Inv_L + + model->BSIM4wgamma2 * Inv_W + + model->BSIM4pgamma2 * Inv_LW; + pParam->BSIM4vbx = model->BSIM4vbx + + model->BSIM4lvbx * Inv_L + + model->BSIM4wvbx * Inv_W + + model->BSIM4pvbx * Inv_LW; + pParam->BSIM4vbm = model->BSIM4vbm + + model->BSIM4lvbm * Inv_L + + model->BSIM4wvbm * Inv_W + + model->BSIM4pvbm * Inv_LW; + pParam->BSIM4xt = model->BSIM4xt + + model->BSIM4lxt * Inv_L + + model->BSIM4wxt * Inv_W + + model->BSIM4pxt * Inv_LW; pParam->BSIM4vfb = model->BSIM4vfb + model->BSIM4lvfb * Inv_L + model->BSIM4wvfb * Inv_W + model->BSIM4pvfb * Inv_LW; - pParam->BSIM4k1 = model->BSIM4k1 - + model->BSIM4lk1 * Inv_L - + model->BSIM4wk1 * Inv_W - + model->BSIM4pk1 * Inv_LW; - pParam->BSIM4kt1 = model->BSIM4kt1 - + model->BSIM4lkt1 * Inv_L - + model->BSIM4wkt1 * Inv_W - + model->BSIM4pkt1 * Inv_LW; - pParam->BSIM4kt1l = model->BSIM4kt1l - + model->BSIM4lkt1l * Inv_L - + model->BSIM4wkt1l * Inv_W - + model->BSIM4pkt1l * Inv_LW; - pParam->BSIM4k2 = model->BSIM4k2 - + model->BSIM4lk2 * Inv_L - + model->BSIM4wk2 * Inv_W - + model->BSIM4pk2 * Inv_LW; - pParam->BSIM4kt2 = model->BSIM4kt2 - + model->BSIM4lkt2 * Inv_L - + model->BSIM4wkt2 * Inv_W - + model->BSIM4pkt2 * Inv_LW; - pParam->BSIM4k3 = model->BSIM4k3 - + model->BSIM4lk3 * Inv_L - + model->BSIM4wk3 * Inv_W - + model->BSIM4pk3 * Inv_LW; - pParam->BSIM4k3b = model->BSIM4k3b - + model->BSIM4lk3b * Inv_L - + model->BSIM4wk3b * Inv_W - + model->BSIM4pk3b * Inv_LW; - pParam->BSIM4w0 = model->BSIM4w0 - + model->BSIM4lw0 * Inv_L - + model->BSIM4ww0 * Inv_W - + model->BSIM4pw0 * Inv_LW; - pParam->BSIM4lpe0 = model->BSIM4lpe0 - + model->BSIM4llpe0 * Inv_L - + model->BSIM4wlpe0 * Inv_W - + model->BSIM4plpe0 * Inv_LW; + pParam->BSIM4k1 = model->BSIM4k1 + + model->BSIM4lk1 * Inv_L + + model->BSIM4wk1 * Inv_W + + model->BSIM4pk1 * Inv_LW; + pParam->BSIM4kt1 = model->BSIM4kt1 + + model->BSIM4lkt1 * Inv_L + + model->BSIM4wkt1 * Inv_W + + model->BSIM4pkt1 * Inv_LW; + pParam->BSIM4kt1l = model->BSIM4kt1l + + model->BSIM4lkt1l * Inv_L + + model->BSIM4wkt1l * Inv_W + + model->BSIM4pkt1l * Inv_LW; + pParam->BSIM4k2 = model->BSIM4k2 + + model->BSIM4lk2 * Inv_L + + model->BSIM4wk2 * Inv_W + + model->BSIM4pk2 * Inv_LW; + pParam->BSIM4kt2 = model->BSIM4kt2 + + model->BSIM4lkt2 * Inv_L + + model->BSIM4wkt2 * Inv_W + + model->BSIM4pkt2 * Inv_LW; + pParam->BSIM4k3 = model->BSIM4k3 + + model->BSIM4lk3 * Inv_L + + model->BSIM4wk3 * Inv_W + + model->BSIM4pk3 * Inv_LW; + pParam->BSIM4k3b = model->BSIM4k3b + + model->BSIM4lk3b * Inv_L + + model->BSIM4wk3b * Inv_W + + model->BSIM4pk3b * Inv_LW; + pParam->BSIM4w0 = model->BSIM4w0 + + model->BSIM4lw0 * Inv_L + + model->BSIM4ww0 * Inv_W + + model->BSIM4pw0 * Inv_LW; + pParam->BSIM4lpe0 = model->BSIM4lpe0 + + model->BSIM4llpe0 * Inv_L + + model->BSIM4wlpe0 * Inv_W + + model->BSIM4plpe0 * Inv_LW; pParam->BSIM4lpeb = model->BSIM4lpeb + model->BSIM4llpeb * Inv_L + model->BSIM4wlpeb * Inv_W @@ -690,128 +693,128 @@ int Size_Not_Found, i; + model->BSIM4ldvtp1 * Inv_L + model->BSIM4wdvtp1 * Inv_W + model->BSIM4pdvtp1 * Inv_LW; - pParam->BSIM4dvtp2 = model->BSIM4dvtp2 /* v4.7 */ + pParam->BSIM4dvtp2 = model->BSIM4dvtp2 /* v4.7 */ + model->BSIM4ldvtp2 * Inv_L + model->BSIM4wdvtp2 * Inv_W + model->BSIM4pdvtp2 * Inv_LW; - pParam->BSIM4dvtp3 = model->BSIM4dvtp3 /* v4.7 */ + pParam->BSIM4dvtp3 = model->BSIM4dvtp3 /* v4.7 */ + model->BSIM4ldvtp3 * Inv_L + model->BSIM4wdvtp3 * Inv_W + model->BSIM4pdvtp3 * Inv_LW; - pParam->BSIM4dvtp4 = model->BSIM4dvtp4 /* v4.7 */ + pParam->BSIM4dvtp4 = model->BSIM4dvtp4 /* v4.7 */ + model->BSIM4ldvtp4 * Inv_L + model->BSIM4wdvtp4 * Inv_W + model->BSIM4pdvtp4 * Inv_LW; - pParam->BSIM4dvtp5 = model->BSIM4dvtp5 /* v4.7 */ + pParam->BSIM4dvtp5 = model->BSIM4dvtp5 /* v4.7 */ + model->BSIM4ldvtp5 * Inv_L + model->BSIM4wdvtp5 * Inv_W + model->BSIM4pdvtp5 * Inv_LW; - pParam->BSIM4dvt0 = model->BSIM4dvt0 - + model->BSIM4ldvt0 * Inv_L - + model->BSIM4wdvt0 * Inv_W - + model->BSIM4pdvt0 * Inv_LW; - pParam->BSIM4dvt1 = model->BSIM4dvt1 - + model->BSIM4ldvt1 * Inv_L - + model->BSIM4wdvt1 * Inv_W - + model->BSIM4pdvt1 * Inv_LW; - pParam->BSIM4dvt2 = model->BSIM4dvt2 - + model->BSIM4ldvt2 * Inv_L - + model->BSIM4wdvt2 * Inv_W - + model->BSIM4pdvt2 * Inv_LW; - pParam->BSIM4dvt0w = model->BSIM4dvt0w - + model->BSIM4ldvt0w * Inv_L - + model->BSIM4wdvt0w * Inv_W - + model->BSIM4pdvt0w * Inv_LW; - pParam->BSIM4dvt1w = model->BSIM4dvt1w - + model->BSIM4ldvt1w * Inv_L - + model->BSIM4wdvt1w * Inv_W - + model->BSIM4pdvt1w * Inv_LW; - pParam->BSIM4dvt2w = model->BSIM4dvt2w - + model->BSIM4ldvt2w * Inv_L - + model->BSIM4wdvt2w * Inv_W - + model->BSIM4pdvt2w * Inv_LW; - pParam->BSIM4drout = model->BSIM4drout - + model->BSIM4ldrout * Inv_L - + model->BSIM4wdrout * Inv_W - + model->BSIM4pdrout * Inv_LW; - pParam->BSIM4dsub = model->BSIM4dsub - + model->BSIM4ldsub * Inv_L - + model->BSIM4wdsub * Inv_W - + model->BSIM4pdsub * Inv_LW; - pParam->BSIM4vth0 = model->BSIM4vth0 - + model->BSIM4lvth0 * Inv_L - + model->BSIM4wvth0 * Inv_W - + model->BSIM4pvth0 * Inv_LW; - pParam->BSIM4ua = model->BSIM4ua - + model->BSIM4lua * Inv_L - + model->BSIM4wua * Inv_W - + model->BSIM4pua * Inv_LW; - pParam->BSIM4ua1 = model->BSIM4ua1 - + model->BSIM4lua1 * Inv_L - + model->BSIM4wua1 * Inv_W - + model->BSIM4pua1 * Inv_LW; - pParam->BSIM4ub = model->BSIM4ub - + model->BSIM4lub * Inv_L - + model->BSIM4wub * Inv_W - + model->BSIM4pub * Inv_LW; - pParam->BSIM4ub1 = model->BSIM4ub1 - + model->BSIM4lub1 * Inv_L - + model->BSIM4wub1 * Inv_W - + model->BSIM4pub1 * Inv_LW; - pParam->BSIM4uc = model->BSIM4uc - + model->BSIM4luc * Inv_L - + model->BSIM4wuc * Inv_W - + model->BSIM4puc * Inv_LW; - pParam->BSIM4uc1 = model->BSIM4uc1 - + model->BSIM4luc1 * Inv_L - + model->BSIM4wuc1 * Inv_W - + model->BSIM4puc1 * Inv_LW; - pParam->BSIM4ud = model->BSIM4ud - + model->BSIM4lud * Inv_L - + model->BSIM4wud * Inv_W - + model->BSIM4pud * Inv_LW; - pParam->BSIM4ud1 = model->BSIM4ud1 - + model->BSIM4lud1 * Inv_L - + model->BSIM4wud1 * Inv_W - + model->BSIM4pud1 * Inv_LW; - pParam->BSIM4up = model->BSIM4up - + model->BSIM4lup * Inv_L - + model->BSIM4wup * Inv_W - + model->BSIM4pup * Inv_LW; - pParam->BSIM4lp = model->BSIM4lp - + model->BSIM4llp * Inv_L - + model->BSIM4wlp * Inv_W - + model->BSIM4plp * Inv_LW; + pParam->BSIM4dvt0 = model->BSIM4dvt0 + + model->BSIM4ldvt0 * Inv_L + + model->BSIM4wdvt0 * Inv_W + + model->BSIM4pdvt0 * Inv_LW; + pParam->BSIM4dvt1 = model->BSIM4dvt1 + + model->BSIM4ldvt1 * Inv_L + + model->BSIM4wdvt1 * Inv_W + + model->BSIM4pdvt1 * Inv_LW; + pParam->BSIM4dvt2 = model->BSIM4dvt2 + + model->BSIM4ldvt2 * Inv_L + + model->BSIM4wdvt2 * Inv_W + + model->BSIM4pdvt2 * Inv_LW; + pParam->BSIM4dvt0w = model->BSIM4dvt0w + + model->BSIM4ldvt0w * Inv_L + + model->BSIM4wdvt0w * Inv_W + + model->BSIM4pdvt0w * Inv_LW; + pParam->BSIM4dvt1w = model->BSIM4dvt1w + + model->BSIM4ldvt1w * Inv_L + + model->BSIM4wdvt1w * Inv_W + + model->BSIM4pdvt1w * Inv_LW; + pParam->BSIM4dvt2w = model->BSIM4dvt2w + + model->BSIM4ldvt2w * Inv_L + + model->BSIM4wdvt2w * Inv_W + + model->BSIM4pdvt2w * Inv_LW; + pParam->BSIM4drout = model->BSIM4drout + + model->BSIM4ldrout * Inv_L + + model->BSIM4wdrout * Inv_W + + model->BSIM4pdrout * Inv_LW; + pParam->BSIM4dsub = model->BSIM4dsub + + model->BSIM4ldsub * Inv_L + + model->BSIM4wdsub * Inv_W + + model->BSIM4pdsub * Inv_LW; + pParam->BSIM4vth0 = model->BSIM4vth0 + + model->BSIM4lvth0 * Inv_L + + model->BSIM4wvth0 * Inv_W + + model->BSIM4pvth0 * Inv_LW; + pParam->BSIM4ua = model->BSIM4ua + + model->BSIM4lua * Inv_L + + model->BSIM4wua * Inv_W + + model->BSIM4pua * Inv_LW; + pParam->BSIM4ua1 = model->BSIM4ua1 + + model->BSIM4lua1 * Inv_L + + model->BSIM4wua1 * Inv_W + + model->BSIM4pua1 * Inv_LW; + pParam->BSIM4ub = model->BSIM4ub + + model->BSIM4lub * Inv_L + + model->BSIM4wub * Inv_W + + model->BSIM4pub * Inv_LW; + pParam->BSIM4ub1 = model->BSIM4ub1 + + model->BSIM4lub1 * Inv_L + + model->BSIM4wub1 * Inv_W + + model->BSIM4pub1 * Inv_LW; + pParam->BSIM4uc = model->BSIM4uc + + model->BSIM4luc * Inv_L + + model->BSIM4wuc * Inv_W + + model->BSIM4puc * Inv_LW; + pParam->BSIM4uc1 = model->BSIM4uc1 + + model->BSIM4luc1 * Inv_L + + model->BSIM4wuc1 * Inv_W + + model->BSIM4puc1 * Inv_LW; + pParam->BSIM4ud = model->BSIM4ud + + model->BSIM4lud * Inv_L + + model->BSIM4wud * Inv_W + + model->BSIM4pud * Inv_LW; + pParam->BSIM4ud1 = model->BSIM4ud1 + + model->BSIM4lud1 * Inv_L + + model->BSIM4wud1 * Inv_W + + model->BSIM4pud1 * Inv_LW; + pParam->BSIM4up = model->BSIM4up + + model->BSIM4lup * Inv_L + + model->BSIM4wup * Inv_W + + model->BSIM4pup * Inv_LW; + pParam->BSIM4lp = model->BSIM4lp + + model->BSIM4llp * Inv_L + + model->BSIM4wlp * Inv_W + + model->BSIM4plp * Inv_LW; pParam->BSIM4eu = model->BSIM4eu + model->BSIM4leu * Inv_L + model->BSIM4weu * Inv_W + model->BSIM4peu * Inv_LW; - pParam->BSIM4u0 = model->BSIM4u0 - + model->BSIM4lu0 * Inv_L - + model->BSIM4wu0 * Inv_W - + model->BSIM4pu0 * Inv_LW; - pParam->BSIM4ute = model->BSIM4ute - + model->BSIM4lute * Inv_L - + model->BSIM4wute * Inv_W - + model->BSIM4pute * Inv_LW; - /*high k mobility*/ - pParam->BSIM4ucs = model->BSIM4ucs - + model->BSIM4lucs * Inv_L - + model->BSIM4wucs * Inv_W - + model->BSIM4pucs * Inv_LW; - pParam->BSIM4ucste = model->BSIM4ucste - + model->BSIM4lucste * Inv_L - + model->BSIM4wucste * Inv_W - + model->BSIM4pucste * Inv_LW; + pParam->BSIM4u0 = model->BSIM4u0 + + model->BSIM4lu0 * Inv_L + + model->BSIM4wu0 * Inv_W + + model->BSIM4pu0 * Inv_LW; + pParam->BSIM4ute = model->BSIM4ute + + model->BSIM4lute * Inv_L + + model->BSIM4wute * Inv_W + + model->BSIM4pute * Inv_LW; + /*high k mobility*/ + pParam->BSIM4ucs = model->BSIM4ucs + + model->BSIM4lucs * Inv_L + + model->BSIM4wucs * Inv_W + + model->BSIM4pucs * Inv_LW; + pParam->BSIM4ucste = model->BSIM4ucste + + model->BSIM4lucste * Inv_L + + model->BSIM4wucste * Inv_W + + model->BSIM4pucste * Inv_LW; - pParam->BSIM4voff = model->BSIM4voff - + model->BSIM4lvoff * Inv_L - + model->BSIM4wvoff * Inv_W - + model->BSIM4pvoff * Inv_LW; - pParam->BSIM4tvoff = model->BSIM4tvoff - + model->BSIM4ltvoff * Inv_L - + model->BSIM4wtvoff * Inv_W - + model->BSIM4ptvoff * Inv_LW; + pParam->BSIM4voff = model->BSIM4voff + + model->BSIM4lvoff * Inv_L + + model->BSIM4wvoff * Inv_W + + model->BSIM4pvoff * Inv_LW; + pParam->BSIM4tvoff = model->BSIM4tvoff + + model->BSIM4ltvoff * Inv_L + + model->BSIM4wtvoff * Inv_W + + model->BSIM4ptvoff * Inv_LW; pParam->BSIM4minv = model->BSIM4minv + model->BSIM4lminv * Inv_L + model->BSIM4wminv * Inv_W @@ -820,7 +823,7 @@ int Size_Not_Found, i; + model->BSIM4lminvcv * Inv_L + model->BSIM4wminvcv * Inv_W + model->BSIM4pminvcv * Inv_LW; - pParam->BSIM4fprout = model->BSIM4fprout + pParam->BSIM4fprout = model->BSIM4fprout + model->BSIM4lfprout * Inv_L + model->BSIM4wfprout * Inv_W + model->BSIM4pfprout * Inv_LW; @@ -832,14 +835,14 @@ int Size_Not_Found, i; + model->BSIM4lpditsd * Inv_L + model->BSIM4wpditsd * Inv_W + model->BSIM4ppditsd * Inv_LW; - pParam->BSIM4delta = model->BSIM4delta - + model->BSIM4ldelta * Inv_L - + model->BSIM4wdelta * Inv_W - + model->BSIM4pdelta * Inv_LW; - pParam->BSIM4rdsw = model->BSIM4rdsw - + model->BSIM4lrdsw * Inv_L - + model->BSIM4wrdsw * Inv_W - + model->BSIM4prdsw * Inv_LW; + pParam->BSIM4delta = model->BSIM4delta + + model->BSIM4ldelta * Inv_L + + model->BSIM4wdelta * Inv_W + + model->BSIM4pdelta * Inv_LW; + pParam->BSIM4rdsw = model->BSIM4rdsw + + model->BSIM4lrdsw * Inv_L + + model->BSIM4wrdsw * Inv_W + + model->BSIM4prdsw * Inv_LW; pParam->BSIM4rdw = model->BSIM4rdw + model->BSIM4lrdw * Inv_L + model->BSIM4wrdw * Inv_W @@ -848,94 +851,94 @@ int Size_Not_Found, i; + model->BSIM4lrsw * Inv_L + model->BSIM4wrsw * Inv_W + model->BSIM4prsw * Inv_LW; - pParam->BSIM4prwg = model->BSIM4prwg - + model->BSIM4lprwg * Inv_L - + model->BSIM4wprwg * Inv_W - + model->BSIM4pprwg * Inv_LW; - pParam->BSIM4prwb = model->BSIM4prwb - + model->BSIM4lprwb * Inv_L - + model->BSIM4wprwb * Inv_W - + model->BSIM4pprwb * Inv_LW; - pParam->BSIM4prt = model->BSIM4prt - + model->BSIM4lprt * Inv_L - + model->BSIM4wprt * Inv_W - + model->BSIM4pprt * Inv_LW; - pParam->BSIM4eta0 = model->BSIM4eta0 - + model->BSIM4leta0 * Inv_L - + model->BSIM4weta0 * Inv_W - + model->BSIM4peta0 * Inv_LW; - pParam->BSIM4teta0 = model->BSIM4teta0 /* v4.7 */ - + model->BSIM4lteta0 * Inv_L - + model->BSIM4wteta0 * Inv_W - + model->BSIM4pteta0 * Inv_LW; - pParam->BSIM4tvoffcv = model->BSIM4tvoffcv /* v4.8.0 */ - + model->BSIM4ltvoffcv * Inv_L - + model->BSIM4wtvoffcv * Inv_W - + model->BSIM4ptvoffcv * Inv_LW; - pParam->BSIM4etab = model->BSIM4etab - + model->BSIM4letab * Inv_L - + model->BSIM4wetab * Inv_W - + model->BSIM4petab * Inv_LW; - pParam->BSIM4pclm = model->BSIM4pclm - + model->BSIM4lpclm * Inv_L - + model->BSIM4wpclm * Inv_W - + model->BSIM4ppclm * Inv_LW; - pParam->BSIM4pdibl1 = model->BSIM4pdibl1 - + model->BSIM4lpdibl1 * Inv_L - + model->BSIM4wpdibl1 * Inv_W - + model->BSIM4ppdibl1 * Inv_LW; - pParam->BSIM4pdibl2 = model->BSIM4pdibl2 - + model->BSIM4lpdibl2 * Inv_L - + model->BSIM4wpdibl2 * Inv_W - + model->BSIM4ppdibl2 * Inv_LW; - pParam->BSIM4pdiblb = model->BSIM4pdiblb - + model->BSIM4lpdiblb * Inv_L - + model->BSIM4wpdiblb * Inv_W - + model->BSIM4ppdiblb * Inv_LW; - pParam->BSIM4pscbe1 = model->BSIM4pscbe1 - + model->BSIM4lpscbe1 * Inv_L - + model->BSIM4wpscbe1 * Inv_W - + model->BSIM4ppscbe1 * Inv_LW; - pParam->BSIM4pscbe2 = model->BSIM4pscbe2 - + model->BSIM4lpscbe2 * Inv_L - + model->BSIM4wpscbe2 * Inv_W - + model->BSIM4ppscbe2 * Inv_LW; - pParam->BSIM4pvag = model->BSIM4pvag - + model->BSIM4lpvag * Inv_L - + model->BSIM4wpvag * Inv_W - + model->BSIM4ppvag * Inv_LW; - pParam->BSIM4wr = model->BSIM4wr - + model->BSIM4lwr * Inv_L - + model->BSIM4wwr * Inv_W - + model->BSIM4pwr * Inv_LW; - pParam->BSIM4dwg = model->BSIM4dwg - + model->BSIM4ldwg * Inv_L - + model->BSIM4wdwg * Inv_W - + model->BSIM4pdwg * Inv_LW; - pParam->BSIM4dwb = model->BSIM4dwb - + model->BSIM4ldwb * Inv_L - + model->BSIM4wdwb * Inv_W - + model->BSIM4pdwb * Inv_LW; - pParam->BSIM4b0 = model->BSIM4b0 - + model->BSIM4lb0 * Inv_L - + model->BSIM4wb0 * Inv_W - + model->BSIM4pb0 * Inv_LW; - pParam->BSIM4b1 = model->BSIM4b1 - + model->BSIM4lb1 * Inv_L - + model->BSIM4wb1 * Inv_W - + model->BSIM4pb1 * Inv_LW; - pParam->BSIM4alpha0 = model->BSIM4alpha0 - + model->BSIM4lalpha0 * Inv_L - + model->BSIM4walpha0 * Inv_W - + model->BSIM4palpha0 * Inv_LW; + pParam->BSIM4prwg = model->BSIM4prwg + + model->BSIM4lprwg * Inv_L + + model->BSIM4wprwg * Inv_W + + model->BSIM4pprwg * Inv_LW; + pParam->BSIM4prwb = model->BSIM4prwb + + model->BSIM4lprwb * Inv_L + + model->BSIM4wprwb * Inv_W + + model->BSIM4pprwb * Inv_LW; + pParam->BSIM4prt = model->BSIM4prt + + model->BSIM4lprt * Inv_L + + model->BSIM4wprt * Inv_W + + model->BSIM4pprt * Inv_LW; + pParam->BSIM4eta0 = model->BSIM4eta0 + + model->BSIM4leta0 * Inv_L + + model->BSIM4weta0 * Inv_W + + model->BSIM4peta0 * Inv_LW; + pParam->BSIM4teta0 = model->BSIM4teta0 /* v4.7 */ + + model->BSIM4lteta0 * Inv_L + + model->BSIM4wteta0 * Inv_W + + model->BSIM4pteta0 * Inv_LW; + pParam->BSIM4tvoffcv = model->BSIM4tvoffcv /* v4.8.0 */ + + model->BSIM4ltvoffcv * Inv_L + + model->BSIM4wtvoffcv * Inv_W + + model->BSIM4ptvoffcv * Inv_LW; + pParam->BSIM4etab = model->BSIM4etab + + model->BSIM4letab * Inv_L + + model->BSIM4wetab * Inv_W + + model->BSIM4petab * Inv_LW; + pParam->BSIM4pclm = model->BSIM4pclm + + model->BSIM4lpclm * Inv_L + + model->BSIM4wpclm * Inv_W + + model->BSIM4ppclm * Inv_LW; + pParam->BSIM4pdibl1 = model->BSIM4pdibl1 + + model->BSIM4lpdibl1 * Inv_L + + model->BSIM4wpdibl1 * Inv_W + + model->BSIM4ppdibl1 * Inv_LW; + pParam->BSIM4pdibl2 = model->BSIM4pdibl2 + + model->BSIM4lpdibl2 * Inv_L + + model->BSIM4wpdibl2 * Inv_W + + model->BSIM4ppdibl2 * Inv_LW; + pParam->BSIM4pdiblb = model->BSIM4pdiblb + + model->BSIM4lpdiblb * Inv_L + + model->BSIM4wpdiblb * Inv_W + + model->BSIM4ppdiblb * Inv_LW; + pParam->BSIM4pscbe1 = model->BSIM4pscbe1 + + model->BSIM4lpscbe1 * Inv_L + + model->BSIM4wpscbe1 * Inv_W + + model->BSIM4ppscbe1 * Inv_LW; + pParam->BSIM4pscbe2 = model->BSIM4pscbe2 + + model->BSIM4lpscbe2 * Inv_L + + model->BSIM4wpscbe2 * Inv_W + + model->BSIM4ppscbe2 * Inv_LW; + pParam->BSIM4pvag = model->BSIM4pvag + + model->BSIM4lpvag * Inv_L + + model->BSIM4wpvag * Inv_W + + model->BSIM4ppvag * Inv_LW; + pParam->BSIM4wr = model->BSIM4wr + + model->BSIM4lwr * Inv_L + + model->BSIM4wwr * Inv_W + + model->BSIM4pwr * Inv_LW; + pParam->BSIM4dwg = model->BSIM4dwg + + model->BSIM4ldwg * Inv_L + + model->BSIM4wdwg * Inv_W + + model->BSIM4pdwg * Inv_LW; + pParam->BSIM4dwb = model->BSIM4dwb + + model->BSIM4ldwb * Inv_L + + model->BSIM4wdwb * Inv_W + + model->BSIM4pdwb * Inv_LW; + pParam->BSIM4b0 = model->BSIM4b0 + + model->BSIM4lb0 * Inv_L + + model->BSIM4wb0 * Inv_W + + model->BSIM4pb0 * Inv_LW; + pParam->BSIM4b1 = model->BSIM4b1 + + model->BSIM4lb1 * Inv_L + + model->BSIM4wb1 * Inv_W + + model->BSIM4pb1 * Inv_LW; + pParam->BSIM4alpha0 = model->BSIM4alpha0 + + model->BSIM4lalpha0 * Inv_L + + model->BSIM4walpha0 * Inv_W + + model->BSIM4palpha0 * Inv_LW; pParam->BSIM4alpha1 = model->BSIM4alpha1 + model->BSIM4lalpha1 * Inv_L + model->BSIM4walpha1 * Inv_W + model->BSIM4palpha1 * Inv_LW; - pParam->BSIM4beta0 = model->BSIM4beta0 - + model->BSIM4lbeta0 * Inv_L - + model->BSIM4wbeta0 * Inv_W - + model->BSIM4pbeta0 * Inv_LW; + pParam->BSIM4beta0 = model->BSIM4beta0 + + model->BSIM4lbeta0 * Inv_L + + model->BSIM4wbeta0 * Inv_W + + model->BSIM4pbeta0 * Inv_LW; pParam->BSIM4agidl = model->BSIM4agidl + model->BSIM4lagidl * Inv_L + model->BSIM4wagidl * Inv_W @@ -952,15 +955,15 @@ int Size_Not_Found, i; + model->BSIM4legidl * Inv_L + model->BSIM4wegidl * Inv_W + model->BSIM4pegidl * Inv_LW; - pParam->BSIM4rgidl = model->BSIM4rgidl /* v4.7 New GIDL/GISL */ + pParam->BSIM4rgidl = model->BSIM4rgidl /* v4.7 New GIDL/GISL */ + model->BSIM4lrgidl * Inv_L + model->BSIM4wrgidl * Inv_W + model->BSIM4prgidl * Inv_LW; - pParam->BSIM4kgidl = model->BSIM4kgidl /* v4.7 New GIDL/GISL */ + pParam->BSIM4kgidl = model->BSIM4kgidl /* v4.7 New GIDL/GISL */ + model->BSIM4lkgidl * Inv_L + model->BSIM4wkgidl * Inv_W + model->BSIM4pkgidl * Inv_LW; - pParam->BSIM4fgidl = model->BSIM4fgidl /* v4.7 New GIDL/GISL */ + pParam->BSIM4fgidl = model->BSIM4fgidl /* v4.7 New GIDL/GISL */ + model->BSIM4lfgidl * Inv_L + model->BSIM4wfgidl * Inv_W + model->BSIM4pfgidl * Inv_LW; @@ -980,15 +983,15 @@ int Size_Not_Found, i; + model->BSIM4legisl * Inv_L + model->BSIM4wegisl * Inv_W + model->BSIM4pegisl * Inv_LW; - pParam->BSIM4rgisl = model->BSIM4rgisl /* v4.7 New GIDL/GISL */ + pParam->BSIM4rgisl = model->BSIM4rgisl /* v4.7 New GIDL/GISL */ + model->BSIM4lrgisl * Inv_L + model->BSIM4wrgisl * Inv_W + model->BSIM4prgisl * Inv_LW; - pParam->BSIM4kgisl = model->BSIM4kgisl /* v4.7 New GIDL/GISL */ + pParam->BSIM4kgisl = model->BSIM4kgisl /* v4.7 New GIDL/GISL */ + model->BSIM4lkgisl * Inv_L + model->BSIM4wkgisl * Inv_W + model->BSIM4pkgisl * Inv_LW; - pParam->BSIM4fgisl = model->BSIM4fgisl /* v4.7 New GIDL/GISL */ + pParam->BSIM4fgisl = model->BSIM4fgisl /* v4.7 New GIDL/GISL */ + model->BSIM4lfgisl * Inv_L + model->BSIM4wfgisl * Inv_W + model->BSIM4pfgisl * Inv_LW; @@ -1121,38 +1124,38 @@ int Size_Not_Found, i; + model->BSIM4wtvfbsdoff * Inv_W + model->BSIM4ptvfbsdoff * Inv_LW; - pParam->BSIM4cgsl = model->BSIM4cgsl - + model->BSIM4lcgsl * Inv_L - + model->BSIM4wcgsl * Inv_W - + model->BSIM4pcgsl * Inv_LW; - pParam->BSIM4cgdl = model->BSIM4cgdl - + model->BSIM4lcgdl * Inv_L - + model->BSIM4wcgdl * Inv_W - + model->BSIM4pcgdl * Inv_LW; - pParam->BSIM4ckappas = model->BSIM4ckappas - + model->BSIM4lckappas * Inv_L - + model->BSIM4wckappas * Inv_W - + model->BSIM4pckappas * Inv_LW; + pParam->BSIM4cgsl = model->BSIM4cgsl + + model->BSIM4lcgsl * Inv_L + + model->BSIM4wcgsl * Inv_W + + model->BSIM4pcgsl * Inv_LW; + pParam->BSIM4cgdl = model->BSIM4cgdl + + model->BSIM4lcgdl * Inv_L + + model->BSIM4wcgdl * Inv_W + + model->BSIM4pcgdl * Inv_LW; + pParam->BSIM4ckappas = model->BSIM4ckappas + + model->BSIM4lckappas * Inv_L + + model->BSIM4wckappas * Inv_W + + model->BSIM4pckappas * Inv_LW; pParam->BSIM4ckappad = model->BSIM4ckappad + model->BSIM4lckappad * Inv_L + model->BSIM4wckappad * Inv_W + model->BSIM4pckappad * Inv_LW; - pParam->BSIM4cf = model->BSIM4cf - + model->BSIM4lcf * Inv_L - + model->BSIM4wcf * Inv_W - + model->BSIM4pcf * Inv_LW; - pParam->BSIM4clc = model->BSIM4clc - + model->BSIM4lclc * Inv_L - + model->BSIM4wclc * Inv_W - + model->BSIM4pclc * Inv_LW; - pParam->BSIM4cle = model->BSIM4cle - + model->BSIM4lcle * Inv_L - + model->BSIM4wcle * Inv_W - + model->BSIM4pcle * Inv_LW; - pParam->BSIM4vfbcv = model->BSIM4vfbcv - + model->BSIM4lvfbcv * Inv_L - + model->BSIM4wvfbcv * Inv_W - + model->BSIM4pvfbcv * Inv_LW; + pParam->BSIM4cf = model->BSIM4cf + + model->BSIM4lcf * Inv_L + + model->BSIM4wcf * Inv_W + + model->BSIM4pcf * Inv_LW; + pParam->BSIM4clc = model->BSIM4clc + + model->BSIM4lclc * Inv_L + + model->BSIM4wclc * Inv_W + + model->BSIM4pclc * Inv_LW; + pParam->BSIM4cle = model->BSIM4cle + + model->BSIM4lcle * Inv_L + + model->BSIM4wcle * Inv_W + + model->BSIM4pcle * Inv_LW; + pParam->BSIM4vfbcv = model->BSIM4vfbcv + + model->BSIM4lvfbcv * Inv_L + + model->BSIM4wvfbcv * Inv_W + + model->BSIM4pvfbcv * Inv_LW; pParam->BSIM4acde = model->BSIM4acde + model->BSIM4lacde * Inv_L + model->BSIM4wacde * Inv_W @@ -1181,83 +1184,82 @@ int Size_Not_Found, i; + model->BSIM4lku0we * Inv_L + model->BSIM4wku0we * Inv_W + model->BSIM4pku0we * Inv_LW; - pParam->BSIM4abulkCVfactor = 1.0 + pow((pParam->BSIM4clc - / pParam->BSIM4leffCV), - pParam->BSIM4cle); + / pParam->BSIM4leffCV), + pParam->BSIM4cle); - T0 = (TRatio - 1.0); + T0 = (TRatio - 1.0); - PowWeffWr = pow(pParam->BSIM4weffCJ * 1.0e6, pParam->BSIM4wr) * here->BSIM4nf; + PowWeffWr = pow(pParam->BSIM4weffCJ * 1.0e6, pParam->BSIM4wr) * here->BSIM4nf; - T1 = T2 = T3 = T4 = 0.0; - pParam->BSIM4ucs = pParam->BSIM4ucs * pow(TRatio, pParam->BSIM4ucste); - if(model->BSIM4tempMod == 0) - { - pParam->BSIM4ua = pParam->BSIM4ua + pParam->BSIM4ua1 * T0; - pParam->BSIM4ub = pParam->BSIM4ub + pParam->BSIM4ub1 * T0; - pParam->BSIM4uc = pParam->BSIM4uc + pParam->BSIM4uc1 * T0; - pParam->BSIM4ud = pParam->BSIM4ud + pParam->BSIM4ud1 * T0; + T1 = T2 = T3 = T4 = 0.0; + pParam->BSIM4ucs = pParam->BSIM4ucs * pow(TRatio, pParam->BSIM4ucste); + if(model->BSIM4tempMod == 0) + { + pParam->BSIM4ua = pParam->BSIM4ua + pParam->BSIM4ua1 * T0; + pParam->BSIM4ub = pParam->BSIM4ub + pParam->BSIM4ub1 * T0; + pParam->BSIM4uc = pParam->BSIM4uc + pParam->BSIM4uc1 * T0; + pParam->BSIM4ud = pParam->BSIM4ud + pParam->BSIM4ud1 * T0; pParam->BSIM4vsattemp = pParam->BSIM4vsat - pParam->BSIM4at * T0; - T10 = pParam->BSIM4prt * T0; - if(model->BSIM4rdsMod) - { - /* External Rd(V) */ - T1 = pParam->BSIM4rdw + T10; - T2 = model->BSIM4rdwmin + T10; - /* External Rs(V) */ - T3 = pParam->BSIM4rsw + T10; - T4 = model->BSIM4rswmin + T10; + T10 = pParam->BSIM4prt * T0; + if(model->BSIM4rdsMod) + { + /* External Rd(V) */ + T1 = pParam->BSIM4rdw + T10; + T2 = model->BSIM4rdwmin + T10; + /* External Rs(V) */ + T3 = pParam->BSIM4rsw + T10; + T4 = model->BSIM4rswmin + T10; } - /* Internal Rds(V) in IV */ - pParam->BSIM4rds0 = (pParam->BSIM4rdsw + T10) - * here->BSIM4nf / PowWeffWr; - pParam->BSIM4rdswmin = (model->BSIM4rdswmin + T10) - * here->BSIM4nf / PowWeffWr; + /* Internal Rds(V) in IV */ + pParam->BSIM4rds0 = (pParam->BSIM4rdsw + T10) + * here->BSIM4nf / PowWeffWr; + pParam->BSIM4rdswmin = (model->BSIM4rdswmin + T10) + * here->BSIM4nf / PowWeffWr; } - else - { - if (model->BSIM4tempMod == 3) - { - pParam->BSIM4ua = pParam->BSIM4ua * pow(TRatio, pParam->BSIM4ua1) ; - pParam->BSIM4ub = pParam->BSIM4ub * pow(TRatio, pParam->BSIM4ub1); - pParam->BSIM4uc = pParam->BSIM4uc * pow(TRatio, pParam->BSIM4uc1); - pParam->BSIM4ud = pParam->BSIM4ud * pow(TRatio, pParam->BSIM4ud1); - } - else - { - /* tempMod = 1, 2 */ - pParam->BSIM4ua = pParam->BSIM4ua * (1.0 + pParam->BSIM4ua1 * delTemp) ; - pParam->BSIM4ub = pParam->BSIM4ub * (1.0 + pParam->BSIM4ub1 * delTemp); - pParam->BSIM4uc = pParam->BSIM4uc * (1.0 + pParam->BSIM4uc1 * delTemp); - pParam->BSIM4ud = pParam->BSIM4ud * (1.0 + pParam->BSIM4ud1 * delTemp); - } - pParam->BSIM4vsattemp = pParam->BSIM4vsat * (1.0 - pParam->BSIM4at * delTemp); - T10 = 1.0 + pParam->BSIM4prt * delTemp; - if(model->BSIM4rdsMod) - { - /* External Rd(V) */ - T1 = pParam->BSIM4rdw * T10; - T2 = model->BSIM4rdwmin * T10; + else + { + if (model->BSIM4tempMod == 3) + { + pParam->BSIM4ua = pParam->BSIM4ua * pow(TRatio, pParam->BSIM4ua1) ; + pParam->BSIM4ub = pParam->BSIM4ub * pow(TRatio, pParam->BSIM4ub1); + pParam->BSIM4uc = pParam->BSIM4uc * pow(TRatio, pParam->BSIM4uc1); + pParam->BSIM4ud = pParam->BSIM4ud * pow(TRatio, pParam->BSIM4ud1); + } + else + { + /* tempMod = 1, 2 */ + pParam->BSIM4ua = pParam->BSIM4ua * (1.0 + pParam->BSIM4ua1 * delTemp) ; + pParam->BSIM4ub = pParam->BSIM4ub * (1.0 + pParam->BSIM4ub1 * delTemp); + pParam->BSIM4uc = pParam->BSIM4uc * (1.0 + pParam->BSIM4uc1 * delTemp); + pParam->BSIM4ud = pParam->BSIM4ud * (1.0 + pParam->BSIM4ud1 * delTemp); + } + pParam->BSIM4vsattemp = pParam->BSIM4vsat * (1.0 - pParam->BSIM4at * delTemp); + T10 = 1.0 + pParam->BSIM4prt * delTemp; + if(model->BSIM4rdsMod) + { + /* External Rd(V) */ + T1 = pParam->BSIM4rdw * T10; + T2 = model->BSIM4rdwmin * T10; - /* External Rs(V) */ - T3 = pParam->BSIM4rsw * T10; - T4 = model->BSIM4rswmin * T10; + /* External Rs(V) */ + T3 = pParam->BSIM4rsw * T10; + T4 = model->BSIM4rswmin * T10; } - /* Internal Rds(V) in IV */ - pParam->BSIM4rds0 = pParam->BSIM4rdsw * T10 * here->BSIM4nf / PowWeffWr; - pParam->BSIM4rdswmin = model->BSIM4rdswmin * T10 * here->BSIM4nf / PowWeffWr; + /* Internal Rds(V) in IV */ + pParam->BSIM4rds0 = pParam->BSIM4rdsw * T10 * here->BSIM4nf / PowWeffWr; + pParam->BSIM4rdswmin = model->BSIM4rdswmin * T10 * here->BSIM4nf / PowWeffWr; } - if (T1 < 0.0) - { T1 = 0.0; - printf("Warning: Rdw at current temperature is negative; set to 0.\n"); - } - if (T2 < 0.0) + if (T1 < 0.0) + { T1 = 0.0; + printf("Warning: Rdw at current temperature is negative; set to 0.\n"); + } + if (T2 < 0.0) { T2 = 0.0; printf("Warning: Rdwmin at current temperature is negative; set to 0.\n"); } - pParam->BSIM4rd0 = T1 / PowWeffWr; + pParam->BSIM4rd0 = T1 / PowWeffWr; pParam->BSIM4rdwmin = T2 / PowWeffWr; if (T3 < 0.0) { T3 = 0.0; @@ -1276,36 +1278,36 @@ int Size_Not_Found, i; /* mobility channel length dependence */ T5 = 1.0 - pParam->BSIM4up * exp( - pParam->BSIM4leff / pParam->BSIM4lp); pParam->BSIM4u0temp = pParam->BSIM4u0 * T5 - * pow(TRatio, pParam->BSIM4ute); + * pow(TRatio, pParam->BSIM4ute); if (pParam->BSIM4eu < 0.0) { pParam->BSIM4eu = 0.0; - printf("Warning: eu has been negative; reset to 0.0.\n"); - } + printf("Warning: eu has been negative; reset to 0.0.\n"); + } if (pParam->BSIM4ucs < 0.0) { pParam->BSIM4ucs = 0.0; - printf("Warning: ucs has been negative; reset to 0.0.\n"); - } + printf("Warning: ucs has been negative; reset to 0.0.\n"); + } - pParam->BSIM4vfbsdoff = pParam->BSIM4vfbsdoff * (1.0 + pParam->BSIM4tvfbsdoff * delTemp); - pParam->BSIM4voff = pParam->BSIM4voff * (1.0 + pParam->BSIM4tvoff * delTemp); + pParam->BSIM4vfbsdoff = pParam->BSIM4vfbsdoff * (1.0 + pParam->BSIM4tvfbsdoff * delTemp); + pParam->BSIM4voff = pParam->BSIM4voff * (1.0 + pParam->BSIM4tvoff * delTemp); - pParam->BSIM4nfactor = pParam->BSIM4nfactor + pParam->BSIM4tnfactor * delTemp / Tnom; /* v4.7 temp dep of leakage currents */ - pParam->BSIM4voffcv = pParam->BSIM4voffcv * (1.0 + pParam->BSIM4tvoffcv * delTemp); /* v4.7 temp dep of leakage currents */ - pParam->BSIM4eta0 = pParam->BSIM4eta0 + pParam->BSIM4teta0 * delTemp / Tnom; /* v4.7 temp dep of leakage currents */ + pParam->BSIM4nfactor = pParam->BSIM4nfactor + pParam->BSIM4tnfactor * delTemp / Tnom; /* v4.7 temp dep of leakage currents */ + pParam->BSIM4voffcv = pParam->BSIM4voffcv * (1.0 + pParam->BSIM4tvoffcv * delTemp); /* v4.7 temp dep of leakage currents */ + pParam->BSIM4eta0 = pParam->BSIM4eta0 + pParam->BSIM4teta0 * delTemp / Tnom; /* v4.7 temp dep of leakage currents */ /* Source End Velocity Limit */ - if((model->BSIM4vtlGiven) && (model->BSIM4vtl > 0.0) ) - { + if((model->BSIM4vtlGiven) && (model->BSIM4vtl > 0.0) ) + { if(model->BSIM4lc < 0.0) pParam->BSIM4lc = 0.0; else pParam->BSIM4lc = model->BSIM4lc ; T0 = pParam->BSIM4leff / (pParam->BSIM4xn * pParam->BSIM4leff + pParam->BSIM4lc); pParam->BSIM4tfactor = (1.0 - T0) / (1.0 + T0 ); - } + } pParam->BSIM4cgdo = (model->BSIM4cgdo + pParam->BSIM4cf) - * pParam->BSIM4weffCV; + * pParam->BSIM4weffCV; pParam->BSIM4cgso = (model->BSIM4cgso + pParam->BSIM4cf) - * pParam->BSIM4weffCV; + * pParam->BSIM4weffCV; pParam->BSIM4cgbo = model->BSIM4cgbo * pParam->BSIM4leffCV * here->BSIM4nf; if (!model->BSIM4ndepGiven && model->BSIM4gamma1Given) @@ -1313,92 +1315,107 @@ int Size_Not_Found, i; pParam->BSIM4ndep = 3.01248e22 * T0 * T0; } - pParam->BSIM4phi = Vtm0 * log(pParam->BSIM4ndep / ni) - + pParam->BSIM4phin + 0.4; + pParam->BSIM4phi = Vtm0 * log(pParam->BSIM4ndep / ni) + + pParam->BSIM4phin + 0.4; - pParam->BSIM4sqrtPhi = sqrt(pParam->BSIM4phi); - pParam->BSIM4phis3 = pParam->BSIM4sqrtPhi * pParam->BSIM4phi; + if(pParam->BSIM4phi <= 0.0) + { + printf("Fatal: Phi = %g is not positive. Please check Phin and Ndep\n", + pParam->BSIM4phi); + printf(" Phin = %g Ndep = %g \n", + pParam->BSIM4phin, pParam->BSIM4ndep); + Fatal_Flag = 1; + } + + pParam->BSIM4sqrtPhi = sqrt(pParam->BSIM4phi); + pParam->BSIM4phis3 = pParam->BSIM4sqrtPhi * pParam->BSIM4phi; pParam->BSIM4Xdep0 = sqrt(2.0 * epssub / (Charge_q - * pParam->BSIM4ndep * 1.0e6)) + * pParam->BSIM4ndep * 1.0e6)) * pParam->BSIM4sqrtPhi; pParam->BSIM4sqrtXdep0 = sqrt(pParam->BSIM4Xdep0); - if(model->BSIM4mtrlMod == 0) - pParam->BSIM4litl = sqrt(3.0 * 3.9 / epsrox * pParam->BSIM4xj * toxe); - else - pParam->BSIM4litl = sqrt(model->BSIM4epsrsub/epsrox * pParam->BSIM4xj * toxe); + if(model->BSIM4mtrlMod == 0) + pParam->BSIM4litl = sqrt(3.0 * 3.9 / epsrox * pParam->BSIM4xj * toxe); + else + pParam->BSIM4litl = sqrt(model->BSIM4epsrsub/epsrox * pParam->BSIM4xj * toxe); pParam->BSIM4vbi = Vtm0 * log(pParam->BSIM4nsd - * pParam->BSIM4ndep / (ni * ni)); + * pParam->BSIM4ndep / (ni * ni)); - if (model->BSIM4mtrlMod == 0) - { - if (pParam->BSIM4ngate > 0.0) - { pParam->BSIM4vfbsd = Vtm0 * log(pParam->BSIM4ngate + if (model->BSIM4mtrlMod == 0) + { + if (pParam->BSIM4ngate > 0.0) + { pParam->BSIM4vfbsd = Vtm0 * log(pParam->BSIM4ngate / pParam->BSIM4nsd); - } - else - pParam->BSIM4vfbsd = 0.0; - } - else - { - T0 = Vtm0 * log(pParam->BSIM4nsd/ni); - T1 = 0.5 * Eg0; - if(T0 > T1) - T0 = T1; - T2 = model->BSIM4easub + T1 - model->BSIM4type * T0; - pParam->BSIM4vfbsd = model->BSIM4phig - T2; - } + } + else + pParam->BSIM4vfbsd = 0.0; + } + else + { + T0 = Vtm0 * log(pParam->BSIM4nsd/ni); + T1 = 0.5 * Eg0; + if(T0 > T1) + T0 = T1; + T2 = model->BSIM4easub + T1 - model->BSIM4type * T0; + pParam->BSIM4vfbsd = model->BSIM4phig - T2; + } pParam->BSIM4cdep0 = sqrt(Charge_q * epssub - * pParam->BSIM4ndep * 1.0e6 / 2.0 - / pParam->BSIM4phi); + * pParam->BSIM4ndep * 1.0e6 / 2.0 + / pParam->BSIM4phi); pParam->BSIM4ToxRatio = exp(pParam->BSIM4ntox - * log(model->BSIM4toxref / toxe)) - / toxe / toxe; + * log(model->BSIM4toxref / toxe)) + / toxe / toxe; pParam->BSIM4ToxRatioEdge = exp(pParam->BSIM4ntox * log(model->BSIM4toxref / (toxe * pParam->BSIM4poxedge))) / toxe / toxe / pParam->BSIM4poxedge / pParam->BSIM4poxedge; + 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.2")) && (strncmp(model->BSIM4version, "4.82", 4)) && + (strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4))) { - pParam->BSIM4AechvbEdgeS = pParam->BSIM4Aechvb * pParam->BSIM4weff - * model->BSIM4dlcig * pParam->BSIM4ToxRatioEdge; - pParam->BSIM4AechvbEdgeD = pParam->BSIM4Aechvb * pParam->BSIM4weff - * model->BSIM4dlcigd * pParam->BSIM4ToxRatioEdge; + pParam->BSIM4AechvbEdgeS = pParam->BSIM4Aechvb * pParam->BSIM4weff + * model->BSIM4dlcig * pParam->BSIM4ToxRatioEdge; + pParam->BSIM4AechvbEdgeD = pParam->BSIM4Aechvb * pParam->BSIM4weff + * model->BSIM4dlcigd * pParam->BSIM4ToxRatioEdge; + } else { if (model->BSIM4dlcig < 0.0) - { + { printf("Warning: dlcig = %g is negative. Set to zero.\n", model->BSIM4dlcig); model->BSIM4dlcig = 0.0; - } - pParam->BSIM4AechvbEdgeS = pParam->BSIM4Aechvb * pParam->BSIM4weff - * model->BSIM4dlcig * pParam->BSIM4ToxRatioEdge; - if (model->BSIM4dlcigd < 0.0) - { + } + pParam->BSIM4AechvbEdgeS = pParam->BSIM4Aechvb * pParam->BSIM4weff + * model->BSIM4dlcig * pParam->BSIM4ToxRatioEdge; + if (model->BSIM4dlcigd < 0.0) + { printf("Warning: dlcigd = %g is negative. Set to zero.\n", model->BSIM4dlcigd); model->BSIM4dlcigd = 0.0; - } - pParam->BSIM4AechvbEdgeD = pParam->BSIM4Aechvb * pParam->BSIM4weff - * model->BSIM4dlcigd * pParam->BSIM4ToxRatioEdge; + } + pParam->BSIM4AechvbEdgeD = pParam->BSIM4Aechvb * pParam->BSIM4weff + * model->BSIM4dlcigd * pParam->BSIM4ToxRatioEdge; + } pParam->BSIM4BechvbEdge = -pParam->BSIM4Bechvb - * toxe * pParam->BSIM4poxedge; + * toxe * pParam->BSIM4poxedge; pParam->BSIM4Aechvb *= pParam->BSIM4weff * pParam->BSIM4leff - * pParam->BSIM4ToxRatio; + * pParam->BSIM4ToxRatio; pParam->BSIM4Bechvb *= -toxe; + + pParam->BSIM4mstar = 0.5 + atan(pParam->BSIM4minv) / PI; pParam->BSIM4mstarcv = 0.5 + atan(pParam->BSIM4minvcv) / PI; pParam->BSIM4voffcbn = pParam->BSIM4voff + model->BSIM4voffl / pParam->BSIM4leff; @@ -1410,85 +1427,79 @@ int Size_Not_Found, i; if (model->BSIM4k1Given || model->BSIM4k2Given) - { if (!model->BSIM4k1Given) - { - if ((!ckt->CKTcurJob) || (ckt->CKTcurJob->JOBtype < 9)) /* don't print in sensitivity */ - fprintf(stdout, "Warning: k1 should be specified with k2.\n"); + { if (!model->BSIM4k1Given) + { fprintf(stdout, "Warning: k1 should be specified with k2.\n"); pParam->BSIM4k1 = 0.53; } if (!model->BSIM4k2Given) - { - if ((!ckt->CKTcurJob) || (ckt->CKTcurJob->JOBtype < 9)) /* don't print in sensitivity */ - fprintf(stdout, "Warning: k2 should be specified with k1.\n"); + { fprintf(stdout, "Warning: k2 should be specified with k1.\n"); pParam->BSIM4k2 = -0.0186; } - if ((!ckt->CKTcurJob) || (ckt->CKTcurJob->JOBtype < 9)) { /* don't print in sensitivity */ - if (model->BSIM4nsubGiven) - fprintf(stdout, "Warning: nsub is ignored because k1 or k2 is given.\n"); - if (model->BSIM4xtGiven) - fprintf(stdout, "Warning: xt is ignored because k1 or k2 is given.\n"); - if (model->BSIM4vbxGiven) - fprintf(stdout, "Warning: vbx is ignored because k1 or k2 is given.\n"); - if (model->BSIM4gamma1Given) - fprintf(stdout, "Warning: gamma1 is ignored because k1 or k2 is given.\n"); - if (model->BSIM4gamma2Given) - fprintf(stdout, "Warning: gamma2 is ignored because k1 or k2 is given.\n"); - } + if (model->BSIM4nsubGiven) + fprintf(stdout, "Warning: nsub is ignored because k1 or k2 is given.\n"); + if (model->BSIM4xtGiven) + fprintf(stdout, "Warning: xt is ignored because k1 or k2 is given.\n"); + if (model->BSIM4vbxGiven) + fprintf(stdout, "Warning: vbx is ignored because k1 or k2 is given.\n"); + if (model->BSIM4gamma1Given) + fprintf(stdout, "Warning: gamma1 is ignored because k1 or k2 is given.\n"); + if (model->BSIM4gamma2Given) + fprintf(stdout, "Warning: gamma2 is ignored because k1 or k2 is given.\n"); } else - { if (!model->BSIM4vbxGiven) + { if (!model->BSIM4vbxGiven) pParam->BSIM4vbx = pParam->BSIM4phi - 7.7348e-4 * pParam->BSIM4ndep - * pParam->BSIM4xt * pParam->BSIM4xt; - if (pParam->BSIM4vbx > 0.0) - pParam->BSIM4vbx = -pParam->BSIM4vbx; - if (pParam->BSIM4vbm > 0.0) + * pParam->BSIM4xt * pParam->BSIM4xt; + if (pParam->BSIM4vbx > 0.0) + pParam->BSIM4vbx = -pParam->BSIM4vbx; + if (pParam->BSIM4vbm > 0.0) pParam->BSIM4vbm = -pParam->BSIM4vbm; if (!model->BSIM4gamma1Given) pParam->BSIM4gamma1 = 5.753e-12 - * sqrt(pParam->BSIM4ndep) + * sqrt(pParam->BSIM4ndep) / model->BSIM4coxe; if (!model->BSIM4gamma2Given) pParam->BSIM4gamma2 = 5.753e-12 - * sqrt(pParam->BSIM4nsub) + * sqrt(pParam->BSIM4nsub) / model->BSIM4coxe; T0 = pParam->BSIM4gamma1 - pParam->BSIM4gamma2; T1 = sqrt(pParam->BSIM4phi - pParam->BSIM4vbx) - - pParam->BSIM4sqrtPhi; + - pParam->BSIM4sqrtPhi; T2 = sqrt(pParam->BSIM4phi * (pParam->BSIM4phi - - pParam->BSIM4vbm)) - pParam->BSIM4phi; + - pParam->BSIM4vbm)) - pParam->BSIM4phi; pParam->BSIM4k2 = T0 * T1 / (2.0 * T2 + pParam->BSIM4vbm); pParam->BSIM4k1 = pParam->BSIM4gamma2 - 2.0 - * pParam->BSIM4k2 * sqrt(pParam->BSIM4phi - - pParam->BSIM4vbm); + * pParam->BSIM4k2 * sqrt(pParam->BSIM4phi + - pParam->BSIM4vbm); } if (!model->BSIM4vfbGiven) { - if (model->BSIM4vth0Given) + if (model->BSIM4vth0Given) { pParam->BSIM4vfb = model->BSIM4type * pParam->BSIM4vth0 - pParam->BSIM4phi - pParam->BSIM4k1 * pParam->BSIM4sqrtPhi; } else - { - if ((model->BSIM4mtrlMod) && (model->BSIM4phigGiven) && - (model->BSIM4nsubGiven)) - { - T0 = Vtm0 * log(pParam->BSIM4nsub/ni); - T1 = 0.5 * Eg0; - if(T0 > T1) - T0 = T1; - T2 = model->BSIM4easub + T1 + model->BSIM4type * T0; - pParam->BSIM4vfb = model->BSIM4phig - T2; - } - else - { - pParam->BSIM4vfb = -1.0; - } - } + { + if ((model->BSIM4mtrlMod) && (model->BSIM4phigGiven) && + (model->BSIM4nsubGiven)) + { + T0 = Vtm0 * log(pParam->BSIM4nsub/ni); + T1 = 0.5 * Eg0; + if(T0 > T1) + T0 = T1; + T2 = model->BSIM4easub + T1 + model->BSIM4type * T0; + pParam->BSIM4vfb = model->BSIM4phig - T2; + } + else + { + pParam->BSIM4vfb = -1.0; + } + } } if (!model->BSIM4vth0Given) { pParam->BSIM4vth0 = model->BSIM4type * (pParam->BSIM4vfb @@ -1500,21 +1511,21 @@ int Size_Not_Found, i; / model->BSIM4toxm; tmp = sqrt(epssub / (epsrox * EPS0) * toxe * pParam->BSIM4Xdep0); - T0 = pParam->BSIM4dsub * pParam->BSIM4leff / tmp; + T0 = pParam->BSIM4dsub * pParam->BSIM4leff / tmp; if (T0 < EXP_THRESHOLD) - { T1 = exp(T0); - T2 = T1 - 1.0; - T3 = T2 * T2; + { T1 = exp(T0); + T2 = T1 - 1.0; + T3 = T2 * T2; T4 = T3 + 2.0 * T1 * MIN_EXP; pParam->BSIM4theta0vb0 = T1 / T4; } else pParam->BSIM4theta0vb0 = 1.0 / (MAX_EXP - 2.0); - T0 = pParam->BSIM4drout * pParam->BSIM4leff / tmp; - if (T0 < EXP_THRESHOLD) - { T1 = exp(T0); - T2 = T1 - 1.0; + T0 = pParam->BSIM4drout * pParam->BSIM4leff / tmp; + if (T0 < EXP_THRESHOLD) + { T1 = exp(T0); + T2 = T1 - 1.0; T3 = T2 * T2; T4 = T3 + 2.0 * T1 * MIN_EXP; T5 = T1 / T4; @@ -1559,25 +1570,25 @@ int Size_Not_Found, i; T0 = sqrt(1.0 + pParam->BSIM4lpe0 / pParam->BSIM4leff); if((model->BSIM4tempMod == 1) || (model->BSIM4tempMod == 0)) - T3 = (pParam->BSIM4kt1 + pParam->BSIM4kt1l / pParam->BSIM4leff) - * (TRatio - 1.0); + T3 = (pParam->BSIM4kt1 + pParam->BSIM4kt1l / pParam->BSIM4leff) + * (TRatio - 1.0); if((model->BSIM4tempMod == 2)||(model->BSIM4tempMod == 3)) T3 = - pParam->BSIM4kt1 * (TRatio - 1.0); T5 = pParam->BSIM4k1ox * (T0 - 1.0) * pParam->BSIM4sqrtPhi + T3; pParam->BSIM4vfbzbfactor = - T8 - T9 + pParam->BSIM4k3 * T4 + T5 - - pParam->BSIM4phi - pParam->BSIM4k1 * pParam->BSIM4sqrtPhi; + - pParam->BSIM4phi - pParam->BSIM4k1 * pParam->BSIM4sqrtPhi; - /* stress effect */ + /* stress effect */ - wlod = model->BSIM4wlod; - if (model->BSIM4wlod < 0.0) - { fprintf(stderr, "Warning: WLOD = %g is less than 0. 0.0 is used\n",model->BSIM4wlod); - wlod = 0.0; - } + wlod = model->BSIM4wlod; + if (model->BSIM4wlod < 0.0) + { fprintf(stderr, "Warning: WLOD = %g is less than 0. 0.0 is used\n",model->BSIM4wlod); + wlod = 0.0; + } T0 = pow(Lnew, model->BSIM4llodku0); - W_tmp = Wnew + wlod; + W_tmp = Wnew + wlod; T1 = pow(W_tmp, model->BSIM4wlodku0); tmp1 = model->BSIM4lku0 / T0 + model->BSIM4wku0 / T1 + model->BSIM4pku0 / (T0 * T1); @@ -1588,20 +1599,20 @@ int Size_Not_Found, i; tmp1 = model->BSIM4lkvth0 / T0 + model->BSIM4wkvth0 / T1 + model->BSIM4pkvth0 / (T0 * T1); pParam->BSIM4kvth0 = 1.0 + tmp1; - pParam->BSIM4kvth0 = sqrt(pParam->BSIM4kvth0*pParam->BSIM4kvth0 + DELTA); + pParam->BSIM4kvth0 = sqrt(pParam->BSIM4kvth0*pParam->BSIM4kvth0 + DELTA); T0 = (TRatio - 1.0); pParam->BSIM4ku0temp = pParam->BSIM4ku0 * (1.0 + model->BSIM4tku0 *T0) + DELTA; Inv_saref = 1.0/(model->BSIM4saref + 0.5*Ldrn); Inv_sbref = 1.0/(model->BSIM4sbref + 0.5*Ldrn); - pParam->BSIM4inv_od_ref = Inv_saref + Inv_sbref; - pParam->BSIM4rho_ref = model->BSIM4ku0 / pParam->BSIM4ku0temp * pParam->BSIM4inv_od_ref; + pParam->BSIM4inv_od_ref = Inv_saref + Inv_sbref; + pParam->BSIM4rho_ref = model->BSIM4ku0 / pParam->BSIM4ku0temp * pParam->BSIM4inv_od_ref; /*high k*/ /*Calculate VgsteffVth for mobMod=3*/ if(model->BSIM4mobMod==3) - { /*Calculate n @ Vbs=Vds=0*/ + { /*Calculate n @ Vbs=Vds=0*/ lt1 = model->BSIM4factor1* pParam->BSIM4sqrtXdep0; T0 = pParam->BSIM4dvt1 * pParam->BSIM4leff / lt1; if (T0 < EXP_THRESHOLD) @@ -1653,25 +1664,25 @@ int Size_Not_Found, i; /* stress effect */ if( (here->BSIM4sa > 0.0) && (here->BSIM4sb > 0.0) && - ((here->BSIM4nf == 1.0) || ((here->BSIM4nf > 1.0) && (here->BSIM4sd > 0.0))) ) - { Inv_sa = 0; - Inv_sb = 0; + ((here->BSIM4nf == 1.0) || ((here->BSIM4nf > 1.0) && (here->BSIM4sd > 0.0))) ) + { Inv_sa = 0; + Inv_sb = 0; - kvsat = model->BSIM4kvsat; - if (model->BSIM4kvsat < -1.0 ) - { fprintf(stderr, "Warning: KVSAT = %g is too small; -1.0 is used.\n",model->BSIM4kvsat); - kvsat = -1.0; - } - if (model->BSIM4kvsat > 1.0) - { fprintf(stderr, "Warning: KVSAT = %g is too big; 1.0 is used.\n",model->BSIM4kvsat); - kvsat = 1.0; - } + kvsat = model->BSIM4kvsat; + if (model->BSIM4kvsat < -1.0 ) + { fprintf(stderr, "Warning: KVSAT = %g is too small; -1.0 is used.\n",model->BSIM4kvsat); + kvsat = -1.0; + } + if (model->BSIM4kvsat > 1.0) + { fprintf(stderr, "Warning: KVSAT = %g is too big; 1.0 is used.\n",model->BSIM4kvsat); + kvsat = 1.0; + } - for(i = 0; i < here->BSIM4nf; i++){ - T0 = 1.0 / here->BSIM4nf / (here->BSIM4sa + 0.5*Ldrn + i * (here->BSIM4sd +Ldrn)); - T1 = 1.0 / here->BSIM4nf / (here->BSIM4sb + 0.5*Ldrn + i * (here->BSIM4sd +Ldrn)); - Inv_sa += T0; - Inv_sb += T1; + for(i = 0; i < here->BSIM4nf; i++){ + T0 = 1.0 / here->BSIM4nf / (here->BSIM4sa + 0.5*Ldrn + i * (here->BSIM4sd +Ldrn)); + T1 = 1.0 / here->BSIM4nf / (here->BSIM4sb + 0.5*Ldrn + i * (here->BSIM4sd +Ldrn)); + Inv_sa += T0; + Inv_sb += T1; } Inv_ODeff = Inv_sa + Inv_sb; rho = model->BSIM4ku0 / pParam->BSIM4ku0temp * Inv_ODeff; @@ -1681,46 +1692,46 @@ int Size_Not_Found, i; T1 = (1.0 + kvsat * rho)/(1.0 + kvsat * pParam->BSIM4rho_ref); here->BSIM4vsattemp = pParam->BSIM4vsattemp * T1; - OD_offset = Inv_ODeff - pParam->BSIM4inv_od_ref; - dvth0_lod = model->BSIM4kvth0 / pParam->BSIM4kvth0 * OD_offset; + OD_offset = Inv_ODeff - pParam->BSIM4inv_od_ref; + dvth0_lod = model->BSIM4kvth0 / pParam->BSIM4kvth0 * OD_offset; dk2_lod = model->BSIM4stk2 / pow(pParam->BSIM4kvth0, model->BSIM4lodk2) * OD_offset; deta0_lod = model->BSIM4steta0 / pow(pParam->BSIM4kvth0, model->BSIM4lodeta0) * OD_offset; - here->BSIM4vth0 = pParam->BSIM4vth0 + dvth0_lod; + here->BSIM4vth0 = pParam->BSIM4vth0 + dvth0_lod; here->BSIM4eta0 = pParam->BSIM4eta0 + deta0_lod; - here->BSIM4k2 = pParam->BSIM4k2 + dk2_lod; - } else { - here->BSIM4u0temp = pParam->BSIM4u0temp; + here->BSIM4k2 = pParam->BSIM4k2 + dk2_lod; + } else { + here->BSIM4u0temp = pParam->BSIM4u0temp; here->BSIM4vth0 = pParam->BSIM4vth0; here->BSIM4vsattemp = pParam->BSIM4vsattemp; here->BSIM4eta0 = pParam->BSIM4eta0; here->BSIM4k2 = pParam->BSIM4k2; } - /* Well Proximity Effect */ + /* Well Proximity Effect */ if (model->BSIM4wpemod) { if( (!here->BSIM4scaGiven) && (!here->BSIM4scbGiven) && (!here->BSIM4sccGiven) ) - { if((here->BSIM4scGiven) && (here->BSIM4sc > 0.0) ) - { T1 = here->BSIM4sc + Wdrn; - T2 = 1.0 / model->BSIM4scref; - here->BSIM4sca = model->BSIM4scref * model->BSIM4scref - / (here->BSIM4sc * T1); - here->BSIM4scb = ( (0.1 * here->BSIM4sc + 0.01 * model->BSIM4scref) - * exp(-10.0 * here->BSIM4sc * T2) - - (0.1 * T1 + 0.01 * model->BSIM4scref) - * exp(-10.0 * T1 * T2) ) / Wdrn; + { if((here->BSIM4scGiven) && (here->BSIM4sc > 0.0) ) + { T1 = here->BSIM4sc + Wdrn; + T2 = 1.0 / model->BSIM4scref; + here->BSIM4sca = model->BSIM4scref * model->BSIM4scref + / (here->BSIM4sc * T1); + here->BSIM4scb = ( (0.1 * here->BSIM4sc + 0.01 * model->BSIM4scref) + * exp(-10.0 * here->BSIM4sc * T2) + - (0.1 * T1 + 0.01 * model->BSIM4scref) + * exp(-10.0 * T1 * T2) ) / Wdrn; here->BSIM4scc = ( (0.05 * here->BSIM4sc + 0.0025 * model->BSIM4scref) * exp(-20.0 * here->BSIM4sc * T2) - (0.05 * T1 + 0.0025 * model->BSIM4scref) * exp(-20.0 * T1 * T2) ) / Wdrn; - } else { + } else { fprintf(stderr, "Warning: No WPE as none of SCA, SCB, SCC, SC is given and/or SC not positive.\n"); - } - } + } + } - if (here->BSIM4sca < 0.0) + if (here->BSIM4sca < 0.0) { printf("Warning: SCA = %g is negative. Set to 0.0.\n", here->BSIM4sca); here->BSIM4sca = 0.0; @@ -1740,27 +1751,24 @@ int Size_Not_Found, i; printf("Warning: SC = %g is negative. Set to 0.0.\n", here->BSIM4sc); here->BSIM4sc = 0.0; } - /*4.6.2*/ - sceff = here->BSIM4sca + model->BSIM4web * here->BSIM4scb + /*4.6.2*/ + sceff = here->BSIM4sca + model->BSIM4web * here->BSIM4scb + model->BSIM4wec * here->BSIM4scc; here->BSIM4vth0 += pParam->BSIM4kvth0we * sceff; here->BSIM4k2 += pParam->BSIM4k2we * sceff; - T3 = 1.0 + pParam->BSIM4ku0we * sceff; - if (T3 <= 0.0) - { T3 = 0.0; - fprintf(stderr, "Warning: ku0we = %g is negatively too high. Negative mobility! \n", pParam->BSIM4ku0we); - } + T3 = 1.0 + pParam->BSIM4ku0we * sceff; + if (T3 <= 0.0) + { T3 = 0.0; + fprintf(stderr, "Warning: ku0we = %g is negatively too high. Negative mobility! \n",pParam->BSIM4ku0we); + } here->BSIM4u0temp *= T3; } - /* adding delvto */ + /* adding delvto */ 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 */ + /* Instance variables calculation */ T3 = model->BSIM4type * here->BSIM4vth0 - here->BSIM4vfb - pParam->BSIM4phi; T4 = T3 + T3; @@ -1789,80 +1797,81 @@ int Size_Not_Found, i; / model->BSIM4toxm; here->BSIM4vfbzb = pParam->BSIM4vfbzbfactor - + model->BSIM4type * here->BSIM4vth0 ; + + model->BSIM4type * here->BSIM4vth0 ; here->BSIM4cgso = pParam->BSIM4cgso; here->BSIM4cgdo = pParam->BSIM4cgdo; - lnl = log(pParam->BSIM4leff * 1.0e6); - lnw = log(pParam->BSIM4weff * 1.0e6); - lnnf = log(here->BSIM4nf); + lnl = log(pParam->BSIM4leff * 1.0e6); + lnw = log(pParam->BSIM4weff * 1.0e6); + lnnf = log(here->BSIM4nf); - bodymode = 5; - if( ( !model->BSIM4rbps0Given) || - ( !model->BSIM4rbpd0Given) ) - bodymode = 1; - else - if( (!model->BSIM4rbsbx0Given && !model->BSIM4rbsby0Given) || - (!model->BSIM4rbdbx0Given && !model->BSIM4rbdby0Given) ) + bodymode = 5; + if( ( !model->BSIM4rbps0Given) || + ( !model->BSIM4rbpd0Given) ) + bodymode = 1; + else + if( (!model->BSIM4rbsbx0Given && !model->BSIM4rbsby0Given) || + (!model->BSIM4rbdbx0Given && !model->BSIM4rbdby0Given) ) bodymode = 3; - if(here->BSIM4rbodyMod == 2) - { - if (bodymode == 5) - { - /*rbsbx = exp( log(model->BSIM4rbsbx0) + model->BSIM4rbsdbxl * lnl + - model->BSIM4rbsdbxw * lnw + model->BSIM4rbsdbxnf * lnnf ); - rbsby = exp( log(model->BSIM4rbsby0) + model->BSIM4rbsdbyl * lnl + - model->BSIM4rbsdbyw * lnw + model->BSIM4rbsdbynf * lnnf ); - */ - rbsbx = model->BSIM4rbsbx0 * exp( model->BSIM4rbsdbxl * lnl + - model->BSIM4rbsdbxw * lnw + model->BSIM4rbsdbxnf * lnnf ); - rbsby = model->BSIM4rbsby0 * exp( model->BSIM4rbsdbyl * lnl + - model->BSIM4rbsdbyw * lnw + model->BSIM4rbsdbynf * lnnf ); - here->BSIM4rbsb = rbsbx * rbsby / (rbsbx + rbsby); + if(here->BSIM4rbodyMod == 2) + { + if (bodymode == 5) + { + /*rbsbx = exp( log(model->BSIM4rbsbx0) + model->BSIM4rbsdbxl * lnl + + model->BSIM4rbsdbxw * lnw + model->BSIM4rbsdbxnf * lnnf ); + rbsby = exp( log(model->BSIM4rbsby0) + model->BSIM4rbsdbyl * lnl + + model->BSIM4rbsdbyw * lnw + model->BSIM4rbsdbynf * lnnf ); + */ + rbsbx = model->BSIM4rbsbx0 * exp( model->BSIM4rbsdbxl * lnl + + model->BSIM4rbsdbxw * lnw + model->BSIM4rbsdbxnf * lnnf ); + rbsby = model->BSIM4rbsby0 * exp( model->BSIM4rbsdbyl * lnl + + model->BSIM4rbsdbyw * lnw + model->BSIM4rbsdbynf * lnnf ); + here->BSIM4rbsb = rbsbx * rbsby / (rbsbx + rbsby); - /*rbdbx = exp( log(model->BSIM4rbdbx0) + model->BSIM4rbsdbxl * lnl + - model->BSIM4rbsdbxw * lnw + model->BSIM4rbsdbxnf * lnnf ); - rbdby = exp( log(model->BSIM4rbdby0) + model->BSIM4rbsdbyl * lnl + - model->BSIM4rbsdbyw * lnw + model->BSIM4rbsdbynf * lnnf ); - */ + /*rbdbx = exp( log(model->BSIM4rbdbx0) + model->BSIM4rbsdbxl * lnl + + model->BSIM4rbsdbxw * lnw + model->BSIM4rbsdbxnf * lnnf ); + rbdby = exp( log(model->BSIM4rbdby0) + model->BSIM4rbsdbyl * lnl + + model->BSIM4rbsdbyw * lnw + model->BSIM4rbsdbynf * lnnf ); + */ - rbdbx = model->BSIM4rbdbx0 * exp( model->BSIM4rbsdbxl * lnl + - model->BSIM4rbsdbxw * lnw + model->BSIM4rbsdbxnf * lnnf ); - rbdby = model->BSIM4rbdby0 * exp( model->BSIM4rbsdbyl * lnl + - model->BSIM4rbsdbyw * lnw + model->BSIM4rbsdbynf * lnnf ); + rbdbx = model->BSIM4rbdbx0 * exp( model->BSIM4rbsdbxl * lnl + + model->BSIM4rbsdbxw * lnw + model->BSIM4rbsdbxnf * lnnf ); + rbdby = model->BSIM4rbdby0 * exp( model->BSIM4rbsdbyl * lnl + + model->BSIM4rbsdbyw * lnw + model->BSIM4rbsdbynf * lnnf ); - here->BSIM4rbdb = rbdbx * rbdby / (rbdbx + rbdby); - } + here->BSIM4rbdb = rbdbx * rbdby / (rbdbx + rbdby); + } - if ((bodymode == 3)|| (bodymode == 5)) - { - /*here->BSIM4rbps = exp( log(model->BSIM4rbps0) + model->BSIM4rbpsl * lnl + - model->BSIM4rbpsw * lnw + model->BSIM4rbpsnf * lnnf ); - here->BSIM4rbpd = exp( log(model->BSIM4rbpd0) + model->BSIM4rbpdl * lnl + - model->BSIM4rbpdw * lnw + model->BSIM4rbpdnf * lnnf ); - */ - here->BSIM4rbps = model->BSIM4rbps0 * exp( model->BSIM4rbpsl * lnl + - model->BSIM4rbpsw * lnw + model->BSIM4rbpsnf * lnnf ); - here->BSIM4rbpd = model->BSIM4rbpd0 * exp( model->BSIM4rbpdl * lnl + - model->BSIM4rbpdw * lnw + model->BSIM4rbpdnf * lnnf ); + if ((bodymode == 3)|| (bodymode == 5)) + { + /*here->BSIM4rbps = exp( log(model->BSIM4rbps0) + model->BSIM4rbpsl * lnl + + model->BSIM4rbpsw * lnw + model->BSIM4rbpsnf * lnnf ); + here->BSIM4rbpd = exp( log(model->BSIM4rbpd0) + model->BSIM4rbpdl * lnl + + model->BSIM4rbpdw * lnw + model->BSIM4rbpdnf * lnnf ); + */ + here->BSIM4rbps = model->BSIM4rbps0 * exp( model->BSIM4rbpsl * lnl + + model->BSIM4rbpsw * lnw + model->BSIM4rbpsnf * lnnf ); + here->BSIM4rbpd = model->BSIM4rbpd0 * exp( model->BSIM4rbpdl * lnl + + model->BSIM4rbpdw * lnw + model->BSIM4rbpdnf * lnnf ); - } + } - /*rbpbx = exp( log(model->BSIM4rbpbx0) + model->BSIM4rbpbxl * lnl + - model->BSIM4rbpbxw * lnw + model->BSIM4rbpbxnf * lnnf ); - rbpby = exp( log(model->BSIM4rbpby0) + model->BSIM4rbpbyl * lnl + - model->BSIM4rbpbyw * lnw + model->BSIM4rbpbynf * lnnf ); - */ - rbpbx = model->BSIM4rbpbx0 * exp( model->BSIM4rbpbxl * lnl + - model->BSIM4rbpbxw * lnw + model->BSIM4rbpbxnf * lnnf ); - rbpby = model->BSIM4rbpby0 * exp( model->BSIM4rbpbyl * lnl + - model->BSIM4rbpbyw * lnw + model->BSIM4rbpbynf * lnnf ); + /*rbpbx = exp( log(model->BSIM4rbpbx0) + model->BSIM4rbpbxl * lnl + + model->BSIM4rbpbxw * lnw + model->BSIM4rbpbxnf * lnnf ); + rbpby = exp( log(model->BSIM4rbpby0) + model->BSIM4rbpbyl * lnl + + model->BSIM4rbpbyw * lnw + model->BSIM4rbpbynf * lnnf ); + */ + rbpbx = model->BSIM4rbpbx0 * exp( model->BSIM4rbpbxl * lnl + + model->BSIM4rbpbxw * lnw + model->BSIM4rbpbxnf * lnnf ); + rbpby = model->BSIM4rbpby0 * exp( model->BSIM4rbpbyl * lnl + + model->BSIM4rbpbyw * lnw + model->BSIM4rbpbynf * lnnf ); + + here->BSIM4rbpb = rbpbx*rbpby/(rbpbx + rbpby); + } - here->BSIM4rbpb = rbpbx*rbpby/(rbpbx + rbpby); - } if ((here->BSIM4rbodyMod == 1 ) || ((here->BSIM4rbodyMod == 2 ) && (bodymode == 5)) ) { if (here->BSIM4rbdb < 1.0e-3) @@ -1888,7 +1897,7 @@ int Size_Not_Found, i; } - if((here->BSIM4rbodyMod == 2) && (bodymode == 3)) + if((here->BSIM4rbodyMod == 2) && (bodymode == 3)) { here->BSIM4grbdb = here->BSIM4grbsb = model->BSIM4gbmin; if (here->BSIM4rbpb < 1.0e-3) @@ -1905,10 +1914,10 @@ int Size_Not_Found, i; here->BSIM4grbpd = model->BSIM4gbmin + 1.0 / here->BSIM4rbpd; } - if((here->BSIM4rbodyMod == 2) && (bodymode == 1)) + if((here->BSIM4rbodyMod == 2) && (bodymode == 1)) { here->BSIM4grbdb = here->BSIM4grbsb = model->BSIM4gbmin; - here->BSIM4grbps = here->BSIM4grbpd = 1.0e3; + here->BSIM4grbps = here->BSIM4grbpd = 1.0e3; if (here->BSIM4rbpb < 1.0e-3) here->BSIM4grbpb = 1.0e3; else @@ -1918,7 +1927,7 @@ int Size_Not_Found, i; /* * Process geomertry dependent parasitics - */ + */ here->BSIM4grgeltd = model->BSIM4rshg * (here->BSIM4xgw + pParam->BSIM4weffCJ / 3.0 / here->BSIM4ngcon) / @@ -1928,114 +1937,114 @@ int Size_Not_Found, i; here->BSIM4grgeltd = 1.0 / here->BSIM4grgeltd; else { here->BSIM4grgeltd = 1.0e3; /* mho */ - if (here->BSIM4rgateMod != 0) + if (here->BSIM4rgateMod != 0) printf("Warning: The gate conductance reset to 1.0e3 mho.\n"); } - DMCGeff = model->BSIM4dmcg - model->BSIM4dmcgt; + DMCGeff = model->BSIM4dmcg - model->BSIM4dmcgt; DMCIeff = model->BSIM4dmci; DMDGeff = model->BSIM4dmdg - model->BSIM4dmcgt; -/* if (here->BSIM4sourcePerimeterGiven) - { if (model->BSIM4perMod == 0) - here->BSIM4Pseff = here->BSIM4sourcePerimeter; - else - here->BSIM4Pseff = here->BSIM4sourcePerimeter - - pParam->BSIM4weffCJ * here->BSIM4nf; - } - else - BSIM4PAeffGeo(here->BSIM4nf, here->BSIM4geoMod, here->BSIM4min, +/* if (here->BSIM4sourcePerimeterGiven) + { if (model->BSIM4perMod == 0) + here->BSIM4Pseff = here->BSIM4sourcePerimeter; + else + here->BSIM4Pseff = here->BSIM4sourcePerimeter + - pParam->BSIM4weffCJ * here->BSIM4nf; + } + else + BSIM4PAeffGeo(here->BSIM4nf, here->BSIM4geoMod, here->BSIM4min, pParam->BSIM4weffCJ, DMCGeff, DMCIeff, DMDGeff, - &(here->BSIM4Pseff), &dumPd, &dumAs, &dumAd); + &(here->BSIM4Pseff), &dumPd, &dumAs, &dumAd); if (here->BSIM4Pseff < 0.0) /4.6.2/ - here->BSIM4Pseff = 0.0; */ + here->BSIM4Pseff = 0.0; */ - /* New Diode Model v4.7*/ - if (here->BSIM4sourcePerimeterGiven) - { /* given */ - if (here->BSIM4sourcePerimeter == 0.0) - here->BSIM4Pseff = 0.0; - else if (here->BSIM4sourcePerimeter < 0.0) - { - printf("Warning: Source Perimeter is specified as negative, it is set to zero.\n"); - here->BSIM4Pseff = 0.0; - } else - { - if (model->BSIM4perMod == 0) - here->BSIM4Pseff = here->BSIM4sourcePerimeter; - else - here->BSIM4Pseff = here->BSIM4sourcePerimeter - - pParam->BSIM4weffCJ * here->BSIM4nf; - } - } else /* not given */ - BSIM4PAeffGeo(here->BSIM4nf, here->BSIM4geoMod, here->BSIM4min, + /* New Diode Model v4.7*/ + if (here->BSIM4sourcePerimeterGiven) + { /* given */ + if (here->BSIM4sourcePerimeter == 0.0) + here->BSIM4Pseff = 0.0; + else if (here->BSIM4sourcePerimeter < 0.0) + { + printf("Warning: Source Perimeter is specified as negative, it is set to zero.\n"); + here->BSIM4Pseff = 0.0; + } else + { + if (model->BSIM4perMod == 0) + here->BSIM4Pseff = here->BSIM4sourcePerimeter; + else + here->BSIM4Pseff = here->BSIM4sourcePerimeter + - pParam->BSIM4weffCJ * here->BSIM4nf; + } + } else /* not given */ + BSIM4PAeffGeo(here->BSIM4nf, here->BSIM4geoMod, here->BSIM4min, pParam->BSIM4weffCJ, DMCGeff, DMCIeff, DMDGeff, - &(here->BSIM4Pseff), &dumPd, &dumAs, &dumAd); + &(here->BSIM4Pseff), &dumPd, &dumAs, &dumAd); - if (here->BSIM4Pseff < 0.0){ /* v4.7 final check */ - here->BSIM4Pseff = 0.0; - printf("Warning: Pseff is negative, it is set to zero.\n"); - } - /* if (here->BSIM4drainPerimeterGiven) + if (here->BSIM4Pseff < 0.0){ /* v4.7 final check */ + here->BSIM4Pseff = 0.0; + printf("Warning: Pseff is negative, it is set to zero.\n"); + } + /* if (here->BSIM4drainPerimeterGiven) { if (model->BSIM4perMod == 0) here->BSIM4Pdeff = here->BSIM4drainPerimeter; else here->BSIM4Pdeff = here->BSIM4drainPerimeter - - pParam->BSIM4weffCJ * here->BSIM4nf; + - pParam->BSIM4weffCJ * here->BSIM4nf; } else BSIM4PAeffGeo(here->BSIM4nf, here->BSIM4geoMod, here->BSIM4min, pParam->BSIM4weffCJ, DMCGeff, DMCIeff, DMDGeff, - &dumPs, &(here->BSIM4Pdeff), &dumAs, &dumAd); + &dumPs, &(here->BSIM4Pdeff), &dumAs, &dumAd); if (here->BSIM4Pdeff < 0.0) /4.6.2/ - here->BSIM4Pdeff = 0.0; */ + here->BSIM4Pdeff = 0.0; */ - if (here->BSIM4drainPerimeterGiven) - { /* given */ - if (here->BSIM4drainPerimeter == 0.0) - here->BSIM4Pdeff = 0.0; - else if (here->BSIM4drainPerimeter < 0.0) - { - printf("Warning: Drain Perimeter is specified as negative, it is set to zero.\n"); - here->BSIM4Pdeff = 0.0; - } else - { - if (model->BSIM4perMod == 0) - here->BSIM4Pdeff = here->BSIM4drainPerimeter; - else - here->BSIM4Pdeff = here->BSIM4drainPerimeter - - pParam->BSIM4weffCJ * here->BSIM4nf; - } - } else /* not given */ - BSIM4PAeffGeo(here->BSIM4nf, here->BSIM4geoMod, here->BSIM4min, - pParam->BSIM4weffCJ, DMCGeff, DMCIeff, DMDGeff, - &dumPs, &(here->BSIM4Pdeff), &dumAs, &dumAd); - - if (here->BSIM4Pdeff < 0.0){ - here->BSIM4Pdeff = 0.0; /*New Diode v4.7*/ - printf("Warning: Pdeff is negative, it is set to zero.\n"); + if (here->BSIM4drainPerimeterGiven) + { /* given */ + if (here->BSIM4drainPerimeter == 0.0) + here->BSIM4Pdeff = 0.0; + else if (here->BSIM4drainPerimeter < 0.0) + { + printf("Warning: Drain Perimeter is specified as negative, it is set to zero.\n"); + here->BSIM4Pdeff = 0.0; + } else + { + if (model->BSIM4perMod == 0) + here->BSIM4Pdeff = here->BSIM4drainPerimeter; + else + here->BSIM4Pdeff = here->BSIM4drainPerimeter + - pParam->BSIM4weffCJ * here->BSIM4nf; } + } else /* not given */ + BSIM4PAeffGeo(here->BSIM4nf, here->BSIM4geoMod, here->BSIM4min, + pParam->BSIM4weffCJ, DMCGeff, DMCIeff, DMDGeff, + &dumPs, &(here->BSIM4Pdeff), &dumAs, &dumAd); + + if (here->BSIM4Pdeff < 0.0){ + here->BSIM4Pdeff = 0.0; /*New Diode v4.7*/ + printf("Warning: Pdeff is negative, it is set to zero.\n"); + } if (here->BSIM4sourceAreaGiven) here->BSIM4Aseff = here->BSIM4sourceArea; else BSIM4PAeffGeo(here->BSIM4nf, here->BSIM4geoMod, here->BSIM4min, pParam->BSIM4weffCJ, DMCGeff, DMCIeff, DMDGeff, - &dumPs, &dumPd, &(here->BSIM4Aseff), &dumAd); - if (here->BSIM4Aseff < 0.0){ - here->BSIM4Aseff = 0.0; /* v4.7 */ - printf("Warning: Aseff is negative, it is set to zero.\n"); + &dumPs, &dumPd, &(here->BSIM4Aseff), &dumAd); + if (here->BSIM4Aseff < 0.0){ + here->BSIM4Aseff = 0.0; /* v4.7 */ + printf("Warning: Aseff is negative, it is set to zero.\n"); } if (here->BSIM4drainAreaGiven) here->BSIM4Adeff = here->BSIM4drainArea; else BSIM4PAeffGeo(here->BSIM4nf, here->BSIM4geoMod, here->BSIM4min, pParam->BSIM4weffCJ, DMCGeff, DMCIeff, DMDGeff, - &dumPs, &dumPd, &dumAs, &(here->BSIM4Adeff)); - if (here->BSIM4Adeff < 0.0){ - here->BSIM4Adeff = 0.0; /* v4.7 */ - printf("Warning: Adeff is negative, it is set to zero.\n"); + &dumPs, &dumPd, &dumAs, &(here->BSIM4Adeff)); + if (here->BSIM4Adeff < 0.0){ + here->BSIM4Adeff = 0.0; /* v4.7 */ + printf("Warning: Adeff is negative, it is set to zero.\n"); } - /* Processing S/D resistance and conductance below */ + /* Processing S/D resistance and conductance below */ if(here->BSIM4sNodePrime != here->BSIM4sNode) { here->BSIM4sourceConductance = 0.0; @@ -2104,56 +2113,56 @@ int Size_Not_Found, i; Nvtms = model->BSIM4vtm * model->BSIM4SjctEmissionCoeff; if ((here->BSIM4Aseff <= 0.0) && (here->BSIM4Pseff <= 0.0)) { SourceSatCurrent = 0.0; /* v4.7 */ - /* SourceSatCurrent = 1.0e-14; */ + /* SourceSatCurrent = 1.0e-14; */ } else { SourceSatCurrent = here->BSIM4Aseff * model->BSIM4SjctTempSatCurDensity - + here->BSIM4Pseff * model->BSIM4SjctSidewallTempSatCurDensity + + here->BSIM4Pseff * model->BSIM4SjctSidewallTempSatCurDensity + pParam->BSIM4weffCJ * here->BSIM4nf * model->BSIM4SjctGateSidewallTempSatCurDensity; } if (SourceSatCurrent > 0.0) { switch(model->BSIM4dioMod) { case 0: - if ((model->BSIM4bvs / Nvtms) > EXP_THRESHOLD) - here->BSIM4XExpBVS = model->BSIM4xjbvs * MIN_EXP; - else - here->BSIM4XExpBVS = model->BSIM4xjbvs * exp(-model->BSIM4bvs / Nvtms); - break; + if ((model->BSIM4bvs / Nvtms) > EXP_THRESHOLD) + here->BSIM4XExpBVS = model->BSIM4xjbvs * MIN_EXP; + else + here->BSIM4XExpBVS = model->BSIM4xjbvs * exp(-model->BSIM4bvs / Nvtms); + break; case 1: BSIM4DioIjthVjmEval(Nvtms, model->BSIM4ijthsfwd, SourceSatCurrent, - 0.0, &(here->BSIM4vjsmFwd)); + 0.0, &(here->BSIM4vjsmFwd)); here->BSIM4IVjsmFwd = SourceSatCurrent * exp(here->BSIM4vjsmFwd / Nvtms); break; case 2: if ((model->BSIM4bvs / Nvtms) > EXP_THRESHOLD) { here->BSIM4XExpBVS = model->BSIM4xjbvs * MIN_EXP; - tmp = MIN_EXP; - } + tmp = MIN_EXP; + } else - { here->BSIM4XExpBVS = exp(-model->BSIM4bvs / Nvtms); - tmp = here->BSIM4XExpBVS; - here->BSIM4XExpBVS *= model->BSIM4xjbvs; - } + { here->BSIM4XExpBVS = exp(-model->BSIM4bvs / Nvtms); + tmp = here->BSIM4XExpBVS; + here->BSIM4XExpBVS *= model->BSIM4xjbvs; + } BSIM4DioIjthVjmEval(Nvtms, model->BSIM4ijthsfwd, SourceSatCurrent, - here->BSIM4XExpBVS, &(here->BSIM4vjsmFwd)); - T0 = exp(here->BSIM4vjsmFwd / Nvtms); + here->BSIM4XExpBVS, &(here->BSIM4vjsmFwd)); + T0 = exp(here->BSIM4vjsmFwd / Nvtms); here->BSIM4IVjsmFwd = SourceSatCurrent * (T0 - here->BSIM4XExpBVS / T0 - + here->BSIM4XExpBVS - 1.0); - here->BSIM4SslpFwd = SourceSatCurrent - * (T0 + here->BSIM4XExpBVS / T0) / Nvtms; + + here->BSIM4XExpBVS - 1.0); + here->BSIM4SslpFwd = SourceSatCurrent + * (T0 + here->BSIM4XExpBVS / T0) / Nvtms; - T2 = model->BSIM4ijthsrev / SourceSatCurrent; - if (T2 < 1.0) - { T2 = 10.0; - fprintf(stderr, "Warning: ijthsrev too small and set to 10 times IsbSat.\n"); - } + T2 = model->BSIM4ijthsrev / SourceSatCurrent; + if (T2 < 1.0) + { T2 = 10.0; + fprintf(stderr, "Warning: ijthsrev too small and set to 10 times IsbSat.\n"); + } here->BSIM4vjsmRev = -model->BSIM4bvs - - Nvtms * log((T2 - 1.0) / model->BSIM4xjbvs); - T1 = model->BSIM4xjbvs * exp(-(model->BSIM4bvs - + here->BSIM4vjsmRev) / Nvtms); - here->BSIM4IVjsmRev = SourceSatCurrent * (1.0 + T1); + - Nvtms * log((T2 - 1.0) / model->BSIM4xjbvs); + T1 = model->BSIM4xjbvs * exp(-(model->BSIM4bvs + + here->BSIM4vjsmRev) / Nvtms); + here->BSIM4IVjsmRev = SourceSatCurrent * (1.0 + T1); here->BSIM4SslpRev = -SourceSatCurrent * T1 / Nvtms; break; default: @@ -2162,13 +2171,13 @@ int Size_Not_Found, i; } Nvtmd = model->BSIM4vtm * model->BSIM4DjctEmissionCoeff; - if ((here->BSIM4Adeff <= 0.0) && (here->BSIM4Pdeff <= 0.0)) - { /* DrainSatCurrent = 1.0e-14; v4.7 */ - DrainSatCurrent = 0.0; + if ((here->BSIM4Adeff <= 0.0) && (here->BSIM4Pdeff <= 0.0)) + { /* DrainSatCurrent = 1.0e-14; v4.7 */ + DrainSatCurrent = 0.0; } else { DrainSatCurrent = here->BSIM4Adeff * model->BSIM4DjctTempSatCurDensity - + here->BSIM4Pdeff * model->BSIM4DjctSidewallTempSatCurDensity + + here->BSIM4Pdeff * model->BSIM4DjctSidewallTempSatCurDensity + pParam->BSIM4weffCJ * here->BSIM4nf * model->BSIM4DjctGateSidewallTempSatCurDensity; } @@ -2221,8 +2230,8 @@ int Size_Not_Found, i; } } - /* GEDL current reverse bias */ - T0 = (TRatio - 1.0); + /* GEDL current reverse bias */ + T0 = (TRatio - 1.0); model->BSIM4njtsstemp = model->BSIM4njts * (1.0 + model->BSIM4tnjts * T0); model->BSIM4njtsswstemp = model->BSIM4njtssw * (1.0 + model->BSIM4tnjtssw * T0); model->BSIM4njtsswgstemp = model->BSIM4njtsswg * (1.0 + model->BSIM4tnjtsswg * T0); @@ -2242,116 +2251,125 @@ int Size_Not_Found, i; DEXP(T9, T5); T9 = model->BSIM4xtsswgd * T7; DEXP(T9, T6); - /*IBM TAT*/ - if(model->BSIM4jtweff < 0.0) - { model->BSIM4jtweff = 0.0; - fprintf(stderr, "TAT width dependence effect is negative. Jtweff is clamped to zero.\n"); - } - T11 = sqrt(model->BSIM4jtweff / pParam->BSIM4weffCJ) + 1.0; + /*IBM TAT*/ + if(model->BSIM4jtweff < 0.0) + { model->BSIM4jtweff = 0.0; + fprintf(stderr, "TAT width dependence effect is negative. Jtweff is clamped to zero.\n"); + } + T11 = sqrt(model->BSIM4jtweff / pParam->BSIM4weffCJ) + 1.0; - T10 = pParam->BSIM4weffCJ * here->BSIM4nf; - here->BSIM4SjctTempRevSatCur = T1 * here->BSIM4Aseff * model->BSIM4jtss; - here->BSIM4DjctTempRevSatCur = T2 * here->BSIM4Adeff * model->BSIM4jtsd; - here->BSIM4SswTempRevSatCur = T3 * here->BSIM4Pseff * model->BSIM4jtssws; - here->BSIM4DswTempRevSatCur = T4 * here->BSIM4Pdeff * model->BSIM4jtsswd; - here->BSIM4SswgTempRevSatCur = T5 * T10 * T11 * model->BSIM4jtsswgs; - here->BSIM4DswgTempRevSatCur = T6 * T10 * T11 * model->BSIM4jtsswgd; + T10 = pParam->BSIM4weffCJ * here->BSIM4nf; + here->BSIM4SjctTempRevSatCur = T1 * here->BSIM4Aseff * model->BSIM4jtss; + here->BSIM4DjctTempRevSatCur = T2 * here->BSIM4Adeff * model->BSIM4jtsd; + here->BSIM4SswTempRevSatCur = T3 * here->BSIM4Pseff * model->BSIM4jtssws; + here->BSIM4DswTempRevSatCur = T4 * here->BSIM4Pdeff * model->BSIM4jtsswd; + here->BSIM4SswgTempRevSatCur = T5 * T10 * T11 * model->BSIM4jtsswgs; + here->BSIM4DswgTempRevSatCur = T6 * T10 * T11 * model->BSIM4jtsswgd; if(model->BSIM4mtrlMod != 0 && model->BSIM4mtrlCompatMod == 0) { /* Calculate TOXP from EOT */ - /* Calculate Vgs_eff @ Vgs = VDD with Poly Depletion Effect */ - Vtm0eot = KboQ * model->BSIM4tempeot; - Vtmeot = Vtm0eot; - vbieot = Vtm0eot * log(pParam->BSIM4nsd - * pParam->BSIM4ndep / (ni * ni)); - phieot = Vtm0eot * log(pParam->BSIM4ndep / ni) - + pParam->BSIM4phin + 0.4; - tmp2 = here->BSIM4vfb + phieot; - vddeot = model->BSIM4type * model->BSIM4vddeot; - T0 = model->BSIM4epsrgate * EPS0; - if ((pParam->BSIM4ngate > 1.0e18) && (pParam->BSIM4ngate < 1.0e25) - && (vddeot > tmp2) && (T0!=0)) - { - T1 = 1.0e6 * CHARGE * T0 * pParam->BSIM4ngate / - (model->BSIM4coxe * model->BSIM4coxe); - T8 = vddeot - tmp2; - T4 = sqrt(1.0 + 2.0 * T8 / T1); - T2 = 2.0 * T8 / (T4 + 1.0); - T3 = 0.5 * T2 * T2 / T1; - T7 = 1.12 - T3 - 0.05; - T6 = sqrt(T7 * T7 + 0.224); - T5 = 1.12 - 0.5 * (T7 + T6); - Vgs_eff = vddeot - T5; - } - else - Vgs_eff = vddeot; + /* Calculate Vgs_eff @ Vgs = VDD with Poly Depletion Effect */ + Vtm0eot = KboQ * model->BSIM4tempeot; + Vtmeot = Vtm0eot; + vbieot = Vtm0eot * log(pParam->BSIM4nsd + * pParam->BSIM4ndep / (ni * ni)); + phieot = Vtm0eot * log(pParam->BSIM4ndep / ni) + + pParam->BSIM4phin + 0.4; + if(phieot <= 0.0) + { + printf("Fatal: phieot = %g is not positive. Please Check Phin and Ndep\n", + pParam->BSIM4phi); + printf("phieot = %g Ndep = %g \n", + pParam->BSIM4phin, pParam->BSIM4ndep); + Fatal_Flag = 1; + } - /* Calculate Vth @ Vds=Vbs=0 */ + tmp2 = here->BSIM4vfb + phieot; + vddeot = model->BSIM4type * model->BSIM4vddeot; + T0 = model->BSIM4epsrgate * EPS0; + if ((pParam->BSIM4ngate > 1.0e18) && (pParam->BSIM4ngate < 1.0e25) + && (vddeot > tmp2) && (T0!=0)) + { + T1 = 1.0e6 * CHARGE * T0 * pParam->BSIM4ngate / + (model->BSIM4coxe * model->BSIM4coxe); + T8 = vddeot - tmp2; + T4 = sqrt(1.0 + 2.0 * T8 / T1); + T2 = 2.0 * T8 / (T4 + 1.0); + T3 = 0.5 * T2 * T2 / T1; + T7 = 1.12 - T3 - 0.05; + T6 = sqrt(T7 * T7 + 0.224); + T5 = 1.12 - 0.5 * (T7 + T6); + Vgs_eff = vddeot - T5; + } + else + Vgs_eff = vddeot; - V0 = vbieot - phieot; - lt1 = model->BSIM4factor1* pParam->BSIM4sqrtXdep0; - ltw = lt1; - T0 = pParam->BSIM4dvt1 * model->BSIM4leffeot / lt1; - if (T0 < EXP_THRESHOLD) - { - T1 = exp(T0); - T2 = T1 - 1.0; - T3 = T2 * T2; - T4 = T3 + 2.0 * T1 * MIN_EXP; - Theta0 = T1 / T4; - } - else - Theta0 = 1.0 / (MAX_EXP - 2.0); - Delt_vth = pParam->BSIM4dvt0 * Theta0 * V0; - T0 = pParam->BSIM4dvt1w * model->BSIM4weffeot * model->BSIM4leffeot / ltw; - if (T0 < EXP_THRESHOLD) - { T1 = exp(T0); - T2 = T1 - 1.0; - T3 = T2 * T2; - T4 = T3 + 2.0 * T1 * MIN_EXP; - T5 = T1 / T4; - } - else - T5 = 1.0 / (MAX_EXP - 2.0); /* 3.0 * MIN_EXP omitted */ - T2 = pParam->BSIM4dvt0w * T5 * V0; - TempRatioeot = model->BSIM4tempeot / model->BSIM4tnom - 1.0; - T0 = sqrt(1.0 + pParam->BSIM4lpe0 / model->BSIM4leffeot); - T1 = pParam->BSIM4k1ox * (T0 - 1.0) * sqrt(phieot) - + (pParam->BSIM4kt1 + pParam->BSIM4kt1l / model->BSIM4leffeot) * TempRatioeot; - Vth_NarrowW = toxe * phieot - / (model->BSIM4weffeot + pParam->BSIM4w0); - Lpe_Vb = sqrt(1.0 + pParam->BSIM4lpeb / model->BSIM4leffeot); - Vth = model->BSIM4type * here->BSIM4vth0 + - (pParam->BSIM4k1ox - pParam->BSIM4k1)*sqrt(phieot)*Lpe_Vb - - Delt_vth - T2 + pParam->BSIM4k3 * Vth_NarrowW + T1; + /* Calculate Vth @ Vds=Vbs=0 */ - /* Calculate n */ - tmp1 = epssub / pParam->BSIM4Xdep0; - tmp2 = pParam->BSIM4nfactor * tmp1; - tmp3 = (tmp2 + pParam->BSIM4cdsc * Theta0 + pParam->BSIM4cit) / model->BSIM4coxe; - if (tmp3 >= -0.5) - n = 1.0 + tmp3; - else - { - T0 = 1.0 / (3.0 + 8.0 * tmp3); - n = (1.0 + 3.0 * tmp3) * T0; - } + V0 = vbieot - phieot; + lt1 = model->BSIM4factor1* pParam->BSIM4sqrtXdep0; + ltw = lt1; + T0 = pParam->BSIM4dvt1 * model->BSIM4leffeot / lt1; + if (T0 < EXP_THRESHOLD) + { + T1 = exp(T0); + T2 = T1 - 1.0; + T3 = T2 * T2; + T4 = T3 + 2.0 * T1 * MIN_EXP; + Theta0 = T1 / T4; + } + else + Theta0 = 1.0 / (MAX_EXP - 2.0); + Delt_vth = pParam->BSIM4dvt0 * Theta0 * V0; + T0 = pParam->BSIM4dvt1w * model->BSIM4weffeot * model->BSIM4leffeot / ltw; + if (T0 < EXP_THRESHOLD) + { T1 = exp(T0); + T2 = T1 - 1.0; + T3 = T2 * T2; + T4 = T3 + 2.0 * T1 * MIN_EXP; + T5 = T1 / T4; + } + else + T5 = 1.0 / (MAX_EXP - 2.0); /* 3.0 * MIN_EXP omitted */ + T2 = pParam->BSIM4dvt0w * T5 * V0; + TempRatioeot = model->BSIM4tempeot / model->BSIM4tnom - 1.0; + T0 = sqrt(1.0 + pParam->BSIM4lpe0 / model->BSIM4leffeot); + T1 = pParam->BSIM4k1ox * (T0 - 1.0) * sqrt(phieot) + + (pParam->BSIM4kt1 + pParam->BSIM4kt1l / model->BSIM4leffeot) * TempRatioeot; + Vth_NarrowW = toxe * phieot + / (model->BSIM4weffeot + pParam->BSIM4w0); + Lpe_Vb = sqrt(1.0 + pParam->BSIM4lpeb / model->BSIM4leffeot); + Vth = model->BSIM4type * here->BSIM4vth0 + + (pParam->BSIM4k1ox - pParam->BSIM4k1)*sqrt(phieot)*Lpe_Vb + - Delt_vth - T2 + pParam->BSIM4k3 * Vth_NarrowW + T1; + + /* Calculate n */ + tmp1 = epssub / pParam->BSIM4Xdep0; + tmp2 = pParam->BSIM4nfactor * tmp1; + tmp3 = (tmp2 + pParam->BSIM4cdsc * Theta0 + pParam->BSIM4cit) / model->BSIM4coxe; + if (tmp3 >= -0.5) + n = 1.0 + tmp3; + else + { + T0 = 1.0 / (3.0 + 8.0 * tmp3); + n = (1.0 + 3.0 * tmp3) * T0; + } - /* Vth correction for Pocket implant */ - if (pParam->BSIM4dvtp0 > 0.0) - { - T3 = model->BSIM4leffeot + pParam->BSIM4dvtp0 * 2.0; - if (model->BSIM4tempMod < 2) - T4 = Vtmeot * log(model->BSIM4leffeot / T3); - else - T4 = Vtm0eot * log(model->BSIM4leffeot / T3); - Vth -= n * T4; - } - Vgsteff = Vgs_eff-Vth; - /* calculating Toxp */ - T3 = model->BSIM4type * here->BSIM4vth0 + /* Vth correction for Pocket implant */ + if (pParam->BSIM4dvtp0 > 0.0) + { + T3 = model->BSIM4leffeot + pParam->BSIM4dvtp0 * 2.0; + if (model->BSIM4tempMod < 2) + T4 = Vtmeot * log(model->BSIM4leffeot / T3); + else + T4 = Vtm0eot * log(model->BSIM4leffeot / T3); + Vth -= n * T4; + } + Vgsteff = Vgs_eff-Vth; + /* calculating Toxp */ + T3 = model->BSIM4type * here->BSIM4vth0 - here->BSIM4vfb - phieot; T4 = T3 + T3; T5 = 2.5 * T3; @@ -2361,32 +2379,36 @@ int Size_Not_Found, i; vtfbphi2eot = 0.0; - niter = 0; - toxpf = toxe; - do - { - toxpi = toxpf; - tmp2 = 2.0e8 * toxpf; - T0 = (Vgsteff + vtfbphi2eot) / tmp2; - T1 = 1.0 + exp(model->BSIM4bdos * 0.7 * log(T0)); - Tcen = model->BSIM4ados * 1.9e-9 / T1; - toxpf = toxe - epsrox/model->BSIM4epsrsub * Tcen; - niter++; - } while ((niter<=4)&&(ABS(toxpf-toxpi)>1e-12)); - here->BSIM4toxp = toxpf; - here->BSIM4coxp = epsrox * EPS0 / here->BSIM4toxp; - } else { - here->BSIM4toxp = model->BSIM4toxp; - here->BSIM4coxp = model->BSIM4coxp; - } + niter = 0; + toxpf = toxe; + do + { + toxpi = toxpf; + tmp2 = 2.0e8 * toxpf; + T0 = (Vgsteff + vtfbphi2eot) / tmp2; + T1 = 1.0 + exp(model->BSIM4bdos * 0.7 * log(T0)); + Tcen = model->BSIM4ados * 1.9e-9 / T1; + toxpf = toxe - epsrox/model->BSIM4epsrsub * Tcen; + niter++; + } while ((niter<=4)&&(ABS(toxpf-toxpi)>1e-12)); + here->BSIM4toxp = toxpf; + here->BSIM4coxp = epsrox * EPS0 / here->BSIM4toxp; + + + } else { + here->BSIM4toxp = model->BSIM4toxp; + here->BSIM4coxp = model->BSIM4coxp; + } if (BSIM4checkModel(model, here, ckt)) - { - SPfrontEnd->IFerrorf(ERR_FATAL, - "detected during BSIM4.8.2 parameter checking for \n model %s of device instance %s\n", model->BSIM4modName, here->BSIM4name); + { 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); return(E_BADPARM); } } /* End instance */ } return(OK); } + diff --git a/src/spicelib/devices/bsim4/b4trunc.c b/src/spicelib/devices/bsim4/b4trunc.c index b3028adb6..b9533edd8 100644 --- a/src/spicelib/devices/bsim4/b4trunc.c +++ b/src/spicelib/devices/bsim4/b4trunc.c @@ -1,29 +1,25 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* Licensed under Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the license at http://opensource.org/licenses/ECL-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc */ #include "ngspice/ngspice.h" @@ -32,7 +28,6 @@ under the License. #include "ngspice/sperror.h" #include "ngspice/suffix.h" - int BSIM4trunc( GENmodel *inModel, @@ -48,8 +43,8 @@ BSIM4instance *here; for (; model != NULL; model = BSIM4nextModel(model)) { for (here = BSIM4instances(model); here != NULL; - here = BSIM4nextInstance(here)) - { + here = BSIM4nextInstance(here)) + { #ifdef STEPDEBUG debugtemp = *timeStep; #endif /* STEPDEBUG */ @@ -61,12 +56,12 @@ BSIM4instance *here; if (here->BSIM4rbodyMod) { CKTterr(here->BSIM4qbs,ckt,timeStep); CKTterr(here->BSIM4qbd,ckt,timeStep); - } - if (here->BSIM4rgateMod == 3) - CKTterr(here->BSIM4qgmid,ckt,timeStep); + } + if (here->BSIM4rgateMod == 3) + CKTterr(here->BSIM4qgmid,ckt,timeStep); #ifdef STEPDEBUG if(debugtemp != *timeStep) - { printf("device %s reduces step from %g to %g\n", + { printf("device %s reduces step from %g to %g\n", here->BSIM4name,debugtemp,*timeStep); } #endif /* STEPDEBUG */ diff --git a/src/spicelib/devices/bsim4/bsim4def.h b/src/spicelib/devices/bsim4/bsim4def.h index 42bc477c6..59d82ceab 100644 --- a/src/spicelib/devices/bsim4/bsim4def.h +++ b/src/spicelib/devices/bsim4/bsim4def.h @@ -1,29 +1,25 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* Licensed under Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the license at http://opensource.org/licenses/ECL-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc */ #ifndef BSIM4 @@ -95,6 +91,7 @@ typedef struct sBSIM4instance double BSIM4l; double BSIM4w; + double BSIM4m; double BSIM4drainArea; double BSIM4sourceArea; double BSIM4drainSquares; @@ -103,7 +100,8 @@ typedef struct sBSIM4instance double BSIM4sourcePerimeter; double BSIM4sourceConductance; double BSIM4drainConductance; - /* stress effect instance param */ + + /* stress effect instance param */ double BSIM4sa; double BSIM4sb; double BSIM4sd; @@ -119,12 +117,11 @@ typedef struct sBSIM4instance double BSIM4rbpd; double BSIM4delvto; - double BSIM4mulu0; - int BSIM4wnflag; double BSIM4xgw; double BSIM4ngcon; - /* added here to account stress effect instance dependence */ + /* added here to account stress effect instance dependence */ + double BSIM4u0temp; double BSIM4vsattemp; double BSIM4vth0; @@ -142,9 +139,12 @@ typedef struct sBSIM4instance double BSIM4icVDS; double BSIM4icVGS; double BSIM4icVBS; - double BSIM4m; + double BSIM4mult_i; + double BSIM4mult_q; + double BSIM4mult_fn; double BSIM4nf; int BSIM4off; + int BSIM4mode; int BSIM4trnqsMod; int BSIM4acnqsMod; @@ -286,6 +286,9 @@ typedef struct sBSIM4instance unsigned BSIM4lGiven :1; unsigned BSIM4wGiven :1; unsigned BSIM4mGiven :1; + unsigned BSIM4mult_iGiven :1; + unsigned BSIM4mult_qGiven :1; + unsigned BSIM4mult_fnGiven :1; unsigned BSIM4nfGiven :1; unsigned BSIM4minGiven :1; unsigned BSIM4drainAreaGiven :1; @@ -307,8 +310,6 @@ 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; @@ -680,6 +681,7 @@ struct bsim4SizeDependParam double BSIM4a1; double BSIM4a2; double BSIM4keta; + double BSIM4ketac; double BSIM4nsub; double BSIM4ndep; double BSIM4nsd; @@ -703,7 +705,7 @@ struct bsim4SizeDependParam double BSIM4w0; double BSIM4dvtp0; double BSIM4dvtp1; - double BSIM4dvtp2; /* New DIBL/Rout */ + double BSIM4dvtp2; /* New DIBL/Rout */ double BSIM4dvtp3; double BSIM4dvtp4; double BSIM4dvtp5; @@ -730,14 +732,14 @@ struct bsim4SizeDependParam double BSIM4lp; double BSIM4u0; double BSIM4eu; - double BSIM4ucs; + double BSIM4ucs; double BSIM4ute; - double BSIM4ucste; + double BSIM4ucste; double BSIM4voff; double BSIM4tvoff; - double BSIM4tnfactor; /* v4.7 Temp dep of leakage current */ - double BSIM4teta0; /* v4.7 temp dep of leakage current */ - double BSIM4tvoffcv; /* v4.7 temp dep of leakage current */ + double BSIM4tnfactor; /* v4.7 Temp dep of leakage current */ + double BSIM4teta0; /* v4.7 temp dep of leakage current */ + double BSIM4tvoffcv; /* v4.7 temp dep of leakage current */ double BSIM4minv; double BSIM4minvcv; double BSIM4vfb; @@ -872,7 +874,7 @@ struct bsim4SizeDependParam double BSIM4theta0vb0; double BSIM4thetaRout; double BSIM4mstar; - double BSIM4VgsteffVth; + double BSIM4VgsteffVth; double BSIM4mstarcv; double BSIM4voffcbn; double BSIM4voffcbncv; @@ -927,7 +929,6 @@ typedef struct sBSIM4model int BSIM4rgateMod; int BSIM4perMod; int BSIM4geoMod; - int BSIM4rgeoMod; int BSIM4mtrlMod; int BSIM4mtrlCompatMod; /* v4.7 */ int BSIM4gidlMod; /* v4.7 New GIDL/GISL */ @@ -936,12 +937,12 @@ typedef struct sBSIM4model int BSIM4tempMod; int BSIM4binUnit; int BSIM4paramChk; - char *BSIM4version; + char *BSIM4version; double BSIM4eot; double BSIM4vddeot; - double BSIM4tempeot; - double BSIM4leffeot; - double BSIM4weffeot; + double BSIM4tempeot; + double BSIM4leffeot; + double BSIM4weffeot; double BSIM4ados; double BSIM4bdos; double BSIM4toxe; @@ -962,6 +963,7 @@ typedef struct sBSIM4model double BSIM4a1; double BSIM4a2; double BSIM4keta; + double BSIM4ketac; double BSIM4nsub; double BSIM4phig; double BSIM4epsrgate; @@ -990,7 +992,7 @@ typedef struct sBSIM4model double BSIM4w0; double BSIM4dvtp0; double BSIM4dvtp1; - double BSIM4dvtp2; /* New DIBL/Rout */ + double BSIM4dvtp2; /* New DIBL/Rout */ double BSIM4dvtp3; double BSIM4dvtp4; double BSIM4dvtp5; @@ -1006,7 +1008,7 @@ typedef struct sBSIM4model double BSIM4dsub; double BSIM4vth0; double BSIM4eu; - double BSIM4ucs; + double BSIM4ucs; double BSIM4ua; double BSIM4ua1; double BSIM4ub; @@ -1019,12 +1021,12 @@ typedef struct sBSIM4model double BSIM4lp; double BSIM4u0; double BSIM4ute; - double BSIM4ucste; + double BSIM4ucste; double BSIM4voff; double BSIM4tvoff; - double BSIM4tnfactor; /* v4.7 Temp dep of leakage current */ - double BSIM4teta0; /* v4.7 temp dep of leakage current */ - double BSIM4tvoffcv; /* v4.7 temp dep of leakage current */ + double BSIM4tnfactor; /* v4.7 Temp dep of leakage current */ + double BSIM4teta0; /* v4.7 temp dep of leakage current */ + double BSIM4tvoffcv; /* v4.7 temp dep of leakage current */ double BSIM4minv; double BSIM4minvcv; double BSIM4voffl; @@ -1247,6 +1249,7 @@ typedef struct sBSIM4model double BSIM4la1; double BSIM4la2; double BSIM4lketa; + double BSIM4lketac; double BSIM4lnsub; double BSIM4lndep; double BSIM4lnsd; @@ -1267,7 +1270,7 @@ typedef struct sBSIM4model double BSIM4lw0; double BSIM4ldvtp0; double BSIM4ldvtp1; - double BSIM4ldvtp2; /* New DIBL/Rout */ + double BSIM4ldvtp2; /* New DIBL/Rout */ double BSIM4ldvtp3; double BSIM4ldvtp4; double BSIM4ldvtp5; @@ -1299,9 +1302,9 @@ typedef struct sBSIM4model double BSIM4lucste; double BSIM4lvoff; double BSIM4ltvoff; - double BSIM4ltnfactor; /* v4.7 Temp dep of leakage current */ - double BSIM4lteta0; /* v4.7 temp dep of leakage current */ - double BSIM4ltvoffcv; /* v4.7 temp dep of leakage current */ + double BSIM4ltnfactor; /* v4.7 Temp dep of leakage current */ + double BSIM4lteta0; /* v4.7 temp dep of leakage current */ + double BSIM4ltvoffcv; /* v4.7 temp dep of leakage current */ double BSIM4lminv; double BSIM4lminvcv; double BSIM4ldelta; @@ -1407,6 +1410,7 @@ typedef struct sBSIM4model double BSIM4wa1; double BSIM4wa2; double BSIM4wketa; + double BSIM4wketac; double BSIM4wnsub; double BSIM4wndep; double BSIM4wnsd; @@ -1427,7 +1431,7 @@ typedef struct sBSIM4model double BSIM4ww0; double BSIM4wdvtp0; double BSIM4wdvtp1; - double BSIM4wdvtp2; /* New DIBL/Rout */ + double BSIM4wdvtp2; /* New DIBL/Rout */ double BSIM4wdvtp3; double BSIM4wdvtp4; double BSIM4wdvtp5; @@ -1459,9 +1463,9 @@ typedef struct sBSIM4model double BSIM4wucste; double BSIM4wvoff; double BSIM4wtvoff; - double BSIM4wtnfactor; /* v4.7 Temp dep of leakage current */ - double BSIM4wteta0; /* v4.7 temp dep of leakage current */ - double BSIM4wtvoffcv; /* v4.7 temp dep of leakage current */ + double BSIM4wtnfactor; /* v4.7 Temp dep of leakage current */ + double BSIM4wteta0; /* v4.7 temp dep of leakage current */ + double BSIM4wtvoffcv; /* v4.7 temp dep of leakage current */ double BSIM4wminv; double BSIM4wminvcv; double BSIM4wdelta; @@ -1567,6 +1571,7 @@ typedef struct sBSIM4model double BSIM4pa1; double BSIM4pa2; double BSIM4pketa; + double BSIM4pketac; double BSIM4pnsub; double BSIM4pndep; double BSIM4pnsd; @@ -1587,7 +1592,7 @@ typedef struct sBSIM4model double BSIM4pw0; double BSIM4pdvtp0; double BSIM4pdvtp1; - double BSIM4pdvtp2; /* New DIBL/Rout */ + double BSIM4pdvtp2; /* New DIBL/Rout */ double BSIM4pdvtp3; double BSIM4pdvtp4; double BSIM4pdvtp5; @@ -1619,9 +1624,9 @@ typedef struct sBSIM4model double BSIM4pucste; double BSIM4pvoff; double BSIM4ptvoff; - double BSIM4ptnfactor; /* v4.7 Temp dep of leakage current */ - double BSIM4pteta0; /* v4.7 temp dep of leakage current */ - double BSIM4ptvoffcv; /* v4.7 temp dep of leakage current */ + double BSIM4ptnfactor; /* v4.7 Temp dep of leakage current */ + double BSIM4pteta0; /* v4.7 temp dep of leakage current */ + double BSIM4ptvoffcv; /* v4.7 temp dep of leakage current */ double BSIM4pminv; double BSIM4pminvcv; double BSIM4pdelta; @@ -1823,6 +1828,7 @@ typedef struct sBSIM4model /* Pre-calculated constants * move to size-dependent param */ + double BSIM4Eg0; double BSIM4vtm; double BSIM4vtm0; @@ -1872,6 +1878,7 @@ typedef struct sBSIM4model double BSIM4vgbrMax; double BSIM4vbsrMax; double BSIM4vbdrMax; + double BSIM4gidlclamp; double BSIM4idovvdsc; struct bsim4SizeDependParam *pSizeDependParamKnot; @@ -1892,7 +1899,6 @@ typedef struct sBSIM4model unsigned BSIM4rgateModGiven :1; unsigned BSIM4perModGiven :1; unsigned BSIM4geoModGiven :1; - unsigned BSIM4rgeoModGiven :1; unsigned BSIM4paramChkGiven :1; unsigned BSIM4trnqsModGiven :1; unsigned BSIM4acnqsModGiven :1; @@ -1932,6 +1938,7 @@ typedef struct sBSIM4model unsigned BSIM4a1Given :1; unsigned BSIM4a2Given :1; unsigned BSIM4ketaGiven :1; + unsigned BSIM4ketacGiven :1; unsigned BSIM4nsubGiven :1; unsigned BSIM4phigGiven :1; unsigned BSIM4epsrgateGiven :1; @@ -1960,7 +1967,7 @@ typedef struct sBSIM4model unsigned BSIM4w0Given :1; unsigned BSIM4dvtp0Given :1; unsigned BSIM4dvtp1Given :1; - unsigned BSIM4dvtp2Given :1; /* New DIBL/Rout */ + unsigned BSIM4dvtp2Given :1; /* New DIBL/Rout */ unsigned BSIM4dvtp3Given :1; unsigned BSIM4dvtp4Given :1; unsigned BSIM4dvtp5Given :1; @@ -1992,9 +1999,9 @@ typedef struct sBSIM4model unsigned BSIM4ucsteGiven :1; unsigned BSIM4voffGiven :1; unsigned BSIM4tvoffGiven :1; - unsigned BSIM4tnfactorGiven :1; /* v4.7 Temp dep of leakage current */ - unsigned BSIM4teta0Given :1; /* v4.7 temp dep of leakage current */ - unsigned BSIM4tvoffcvGiven :1; /* v4.7 temp dep of leakage current */ + unsigned BSIM4tnfactorGiven :1; /* v4.7 Temp dep of leakage current */ + unsigned BSIM4teta0Given :1; /* v4.7 temp dep of leakage current */ + unsigned BSIM4tvoffcvGiven :1; /* v4.7 temp dep of leakage current */ unsigned BSIM4vofflGiven :1; unsigned BSIM4voffcvlGiven :1; unsigned BSIM4minvGiven :1; @@ -2084,7 +2091,7 @@ typedef struct sBSIM4model unsigned BSIM4jtsswdGiven :1; unsigned BSIM4jtsswgsGiven :1; unsigned BSIM4jtsswgdGiven :1; - unsigned BSIM4jtweffGiven :1; + unsigned BSIM4jtweffGiven :1; unsigned BSIM4njtsGiven :1; unsigned BSIM4njtsswGiven :1; unsigned BSIM4njtsswgGiven :1; @@ -2217,6 +2224,7 @@ typedef struct sBSIM4model unsigned BSIM4la1Given :1; unsigned BSIM4la2Given :1; unsigned BSIM4lketaGiven :1; + unsigned BSIM4lketacGiven :1; unsigned BSIM4lnsubGiven :1; unsigned BSIM4lndepGiven :1; unsigned BSIM4lnsdGiven :1; @@ -2237,7 +2245,7 @@ typedef struct sBSIM4model unsigned BSIM4lw0Given :1; unsigned BSIM4ldvtp0Given :1; unsigned BSIM4ldvtp1Given :1; - unsigned BSIM4ldvtp2Given :1; /* New DIBL/Rout */ + unsigned BSIM4ldvtp2Given :1; /* New DIBL/Rout */ unsigned BSIM4ldvtp3Given :1; unsigned BSIM4ldvtp4Given :1; unsigned BSIM4ldvtp5Given :1; @@ -2264,14 +2272,14 @@ typedef struct sBSIM4model unsigned BSIM4llpGiven :1; unsigned BSIM4lu0Given :1; unsigned BSIM4leuGiven :1; - unsigned BSIM4lucsGiven :1; + unsigned BSIM4lucsGiven :1; unsigned BSIM4luteGiven :1; - unsigned BSIM4lucsteGiven :1; + unsigned BSIM4lucsteGiven :1; unsigned BSIM4lvoffGiven :1; unsigned BSIM4ltvoffGiven :1; - unsigned BSIM4ltnfactorGiven :1; /* v4.7 Temp dep of leakage current */ - unsigned BSIM4lteta0Given :1; /* v4.7 temp dep of leakage current */ - unsigned BSIM4ltvoffcvGiven :1; /* v4.7 temp dep of leakage current */ + unsigned BSIM4ltnfactorGiven :1; /* v4.7 Temp dep of leakage current */ + unsigned BSIM4lteta0Given :1; /* v4.7 temp dep of leakage current */ + unsigned BSIM4ltvoffcvGiven :1; /* v4.7 temp dep of leakage current */ unsigned BSIM4lminvGiven :1; unsigned BSIM4lminvcvGiven :1; unsigned BSIM4lrdswGiven :1; @@ -2377,6 +2385,7 @@ typedef struct sBSIM4model unsigned BSIM4wa1Given :1; unsigned BSIM4wa2Given :1; unsigned BSIM4wketaGiven :1; + unsigned BSIM4wketacGiven :1; unsigned BSIM4wnsubGiven :1; unsigned BSIM4wndepGiven :1; unsigned BSIM4wnsdGiven :1; @@ -2397,7 +2406,7 @@ typedef struct sBSIM4model unsigned BSIM4ww0Given :1; unsigned BSIM4wdvtp0Given :1; unsigned BSIM4wdvtp1Given :1; - unsigned BSIM4wdvtp2Given :1; /* New DIBL/Rout */ + unsigned BSIM4wdvtp2Given :1; /* New DIBL/Rout */ unsigned BSIM4wdvtp3Given :1; unsigned BSIM4wdvtp4Given :1; unsigned BSIM4wdvtp5Given :1; @@ -2424,14 +2433,14 @@ typedef struct sBSIM4model unsigned BSIM4wlpGiven :1; unsigned BSIM4wu0Given :1; unsigned BSIM4weuGiven :1; - unsigned BSIM4wucsGiven :1; + unsigned BSIM4wucsGiven :1; unsigned BSIM4wuteGiven :1; - unsigned BSIM4wucsteGiven :1; + unsigned BSIM4wucsteGiven :1; unsigned BSIM4wvoffGiven :1; unsigned BSIM4wtvoffGiven :1; - unsigned BSIM4wtnfactorGiven :1; /* v4.7 Temp dep of leakage current */ - unsigned BSIM4wteta0Given :1; /* v4.7 temp dep of leakage current */ - unsigned BSIM4wtvoffcvGiven :1; /* v4.7 temp dep of leakage current */ + unsigned BSIM4wtnfactorGiven :1; /* v4.7 Temp dep of leakage current */ + unsigned BSIM4wteta0Given :1; /* v4.7 temp dep of leakage current */ + unsigned BSIM4wtvoffcvGiven :1; /* v4.7 temp dep of leakage current */ unsigned BSIM4wminvGiven :1; unsigned BSIM4wminvcvGiven :1; unsigned BSIM4wrdswGiven :1; @@ -2537,6 +2546,7 @@ typedef struct sBSIM4model unsigned BSIM4pa1Given :1; unsigned BSIM4pa2Given :1; unsigned BSIM4pketaGiven :1; + unsigned BSIM4pketacGiven :1; unsigned BSIM4pnsubGiven :1; unsigned BSIM4pndepGiven :1; unsigned BSIM4pnsdGiven :1; @@ -2557,7 +2567,7 @@ typedef struct sBSIM4model unsigned BSIM4pw0Given :1; unsigned BSIM4pdvtp0Given :1; unsigned BSIM4pdvtp1Given :1; - unsigned BSIM4pdvtp2Given :1; /* New DIBL/Rout */ + unsigned BSIM4pdvtp2Given :1; /* New DIBL/Rout */ unsigned BSIM4pdvtp3Given :1; unsigned BSIM4pdvtp4Given :1; unsigned BSIM4pdvtp5Given :1; @@ -2584,14 +2594,14 @@ typedef struct sBSIM4model unsigned BSIM4plpGiven :1; unsigned BSIM4pu0Given :1; unsigned BSIM4peuGiven :1; - unsigned BSIM4pucsGiven :1; + unsigned BSIM4pucsGiven :1; unsigned BSIM4puteGiven :1; - unsigned BSIM4pucsteGiven :1; + unsigned BSIM4pucsteGiven :1; unsigned BSIM4pvoffGiven :1; unsigned BSIM4ptvoffGiven :1; - unsigned BSIM4ptnfactorGiven :1; /* v4.7 Temp dep of leakage current */ - unsigned BSIM4pteta0Given :1; /* v4.7 temp dep of leakage current */ - unsigned BSIM4ptvoffcvGiven :1; /* v4.7 temp dep of leakage current */ + unsigned BSIM4ptnfactorGiven :1; /* v4.7 Temp dep of leakage current */ + unsigned BSIM4pteta0Given :1; /* v4.7 temp dep of leakage current */ + unsigned BSIM4ptvoffcvGiven :1; /* v4.7 temp dep of leakage current */ unsigned BSIM4pminvGiven :1; unsigned BSIM4pminvcvGiven :1; unsigned BSIM4prdswGiven :1; @@ -2705,7 +2715,7 @@ typedef struct sBSIM4model unsigned BSIM4SbulkJctGateSideGradingCoeffGiven :1; unsigned BSIM4SunitLengthGateSidewallJctCapGiven :1; unsigned BSIM4SjctEmissionCoeffGiven :1; - unsigned BSIM4SjctTempExponentGiven :1; + unsigned BSIM4SjctTempExponentGiven :1; unsigned BSIM4DjctSatCurDensityGiven :1; unsigned BSIM4DjctSidewallSatCurDensityGiven :1; @@ -2807,7 +2817,6 @@ typedef struct sBSIM4model unsigned BSIM4pku0weGiven :1; unsigned BSIM4gidlclampGiven :1; unsigned BSIM4idovvdscGiven :1; - } BSIM4model; @@ -2855,35 +2864,40 @@ 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 /* Global parameters */ -#define BSIM4_MOD_TEMPEOT 65 -#define BSIM4_MOD_LEFFEOT 66 -#define BSIM4_MOD_WEFFEOT 67 -#define BSIM4_MOD_UCSTE 68 -#define BSIM4_MOD_LUCSTE 69 -#define BSIM4_MOD_WUCSTE 70 -#define BSIM4_MOD_PUCSTE 71 -#define BSIM4_MOD_UCS 72 -#define BSIM4_MOD_LUCS 73 -#define BSIM4_MOD_WUCS 74 -#define BSIM4_MOD_PUCS 75 -#define BSIM4_MOD_CVCHARGEMOD 76 -#define BSIM4_MOD_ADOS 77 -#define BSIM4_MOD_BDOS 78 -#define BSIM4_MOD_TEMPMOD 79 -#define BSIM4_MOD_MTRLMOD 80 -#define BSIM4_MOD_IGCMOD 81 -#define BSIM4_MOD_IGBMOD 82 -#define BSIM4_MOD_ACNQSMOD 83 -#define BSIM4_MOD_FNOIMOD 84 -#define BSIM4_MOD_RDSMOD 85 -#define BSIM4_MOD_DIOMOD 86 -#define BSIM4_MOD_PERMOD 87 -#define BSIM4_MOD_GEOMOD 88 -#define BSIM4_MOD_RGEOMOD 89 +#define BSIM4_MOD_TEMPEOT 66 +#define BSIM4_MOD_LEFFEOT 67 +#define BSIM4_MOD_WEFFEOT 68 +#define BSIM4_MOD_UCSTE 69 +#define BSIM4_MOD_LUCSTE 70 +#define BSIM4_MOD_WUCSTE 71 +#define BSIM4_MOD_PUCSTE 72 +#define BSIM4_MOD_UCS 73 +#define BSIM4_MOD_LUCS 74 +#define BSIM4_MOD_WUCS 75 +#define BSIM4_MOD_PUCS 76 +#define BSIM4_MOD_CVCHARGEMOD 77 +#define BSIM4_MOD_ADOS 78 +#define BSIM4_MOD_BDOS 79 +#define BSIM4_MOD_TEMPMOD 80 +#define BSIM4_MOD_MTRLMOD 81 +#define BSIM4_MOD_IGCMOD 82 +#define BSIM4_MOD_IGBMOD 83 +#define BSIM4_MOD_ACNQSMOD 84 +#define BSIM4_MOD_FNOIMOD 85 +#define BSIM4_MOD_RDSMOD 86 +#define BSIM4_MOD_DIOMOD 87 +#define BSIM4_MOD_PERMOD 88 +#define BSIM4_MOD_GEOMOD 89 #define BSIM4_MOD_RGATEMOD 90 #define BSIM4_MOD_RBODYMOD 91 #define BSIM4_MOD_CAPMOD 92 @@ -3224,47 +3238,47 @@ typedef struct sBSIM4model #define BSIM4_MOD_LLP 442 #define BSIM4_MOD_LMINVCV 443 -#define BSIM4_MOD_FGIDL 444 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_KGIDL 445 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_RGIDL 446 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_FGISL 447 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_KGISL 448 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_RGISL 449 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_LFGIDL 450 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_LKGIDL 451 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_LRGIDL 452 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_LFGISL 453 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_LKGISL 454 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_LRGISL 455 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_WFGIDL 456 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_WKGIDL 457 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_WRGIDL 458 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_WFGISL 459 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_WKGISL 460 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_WRGISL 461 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_PFGIDL 462 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_PKGIDL 463 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_PRGIDL 464 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_PFGISL 465 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_PKGISL 466 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_PRGISL 467 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_GIDLMOD 379 /* v4.7 New GIDL/GISL*/ -#define BSIM4_MOD_DVTP2 468 /* v4.7 NEW DIBL/Rout*/ -#define BSIM4_MOD_DVTP3 469 /* v4.7 NEW DIBL/Rout*/ -#define BSIM4_MOD_DVTP4 470 /* v4.7 NEW DIBL/Rout*/ -#define BSIM4_MOD_DVTP5 471 /* v4.7 NEW DIBL/Rout*/ -#define BSIM4_MOD_LDVTP2 472 /* v4.7 NEW DIBL/Rout*/ -#define BSIM4_MOD_LDVTP3 473 /* v4.7 NEW DIBL/Rout*/ -#define BSIM4_MOD_LDVTP4 474 /* v4.7 NEW DIBL/Rout*/ -#define BSIM4_MOD_LDVTP5 475 /* v4.7 NEW DIBL/Rout*/ -#define BSIM4_MOD_WDVTP2 476 /* v4.7 NEW DIBL/Rout*/ -#define BSIM4_MOD_WDVTP3 477 /* v4.7 NEW DIBL/Rout*/ -#define BSIM4_MOD_WDVTP4 478 /* v4.7 NEW DIBL/Rout*/ -#define BSIM4_MOD_WDVTP5 479 /* v4.7 NEW DIBL/Rout*/ -#define BSIM4_MOD_PDVTP2 480 /* v4.7 NEW DIBL/Rout*/ -#define BSIM4_MOD_PDVTP3 298 /* v4.7 NEW DIBL/Rout*/ -#define BSIM4_MOD_PDVTP4 299 /* v4.7 NEW DIBL/Rout*/ -#define BSIM4_MOD_PDVTP5 300 /* v4.7 NEW DIBL/Rout*/ +#define BSIM4_MOD_FGIDL 444 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_KGIDL 445 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_RGIDL 446 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_FGISL 447 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_KGISL 448 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_RGISL 449 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_LFGIDL 450 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_LKGIDL 451 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_LRGIDL 452 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_LFGISL 453 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_LKGISL 454 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_LRGISL 455 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_WFGIDL 456 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_WKGIDL 457 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_WRGIDL 458 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_WFGISL 459 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_WKGISL 460 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_WRGISL 461 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_PFGIDL 462 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_PKGIDL 463 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_PRGIDL 464 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_PFGISL 465 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_PKGISL 466 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_PRGISL 467 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_GIDLMOD 379 /* v4.7 New GIDL/GISL*/ +#define BSIM4_MOD_DVTP2 468 /* v4.7 NEW DIBL/Rout*/ +#define BSIM4_MOD_DVTP3 469 /* v4.7 NEW DIBL/Rout*/ +#define BSIM4_MOD_DVTP4 470 /* v4.7 NEW DIBL/Rout*/ +#define BSIM4_MOD_DVTP5 471 /* v4.7 NEW DIBL/Rout*/ +#define BSIM4_MOD_LDVTP2 472 /* v4.7 NEW DIBL/Rout*/ +#define BSIM4_MOD_LDVTP3 473 /* v4.7 NEW DIBL/Rout*/ +#define BSIM4_MOD_LDVTP4 474 /* v4.7 NEW DIBL/Rout*/ +#define BSIM4_MOD_LDVTP5 475 /* v4.7 NEW DIBL/Rout*/ +#define BSIM4_MOD_WDVTP2 476 /* v4.7 NEW DIBL/Rout*/ +#define BSIM4_MOD_WDVTP3 477 /* v4.7 NEW DIBL/Rout*/ +#define BSIM4_MOD_WDVTP4 478 /* v4.7 NEW DIBL/Rout*/ +#define BSIM4_MOD_WDVTP5 479 /* v4.7 NEW DIBL/Rout*/ +#define BSIM4_MOD_PDVTP2 480 /* v4.7 NEW DIBL/Rout*/ +#define BSIM4_MOD_PDVTP3 298 /* v4.7 NEW DIBL/Rout*/ +#define BSIM4_MOD_PDVTP4 299 /* v4.7 NEW DIBL/Rout*/ +#define BSIM4_MOD_PDVTP5 300 /* v4.7 NEW DIBL/Rout*/ /* Width dependence */ #define BSIM4_MOD_WCDSC 481 @@ -3550,11 +3564,11 @@ typedef struct sBSIM4model #define BSIM4_MOD_LKVTH0 808 #define BSIM4_MOD_WKVTH0 809 #define BSIM4_MOD_PKVTH0 810 -#define BSIM4_MOD_WLOD 811 -#define BSIM4_MOD_STK2 812 -#define BSIM4_MOD_LODK2 813 -#define BSIM4_MOD_STETA0 814 -#define BSIM4_MOD_LODETA0 815 +#define BSIM4_MOD_WLOD 811 +#define BSIM4_MOD_STK2 812 +#define BSIM4_MOD_LODK2 813 +#define BSIM4_MOD_STETA0 814 +#define BSIM4_MOD_LODETA0 815 #define BSIM4_MOD_WEB 816 #define BSIM4_MOD_WEC 817 @@ -3643,29 +3657,29 @@ typedef struct sBSIM4model /* trap-assisted tunneling */ #define BSIM4_MOD_JTSS 900 -#define BSIM4_MOD_JTSD 901 -#define BSIM4_MOD_JTSSWS 902 -#define BSIM4_MOD_JTSSWD 903 -#define BSIM4_MOD_JTSSWGS 904 -#define BSIM4_MOD_JTSSWGD 905 -#define BSIM4_MOD_NJTS 906 -#define BSIM4_MOD_NJTSSW 907 -#define BSIM4_MOD_NJTSSWG 908 -#define BSIM4_MOD_XTSS 909 -#define BSIM4_MOD_XTSD 910 -#define BSIM4_MOD_XTSSWS 911 -#define BSIM4_MOD_XTSSWD 912 -#define BSIM4_MOD_XTSSWGS 913 -#define BSIM4_MOD_XTSSWGD 914 -#define BSIM4_MOD_TNJTS 915 -#define BSIM4_MOD_TNJTSSW 916 -#define BSIM4_MOD_TNJTSSWG 917 +#define BSIM4_MOD_JTSD 901 +#define BSIM4_MOD_JTSSWS 902 +#define BSIM4_MOD_JTSSWD 903 +#define BSIM4_MOD_JTSSWGS 904 +#define BSIM4_MOD_JTSSWGD 905 +#define BSIM4_MOD_NJTS 906 +#define BSIM4_MOD_NJTSSW 907 +#define BSIM4_MOD_NJTSSWG 908 +#define BSIM4_MOD_XTSS 909 +#define BSIM4_MOD_XTSD 910 +#define BSIM4_MOD_XTSSWS 911 +#define BSIM4_MOD_XTSSWD 912 +#define BSIM4_MOD_XTSSWGS 913 +#define BSIM4_MOD_XTSSWGD 914 +#define BSIM4_MOD_TNJTS 915 +#define BSIM4_MOD_TNJTSSW 916 +#define BSIM4_MOD_TNJTSSWG 917 #define BSIM4_MOD_VTSS 918 -#define BSIM4_MOD_VTSD 919 -#define BSIM4_MOD_VTSSWS 920 -#define BSIM4_MOD_VTSSWD 921 -#define BSIM4_MOD_VTSSWGS 922 -#define BSIM4_MOD_VTSSWGD 923 +#define BSIM4_MOD_VTSD 919 +#define BSIM4_MOD_VTSSWS 920 +#define BSIM4_MOD_VTSSWD 921 +#define BSIM4_MOD_VTSSWGS 922 +#define BSIM4_MOD_VTSSWGD 923 #define BSIM4_MOD_PUD 924 #define BSIM4_MOD_PUD1 925 #define BSIM4_MOD_PUP 926 @@ -3722,9 +3736,9 @@ typedef struct sBSIM4model #define BSIM4_DRAINCONDUCT 991 #define BSIM4_CBDB 992 #define BSIM4_CBSB 993 -#define BSIM4_CSUB 994 -#define BSIM4_QINV 995 -#define BSIM4_IGIDL 996 +#define BSIM4_CSUB 994 +#define BSIM4_QINV 995 +#define BSIM4_IGIDL 996 #define BSIM4_CSGB 997 #define BSIM4_CSDB 998 #define BSIM4_CSSB 999 @@ -3733,14 +3747,14 @@ typedef struct sBSIM4model #define BSIM4_CSBB 1002 #define BSIM4_CBBB 1003 #define BSIM4_QS 1004 -#define BSIM4_IGISL 1005 -#define BSIM4_IGS 1006 -#define BSIM4_IGD 1007 -#define BSIM4_IGB 1008 -#define BSIM4_IGCS 1009 -#define BSIM4_IGCD 1010 -#define BSIM4_QDEF 1011 -#define BSIM4_DELVT0 1012 +#define BSIM4_IGISL 1005 +#define BSIM4_IGS 1006 +#define BSIM4_IGD 1007 +#define BSIM4_IGB 1008 +#define BSIM4_IGCS 1009 +#define BSIM4_IGCD 1010 +#define BSIM4_QDEF 1011 +#define BSIM4_DELVT0 1012 #define BSIM4_GCRG 1013 #define BSIM4_GTAU 1014 @@ -3753,13 +3767,13 @@ typedef struct sBSIM4model #define BSIM4_MOD_LKVTH0WE 1061 #define BSIM4_MOD_LK2WE 1062 -#define BSIM4_MOD_LKU0WE 1063 +#define BSIM4_MOD_LKU0WE 1063 #define BSIM4_MOD_WKVTH0WE 1064 #define BSIM4_MOD_WK2WE 1065 -#define BSIM4_MOD_WKU0WE 1066 +#define BSIM4_MOD_WKU0WE 1066 #define BSIM4_MOD_PKVTH0WE 1067 #define BSIM4_MOD_PK2WE 1068 -#define BSIM4_MOD_PKU0WE 1069 +#define BSIM4_MOD_PKU0WE 1069 #define BSIM4_MOD_RBPS0 1101 #define BSIM4_MOD_RBPSL 1102 @@ -3843,26 +3857,35 @@ typedef struct sBSIM4model /* v4.7 temp dep of leakage current */ -#define BSIM4_MOD_TNFACTOR 1256 -#define BSIM4_MOD_TETA0 1257 -#define BSIM4_MOD_TVOFFCV 1258 -#define BSIM4_MOD_LTNFACTOR 1260 -#define BSIM4_MOD_LTETA0 1261 -#define BSIM4_MOD_LTVOFFCV 1262 -#define BSIM4_MOD_WTNFACTOR 1264 -#define BSIM4_MOD_WTETA0 1265 -#define BSIM4_MOD_WTVOFFCV 1266 -#define BSIM4_MOD_PTNFACTOR 1268 -#define BSIM4_MOD_PTETA0 1269 -#define BSIM4_MOD_PTVOFFCV 1270 +#define BSIM4_MOD_TNFACTOR 1256 +#define BSIM4_MOD_TETA0 1257 +#define BSIM4_MOD_TVOFFCV 1258 +#define BSIM4_MOD_LTNFACTOR 1260 +#define BSIM4_MOD_LTETA0 1261 +#define BSIM4_MOD_LTVOFFCV 1262 +#define BSIM4_MOD_WTNFACTOR 1264 +#define BSIM4_MOD_WTETA0 1265 +#define BSIM4_MOD_WTVOFFCV 1266 +#define BSIM4_MOD_PTNFACTOR 1268 +#define BSIM4_MOD_PTETA0 1269 +#define BSIM4_MOD_PTVOFFCV 1270 /* tnoiMod=2 (v4.7) */ -#define BSIM4_MOD_TNOIC 1272 -#define BSIM4_MOD_RNOIC 1273 +#define BSIM4_MOD_TNOIC 1272 +#define BSIM4_MOD_RNOIC 1273 /* smoothing for gidl clamp (C.K.Dabhi) */ -#define BSIM4_MOD_GIDLCLAMP 1274 +#define BSIM4_MOD_GIDLCLAMP 1274 /* Tuning for noise parameter BSIM4IdovVds (C.K.Dabhi) - request cadence */ -#define BSIM4_MOD_IDOVVDSC 1275 +#define BSIM4_MOD_IDOVVDSC 1275 + +/* for dynamic evaluate */ +#define BSIM4_MOD_KETAC 1276 +#define BSIM4_MOD_LKETAC 1277 +#define BSIM4_MOD_WKETAC 1278 +#define BSIM4_MOD_PKETAC 1279 +#define BSIM4_MULT_I 1280 +#define BSIM4_MULT_Q 1281 +#define BSIM4_MULT_FN 1282 #define BSIM4_MOD_VGS_MAX 1301 #define BSIM4_MOD_VGD_MAX 1302 @@ -3876,14 +3899,6 @@ typedef struct sBSIM4model #define BSIM4_MOD_VBSR_MAX 1310 #define BSIM4_MOD_VBDR_MAX 1311 -#define BSIM4_VGSTEFF 1400 -#define BSIM4_VDSEFF 1401 -#define BSIM4_CGSO 1402 -#define BSIM4_CGDO 1403 -#define BSIM4_CGBO 1404 -#define BSIM4_WEFF 1405 -#define BSIM4_LEFF 1406 - #include "bsim4ext.h" extern void BSIM4evaluate(double,double,double,BSIM4instance*,BSIM4model*, @@ -3898,3 +3913,4 @@ extern int BSIM4RdsEndIso(double, double, double, double, double, double, int, i extern int BSIM4RdsEndSha(double, double, double, double, double, double, int, int, double *); #endif /*BSIM4*/ + diff --git a/src/spicelib/devices/bsim4/bsim4ext.h b/src/spicelib/devices/bsim4/bsim4ext.h index dad9274d3..468034b64 100644 --- a/src/spicelib/devices/bsim4/bsim4ext.h +++ b/src/spicelib/devices/bsim4/bsim4ext.h @@ -1,29 +1,25 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* Licensed under Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the license at http://opensource.org/licenses/ECL-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc */ extern int BSIM4acLoad(GENmodel *,CKTcircuit*); @@ -38,7 +34,7 @@ extern void BSIM4mosCap(CKTcircuit*, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double*, double*, double*, double*, double*, double*, double*, double*, - double*, double*, double*, double*, double*, double*, double*, + double*, double*, double*, double*, double*, double*, double*, double*); extern int BSIM4param(int,IFvalue*,GENinstance*,IFvalue*); extern int BSIM4pzLoad(GENmodel*,CKTcircuit*,SPcomplex*); diff --git a/src/spicelib/devices/bsim4/bsim4itf.h b/src/spicelib/devices/bsim4/bsim4itf.h index 52013b107..429aef8e1 100644 --- a/src/spicelib/devices/bsim4/bsim4itf.h +++ b/src/spicelib/devices/bsim4/bsim4itf.h @@ -1,29 +1,25 @@ /* ****************************************************************************** - * BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 * + * BSIM4 4.8.3 released on 05/19/2025 * * BSIM4 Model Equations * ****************************************************************************** ****************************************************************************** - * Copyright (c) 2020 University of California * + * Copyright (c) 2025 University of California * * * - * Project Director: Prof. Chenming Hu. * - * Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) * - * Prof. Yogesh Chauhan (IIT Kanpur) * - * Dr. Pragya Kushwaha (Postdoc, UC Berkeley) * - * Dr. Avirup Dasgupta (Postdoc, UC Berkeley) * - * Ming-Yen Kao (Ph.D. student, UC Berkeley) * - * Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang * - * Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, * - * Sayeef Salahuddin, Chenming Hu * + * Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu * + * Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ * ******************************************************************************/ /* Licensed under Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the license at http://opensource.org/licenses/ECL-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this +standard can be found at: http://www.si2.org/cmc */ #ifndef DEV_BSIM4