diff --git a/src/frontend/Makefile.am b/src/frontend/Makefile.am index 9c765ab27..14ae122ef 100644 --- a/src/frontend/Makefile.am +++ b/src/frontend/Makefile.am @@ -130,6 +130,8 @@ libfte_la_SOURCES = \ inp.h \ inpcom.c \ inpcom.h \ + inpcompat.c \ + inpcompat.h \ inpc_probe.c \ interp.c \ interp.h \ diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 750a3d5f2..e2344177a 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -46,6 +46,8 @@ Author: 1985 Wayne A. Christopher #include "subckt.h" #include "variable.h" +#include "inpcompat.h" + #ifdef XSPICE /* gtri - add - 12/12/90 - wbk - include new stuff */ #include "ngspice/enh.h" @@ -53,11 +55,6 @@ Author: 1985 Wayne A. Christopher /* gtri - end - 12/12/90 */ #endif -#define INTEGRATE_UDEVICES -#ifdef INTEGRATE_UDEVICES -#include "ngspice/udevices.h" -#endif - /* SJB - Uncomment this line for debug tracing */ /*#define TRACE*/ @@ -139,7 +136,7 @@ static void inp_reorder_params( static int inp_split_multi_param_lines(struct card *deck, int line_number); static void inp_sort_params(struct card *param_cards, struct card *card_bf_start, struct card *s_c, struct card *e_c); -static char *inp_remove_ws(char *s); +char *inp_remove_ws(char *s); static void inp_compat(struct card *deck); static void inp_bsource_compat(struct card *deck); static bool inp_temper_compat(struct card *card); @@ -180,12 +177,6 @@ static struct modellist *inp_find_model( struct nscope *scope, const char *name); void tprint(struct card *deck); -static void print_compat_mode(void); -static void set_compat_mode(void); -static struct card *pspice_compat(struct card *newcard); -static void pspice_compat_a(struct card *oldcard); -static struct card *ltspice_compat(struct card *oldcard); -static void ltspice_compat_a(struct card *oldcard); static void inp_repair_dc_ps(struct card* oldcard); static void inp_get_w_l_x(struct card* oldcard); @@ -772,98 +763,6 @@ char *find_back_assignment(const char *p, const char *start) } -/* Set a compatibility flag. -Currently available are flags for: -- LTSPICE, HSPICE, Spice3, PSPICE, KiCad, Spectre, XSPICE -*/ -struct compat newcompat; -static void set_compat_mode(void) -{ - char behaviour[80]; - newcompat.hs = FALSE; - newcompat.ps = FALSE; - newcompat.xs = FALSE; - newcompat.lt = FALSE; - newcompat.ki = FALSE; - newcompat.a = FALSE; - newcompat.spe = FALSE; - newcompat.isset = FALSE; - newcompat.s3 = FALSE; - newcompat.mc = FALSE; - if (cp_getvar("ngbehavior", CP_STRING, behaviour, sizeof(behaviour))) { - if (strstr(behaviour, "hs")) - newcompat.isset = newcompat.hs = TRUE; /*HSPICE*/ - if (strstr(behaviour, "ps")) - newcompat.isset = newcompat.ps = TRUE; /*PSPICE*/ - if (strstr(behaviour, "xs")) - newcompat.isset = newcompat.xs = TRUE; /*XSPICE*/ - if (strstr(behaviour, "lt")) - newcompat.isset = newcompat.lt = TRUE; /*LTSPICE*/ - if (strstr(behaviour, "ki")) - newcompat.isset = newcompat.ki = TRUE; /*KiCad*/ - if (strstr(behaviour, "a")) - newcompat.isset = newcompat.a = TRUE; /*complete netlist, used in conjuntion with other mode*/ - if (strstr(behaviour, "ll")) - newcompat.isset = newcompat.ll = TRUE; /*all (currently not used)*/ - if (strstr(behaviour, "s3")) - newcompat.isset = newcompat.s3 = TRUE; /*spice3 only*/ - if (strstr(behaviour, "eg")) - newcompat.isset = newcompat.eg = TRUE; /*EAGLE*/ - if (strstr(behaviour, "spe")) { - newcompat.isset = newcompat.spe = TRUE; /*Spectre*/ - newcompat.ps = newcompat.lt = newcompat.ki = newcompat.eg = FALSE; - } - if (strstr(behaviour, "mc")) { - newcompat.isset = FALSE; - newcompat.mc = TRUE; /*make check*/ - } - } - if (newcompat.hs && newcompat.ps) { - fprintf(stderr, "Warning: hs and ps compatibility are mutually exclusive, switch to ps!\n"); - newcompat.hs = FALSE; - } - /* reset everything for 'make check' */ - if (newcompat.mc) - newcompat.eg = newcompat.hs = newcompat.spe = newcompat.ps = newcompat.xs = - newcompat.ll = newcompat.lt = newcompat.ki = newcompat.a = FALSE; -} - -/* Print the compatibility flags */ -static void print_compat_mode(void) { - if (newcompat.mc) /* make check */ - return; - if (newcompat.isset) { - fprintf(stdout, "\n"); - fprintf(stdout, "Note: Compatibility modes selected:"); - if (newcompat.hs) - fprintf(stdout, " hs"); - if (newcompat.ps) - fprintf(stdout, " ps"); - if (newcompat.xs) - fprintf(stdout, " xs"); - if (newcompat.lt) - fprintf(stdout, " lt"); - if (newcompat.ki) - fprintf(stdout, " ki"); - if (newcompat.ll) - fprintf(stdout, " ll"); - if (newcompat.s3) - fprintf(stdout, " s3"); - if (newcompat.eg) - fprintf(stdout, " eg"); - if (newcompat.spe) - fprintf(stdout, " spe"); - if (newcompat.a) - fprintf(stdout, " a"); - fprintf(stdout, "\n\n"); - } - else { - fprintf(stdout, "\n"); - fprintf(stdout, "Note: No compatibility mode selected!\n\n"); - } -} - - /* We check x lines for nf=, w= and l= and fill in their values. To be used when expanding subcircuits with binned model cards. @@ -3182,7 +3081,7 @@ static char *inp_fix_subckt(struct names *subckt_w_params, char *s) * thats odd and very naive business */ -static char *inp_remove_ws(char *s) +char *inp_remove_ws(char *s) { char *x = s; char *d = s; @@ -8082,1727 +7981,6 @@ static void inp_meas_current(struct card *deck) } } -/* replace the E and G source TABLE function by a B source pwl - * (used by ST OpAmps and comparators of Infineon models). - * E_RO_3 VB_3 VB_4 VALUE={ TABLE( V(VCCP,VCCN), 2 , 35 , 3.3 , 15 , 5 , 10 - * )*I(VreadIo)} - * will become - * BE_RO_3_1 TABLE_NEW_1 0 v = pwl( V(VCCP,VCCN), 2 , 35 , 3.3 , 15 , 5 , 10) - * E_RO_3 VB_3 VB_4 VALUE={ V(TABLE_NEW_1)*I(VreadIo)} - */ -static void replace_table(struct card *startcard) -{ - struct card *card; - static int numb = 0; - for (card = startcard; card; card = card->nextcard) { - char *cut_line = card->line; - if (*cut_line == 'e' || *cut_line == 'g') { - char *valp = search_plain_identifier(cut_line, "value"); - char *valp2 = search_plain_identifier(cut_line, "cur"); - if (valp || (valp2 && *cut_line == 'g')) { - char *ftablebeg = strstr(cut_line, "table("); - while (ftablebeg) { - /* get the beginning of the line */ - char *begline = copy_substring(cut_line, ftablebeg); - /* get the table function */ - char *tabfun = gettok_char(&ftablebeg, ')', TRUE, TRUE); - /* the new e, g line */ - char *neweline = tprintf("%s v(table_new_%d)%s", - begline, numb, ftablebeg); - char *newbline = - tprintf("btable_new_%d table_new_%d 0 v=pwl%s", - numb, numb, tabfun + 5); - numb++; - tfree(tabfun); - tfree(begline); - tfree(card->line); - card->line = cut_line = neweline; - insert_new_line(card, newbline, 0, card->linenum_orig); - /* read next TABLE function in cut_line */ - ftablebeg = strstr(cut_line, "table("); - } - continue; - } - } - } -} - -/* find the model requested by ako:model and do the replacement */ -static struct card *find_model(struct card *startcard, - struct card *changecard, char *searchname, char *newmname, - char *newmtype, char *endstr) -{ - struct card *nomod, *returncard = changecard; - char *origmname, *origmtype; - char *beginline = startcard->line; - if (ciprefix(".subckt", beginline)) - startcard = startcard->nextcard; - - int nesting2 = 0; - for (nomod = startcard; nomod; nomod = nomod->nextcard) { - char *origmodline = nomod->line; - if (ciprefix(".subckt", origmodline)) - nesting2++; - if (ciprefix(".ends", origmodline)) - nesting2--; - /* skip any subcircuit */ - if (nesting2 > 0) - continue; - if (nesting2 == -1) { - returncard = changecard; - break; - } - if (ciprefix(".model", origmodline)) { - origmodline = nexttok(origmodline); - origmname = gettok(&origmodline); - origmtype = gettok_noparens(&origmodline); - if (cieq(origmname, searchname)) { - if (!eq(origmtype, newmtype)) { - fprintf(stderr, - "Error: Original (%s) and new (%s) type for AKO " - "model disagree\n", - origmtype, newmtype); - controlled_exit(1); - } - /* we have got it */ - char *newmodcard = tprintf(".model %s %s %s%s", - newmname, newmtype, origmodline, endstr); - char *tmpstr = strstr(newmodcard, ")("); - if (tmpstr) { - tmpstr[0] = ' '; - tmpstr[1] = ' '; - } - tfree(changecard->line); - changecard->line = newmodcard; - tfree(origmname); - tfree(origmtype); - returncard = NULL; - break; - } - tfree(origmname); - tfree(origmtype); - } - else - returncard = changecard; - } - return returncard; -} - -/* Process any .distribution cards for PSPICE's Monte-Carlo feature. - * A .distribution card defines a probability distribution by a PWL - * density function. This could be rewritten as a function that - * returns a random value following that distribution. - * For now, just comment it away. - */ -static void do_distribution(struct card *oldcard) { - while (oldcard) { - char *line = oldcard->line; - - if (line && ciprefix(".distribution", line)) - *line = '*'; - oldcard = oldcard->nextcard; - } -} - -/* Do the .model replacement required by ako (a kind of) - * PSPICE does not support nested .subckt definitions, so - * a simple structure is needed: search for ako:modelname, - * then for modelname in the subcircuit or in the top level. - * .model qorig npn (BF=48 IS=2e-7) - * .model qbip1 ako:qorig NPN (BF=60 IKF=45m) - * after the replacement we have - * .model qbip1 NPN (BF=48 IS=2e-7 BF=60 IKF=45m) - * and we benefit from the fact that if parameters have - * doubled, the last entry of a parameter (e.g. BF=60) - * overwrites the previous one (BF=48). - */ -static struct card *ako_model(struct card *startcard) -{ - char *newmname, *newmtype; - struct card *card, *returncard = NULL, *subcktcard = NULL; - for (card = startcard; card; card = card->nextcard) { - char *akostr, *searchname; - char *cut_line = card->line; - - if (ciprefix(".subckt", cut_line)) - subcktcard = card; - else if (ciprefix(".ends", cut_line)) - subcktcard = NULL; - if (ciprefix(".model", cut_line)) { - if ((akostr = strstr(cut_line, "ako:")) != NULL && - isspace_c(akostr[-1])) { - akostr += 4; - searchname = gettok(&akostr); - cut_line = nexttok(cut_line); - newmname = gettok(&cut_line); - newmtype = gettok_noparens(&akostr); - - /* Find the model and do the replacement. */ - - if (subcktcard) - returncard = find_model(subcktcard, card, searchname, - newmname, newmtype, akostr); - if (returncard || !subcktcard) - returncard = find_model(startcard, card, searchname, - newmname, newmtype, akostr); - tfree(searchname); - tfree(newmname); - tfree(newmtype); - - /* Replacement not possible, bail out. */ - - if (returncard) - break; - } - } - } - return returncard; -} - -struct vsmodels { - char *modelname; - char *subcktline; - struct vsmodels *nextmodel; -}; - -/* insert a new model, just behind the given model */ -static struct vsmodels *insert_new_model( - struct vsmodels *vsmodel, char *name, char *subcktline) -{ - struct vsmodels *x = TMALLOC(struct vsmodels, 1); - - x->nextmodel = vsmodel ? vsmodel->nextmodel : NULL; - x->modelname = copy(name); - x->subcktline = copy(subcktline); - if (vsmodel) - vsmodel->nextmodel = x; - else - vsmodel = x; - - return vsmodel; -} - -/* find the model */ -static bool find_a_model( - struct vsmodels *vsmodel, char *name, char *subcktline) -{ - struct vsmodels *x; - for (x = vsmodel; vsmodel; vsmodel = vsmodel->nextmodel) - if (eq(vsmodel->modelname, name) && - eq(vsmodel->subcktline, subcktline)) - return TRUE; - return FALSE; -} - -/* delete the vsmodels list */ -static bool del_models(struct vsmodels *vsmodel) -{ - struct vsmodels *x; - - if (!vsmodel) - return FALSE; - - while (vsmodel) { - x = vsmodel->nextmodel; - tfree(vsmodel->modelname); - tfree(vsmodel->subcktline); - tfree(vsmodel); - vsmodel = x; - } - - return TRUE; -} - -/* Check for double '{', replace the inner '{', '}' by '(', ')' - in .subckt or .model (which both may stem from external sources) */ -static void rem_double_braces(struct card* newcard) -{ - struct card* card; - int slevel = 0; - - for (card = newcard; card; card = card->nextcard) { - char* cut_line = card->line; - if (ciprefix(".subckt", cut_line)) - slevel++; - else if (ciprefix(".ends", cut_line)) - slevel--; - if (ciprefix(".model", cut_line) || slevel > 0) { - cut_line = strchr(cut_line, '{'); - if (cut_line) { - int level = 1; - cut_line++; - while (*cut_line != '\0') { - if (*cut_line == '{') { - level++; - if (level > 1) - *cut_line = '('; - } - else if (*cut_line == '}') { - if (level > 1) - *cut_line = ')'; - level--; - } - cut_line++; - } - } - } - } -} - -#ifdef INTEGRATE_UDEVICES -static void list_the_cards(struct card *startcard, char *prefix) -{ - struct card *card; - if (!startcard) { return; } - for (card = startcard; card; card = card->nextcard) { - char* cut_line = card->line; - printf("%s %s\n", prefix, cut_line); - } -} - -static struct card *the_last_card(struct card *startcard) -{ - struct card *card, *lastcard = NULL; - if (!startcard) { return NULL; } - for (card = startcard; card; card = card->nextcard) { - lastcard = card; - } - return lastcard; -} - static void remove_old_cards(struct card *first, struct card *stop) -{ - struct card *x, *y, *next = NULL, *nexta = NULL; - if (!first || !stop || (first == stop)) { return; } - for (x = first; (x && (x != stop)); x = next) { - if (x->line) { tfree(x->line); } - if (x->error) { tfree(x->error); } - for (y = x->actualLine; y; y = nexta) { - if (y->line) { tfree(y->line); } - if (y->error) { tfree(y->error); } - nexta = y->nextcard; - tfree(y); - } - next = x->nextcard; - tfree(x); - } - -} - -static struct card *u_instances(struct card *startcard) -{ - struct card *card, *returncard = NULL, *subcktcard = NULL; - struct card *newcard = NULL, *last_newcard = NULL; - int models_ok = 0, models_not_ok = 0; - int udev_ok = 0, udev_not_ok = 0; - BOOL create_called = FALSE, repeat_pass = FALSE; - BOOL skip_next = FALSE; - - card = startcard; - while (card) { - char *cut_line = card->line; - - skip_next = FALSE; - if (ciprefix(".subckt", cut_line)) { - models_ok = models_not_ok = 0; - udev_ok = udev_not_ok = 0; - subcktcard = card; - if (!repeat_pass) { - if (create_called) { - cleanup_udevice(); - } - initialize_udevice(subcktcard->line); - create_called = TRUE; - } - } else if (ciprefix(".ends", cut_line)) { - if (repeat_pass) { - newcard = replacement_udevice_cards(); - if (newcard) { - char *tmp = NULL, *pos, *posp, *new_str = NULL, *cl; - /* Pspice definition of .subckt card: - .SUBCKT [node]* - + [OPTIONAL: < = >*] - + [PARAMS: < = >* ] - + [TEXT: < = >* ] - ... - .ENDS - */ - cl = subcktcard->line; - tmp = TMALLOC(char, strlen(cl) + 1); - (void) memcpy(tmp, cl, strlen(cl) + 1); - pos = strstr(tmp, "optional:"); - posp = strstr(tmp, "params:"); - /* If there is an optional: and a param: then posp > pos */ - if (pos) { - /* Remove the optional: section if present */ - *pos = '\0'; - if (posp) { - strcat(tmp, posp); - } - } - new_str = copy(tmp); - tfree(tmp); - remove_old_cards(subcktcard->nextcard, card); - subcktcard->nextcard = newcard; - tfree(subcktcard->line); - subcktcard->line = new_str; - if (ft_ngdebug) { - printf("%s\n", new_str); - list_the_cards(newcard, "Replacement:"); - } - last_newcard = the_last_card(newcard); - if (last_newcard) { - last_newcard->nextcard = card; // the .ends card - } - } else { - models_ok = models_not_ok = 0; - udev_ok = udev_not_ok = 0; - } - } - if (models_not_ok > 0 || udev_not_ok > 0) { - repeat_pass = FALSE; - cleanup_udevice(); - create_called = FALSE; - } else if (udev_ok > 0) { - repeat_pass = TRUE; - card = subcktcard; - skip_next = TRUE; - } else { - repeat_pass = FALSE; - cleanup_udevice(); - create_called = FALSE; - } - subcktcard = NULL; - } else if (ciprefix(".model", cut_line)) { - if (subcktcard && !repeat_pass) { - if (!u_process_model_line(cut_line)) { - models_not_ok++; - } else { - models_ok++; - } - } - } else if (ciprefix("u", cut_line)) { - if (subcktcard) { - if (repeat_pass) { - if (!u_process_instance(cut_line)) { - repeat_pass = FALSE; - cleanup_udevice(); - create_called = FALSE; - subcktcard = NULL; - models_ok = models_not_ok = 0; - udev_ok = udev_not_ok = 0; - skip_next = FALSE; - } - } else { - if (u_check_instance(cut_line)) { - udev_ok++; - } else { - udev_not_ok++; - } - } - } - } else { - if (!ciprefix("*", cut_line)) { - udev_not_ok++; - } - } - - if (!skip_next) { - card = card->nextcard; - } - } - if (create_called) { - cleanup_udevice(); - } - return returncard; -} -#endif - -/**** PSPICE to ngspice ************** -* .model replacement in ako (a kind of) model descriptions -* replace the E source TABLE function by a B source pwl -* add predefined params TEMP, VT, GMIN to beginning of deck -* add predefined params TEMP, VT, GMIN to beginning of each .subckt call -* add .functions limit, pwr, pwrs, stp, if, int -* replace vswitch part S - S1 D S DG GND SWN - .MODEL SWN VSWITCH(VON = { 0.55 } VOFF = { 0.49 } - RON = { 1 / (2 * M*(W / LE)*(KPN / 2) * 10) } ROFF = { 1G }) -* by - as1 %vd(DG GND) % gd(D S) aswn - .model aswn aswitch(cntl_off={0.49} cntl_on={0.55} r_off={1G} - + r_on={ 1 / (2 * M*(W / LE)*(KPN / 2) * 10) } log = TRUE) -* replace vswitch part S_ST - S1 D S DG GND S_ST - .MODEL S_ST VSWITCH(VT = { 1.5 } VH = { 0.3 } - RON = { 1 / (2 * M*(W / LE)*(KPN / 2) * 10) } ROFF = { 1G }) -* by the classical voltage controlled ngspice switch - S1 D S DG GND SWN - .MODEL S_ST SW(VT = { 1.5 } VH = { 0.3 } - RON = { 1 / (2 * M*(W / LE)*(KPN / 2) * 10) } ROFF = { 1G }) - switch parameter td is not yet supported -* replace & by && -* replace | by || -* in R instance, replace TC = xx1, xx2 by TC1=xx1 TC2=xx2 -* replace T_ABS by temp and T_REL_GLOBAL by dtemp in .model cards -* get the area factor for diodes and bipolar devices -* in subcircuit .subckt and X lines with 'params:' statement - replace comma separator by space. Do nothing if comma is inside of {}. -* in .model, if double curly braces {{}}, replace the inner by {()} */ -static struct card *pspice_compat(struct card *oldcard) -{ - struct card *card, *newcard, *nextcard; - struct vsmodels *modelsfound = NULL; - int skip_control = 0; - - /* .model replacement in ako (a kind of) model descriptions - * in first .subckt and top level only */ - struct card *errcard; - if ((errcard = ako_model(oldcard)) != NULL) { - fprintf(stderr, "Error: no model found for %s\n", errcard->line); - controlled_exit(1); - } - - /* Process .distribution cards. */ - do_distribution(oldcard); - - /* replace TABLE function in E source */ - replace_table(oldcard); - - /* remove double braces */ - rem_double_braces(oldcard); - - /* add predefined params TEMP, VT, GMIN to beginning of deck */ - char *new_str = copy(".param temp = 'temper'"); - newcard = insert_new_line(NULL, new_str, 1, 0); - new_str = copy(".param vt = '(temper + 273.15) * 8.6173303e-5'"); - nextcard = insert_new_line(newcard, new_str, 2, 0); - new_str = copy(".param gmin = 1e-12"); - nextcard = insert_new_line(nextcard, new_str, 3, 0); - /* add funcs limit, pwr, pwrs, stp, if, int */ - /* LIMIT( Output Expression, Limit1, Limit2) - Output will stay between the two limits given. */ - new_str = copy(".func limit(x, a, b) { ternary_fcn(a > b, max(min(x, a), b), max(min(x, b), a)) }"); - nextcard = insert_new_line(nextcard, new_str, 4, 0); - new_str = copy(".func pwr(x, a) { pow(x, a) }"); - nextcard = insert_new_line(nextcard, new_str, 5, 0); - new_str = copy(".func pwrs(x, a) { sgn(x) * pow(x, a) }"); - nextcard = insert_new_line(nextcard, new_str, 6, 0); - new_str = copy(".func stp(x) { u(x) }"); - nextcard = insert_new_line(nextcard, new_str, 7, 0); - new_str = copy(".func if(a, b, c) {ternary_fcn( a , b , c )}"); - nextcard = insert_new_line(nextcard, new_str, 8, 0); - new_str = copy(".func int(x) { sign(x)*floor(abs(x)) }"); - nextcard = insert_new_line(nextcard, new_str, 9, 0); - nextcard->nextcard = oldcard; - -#ifdef INTEGRATE_UDEVICES - { - struct card *ucard; -#ifdef TRACE - list_the_cards(newcard, "Before udevices"); -#endif - ucard = u_instances(newcard); -#ifdef TRACE - list_the_cards(newcard, "After udevices"); -#endif - } -#endif - - - /* add predefined parameters TEMP, VT after each subckt call */ - /* FIXME: This should not be necessary if we had a better sense of - hierarchy during the evaluation of TEMPER */ - for (card = newcard; card; card = card->nextcard) { - char *cut_line = card->line; - if (ciprefix(".subckt", cut_line)) { - new_str = copy(".param temp = 'temper'"); - nextcard = insert_new_line(card, new_str, 0, 0); - new_str = copy(".param vt = '(temper + 273.15) * 8.6173303e-5'"); - nextcard = insert_new_line(nextcard, new_str, 1, 0); - /* params: replace comma separator by space. - Do nothing if you are inside of { }. */ - char* parastr = strstr(cut_line, "params:"); - int brace = 0; - if (parastr) { - parastr += 8; - while (*parastr) { - if (*parastr == '{') - brace++; - else if (*parastr == '}') - brace--; - if (brace == 0 && *parastr == ',') - *parastr = ' '; - parastr++; - } - } - } - } - - /* .model xxx NMOS/PMOS level=6 --> level = 8, version=3.2.4 - .model xxx NMOS/PMOS level=7 --> level = 8, version=3.2.4 - .model xxx NMOS/PMOS level=5 --> level = 44 - .model xxx NMOS/PMOS level=8 --> level = 14, version=4.5.0 - .model xxx NPN/PNP level=2 --> level = 6 - .model xxx LPNP level=n --> level = 1 subs=-1 - Remove any Monte - Carlo variation parameters from .model cards.*/ - for (card = newcard; card; card = card->nextcard) { - char* cut_line = card->line; - if (ciprefix(".model", cut_line)) { - char* modname, *modtype, *curr_line; - int i; - char *cut_del = curr_line = cut_line = inp_remove_ws(copy(cut_line)); - cut_line = nexttok(cut_line); /* skip .model */ - modname = gettok(&cut_line); /* save model name */ - if (!modname) { - fprintf(stderr, "Error: No model name given for %s\n", curr_line); - controlled_exit(EXIT_BAD); - } - modtype = gettok_noparens(&cut_line); /* save model type */ - if (!modtype) { - fprintf(stderr, "Error: No model type given for %s\n", curr_line); - controlled_exit(EXIT_BAD); - } - if (cieq(modtype, "NMOS") || cieq(modtype, "PMOS")) { - char* lv = strstr(cut_line, "level="); - if (lv) { - int ll; - lv = lv + 6; - char* ntok = gettok(&lv); - ll = atoi(ntok); - switch (ll) { - case 5: - { - /* EKV 2.6 in the adms branch */ - char* newline = tprintf(".model %s %s level=44 %s", modname, modtype, lv); - tfree(card->line); - card->line = curr_line = newline; - } - break; - case 6: - case 7: - { - /* BSIM3 version 3.2.4 */ - char* newline = tprintf(".model %s %s level=8 version=3.2.4 %s", modname, modtype, lv); - tfree(card->line); - card->line = curr_line = newline; - } - break; - case 8: - { - /* BSIM4 version 4.5.0 */ - char* newline = tprintf(".model %s %s level=14 version=4.5.0 %s", modname, modtype, lv); - tfree(card->line); - card->line = curr_line = newline; - } - break; - default: - break; - } - tfree(ntok); - } - } - else if (cieq(modtype, "NPN") || cieq(modtype, "PNP")) { - char* lv = strstr(cut_line, "level="); - if (lv) { - int ll; - lv = lv + 6; - char* ntok = gettok(&lv); - ll = atoi(ntok); - switch (ll) { - case 2: - { - /* MEXTRAM 504.12.1 in the adms branch */ - char* newline = tprintf(".model %s %s level=6 %s", modname, modtype, lv); - tfree(card->line); - card->line = curr_line = newline; - } - break; - default: - break; - } - tfree(ntok); - } - } - else if (cieq(modtype, "LPNP")) { - /* lateral PNP enabled */ - char* newline = tprintf(".model %s PNP level=1 subs=-1 %s", modname, cut_line); - tfree(card->line); - card->line = curr_line = newline; - } - tfree(modname); - tfree(modtype); - - /* Remove any Monte-Carlo variation parameters. They qualify - * a previous parameter, so there must be at least 3 tokens. - * There are two keywords "dev" (different values for each device), - * and "lot" (all devices of this model share a value). - * The keyword may be optionally followed by '/' and - * a probability distribution name, then there must be '=' and - * a value, then an optional '%' indicating relative rather than - * absolute variation. Allow muliple lot and dev on a single .model line. - */ - bool remdevlot = FALSE; - cut_line = curr_line; - for (i = 0; i < 3; i++) - cut_line = nexttok(cut_line); - while (cut_line) { - if (!strncmp(cut_line, "dev=", 4) || - !strncmp(cut_line, "lot=", 4)) { - while (*cut_line && !isspace_c(*cut_line)) { - *cut_line++ = ' '; - } - remdevlot = TRUE; - cut_line = skip_ws(cut_line); - continue; - } - cut_line = nexttok(cut_line); - } - if (remdevlot) { - tfree(card->line); - card->line = curr_line; - } - else - tfree(cut_del); - } // if .model - } // for loop through all cards - - /* x ... params: p1=val1, p2=val2 replace comma separator by space. - Do nothing if you are inside of { }. */ - for (card = newcard; card; card = card->nextcard) { - char* cut_line = card->line; - if (ciprefix("x", cut_line)) { - char* parastr = strstr(cut_line, "params:"); - int brace = 0; - if (parastr) { - parastr += 8; - while (*parastr) { - if (*parastr == '{') - brace++; - else if (*parastr == '}') - brace--; - if (brace == 0 && *parastr == ',') - *parastr = ' '; - parastr++; - } - } - } - } - - /* in R instance, replace TC = xx1, xx2 by TC1=xx1 TC2=xx2 */ - for (card = newcard; card; card = card->nextcard) { - char *cut_line = card->line; - - /* exclude any command inside .control ... .endc */ - if (ciprefix(".control", cut_line)) { - skip_control++; - continue; - } - else if (ciprefix(".endc", cut_line)) { - skip_control--; - continue; - } - else if (skip_control > 0) { - continue; - } - - if (*cut_line == 'r' || *cut_line == 'l' || *cut_line == 'c') { - /* Skip name and two nodes */ - char *ntok = nexttok(cut_line); - ntok = nexttok(ntok); - ntok = nexttok(ntok); - if (!ntok || *ntok == '\0') { - fprintf(stderr, "Error: Missing token in line %d:\n%s\n", - card->linenum, cut_line); - fprintf(stderr, " Please correct the input file\n"); - if (ft_stricterror) - controlled_exit(1); - else - continue; - } - char *tctok = search_plain_identifier(ntok, "tc"); - if (tctok) { - char *tc1, *tc2; - char *tctok1 = strchr(tctok, '='); - if (tctok1) - /* skip '=' */ - tctok1 += 1; - else - /* no '=' found, skip 'tc' */ - tctok1 = tctok + 2; - /* tc1 may be an expression, enclosed in {} */ - if (*tctok1 == '{') { - tc1 = gettok_char(&tctok1, '}', TRUE, TRUE); - } - else { - tc1 = gettok_node(&tctok1); - } - /* skip spaces and commas */ - while (isspace_c(*tctok1) || (*tctok1 == ',')) - tctok1++; - /* tc2 may be an expression, enclosed in {} */ - if (*tctok1 == '{') { - tc2 = gettok_char(&tctok1, '}', TRUE, TRUE); - } - else { - tc2 = gettok_node(&tctok1); - } - tctok[-1] = '\0'; - char *newstring; - if (tc1 && tc2) - newstring = tprintf("%s tc1=%s tc2=%s", - cut_line, tc1, tc2); - else if (tc1) - newstring = tprintf("%s tc1=%s", cut_line, tc1); - else { - fprintf(stderr, - "Warning: tc without parameters removed in line " - "\n %s\n", - cut_line); - continue; - } - tfree(card->line); - card->line = newstring; - tfree(tc1); - tfree(tc2); - } - } - } - - /* replace & with && , | with || , *# with * # , and ~ with ! */ - for (card = newcard; card; card = card->nextcard) { - char *t; - char *cut_line = card->line; - - /* we don't have command lines in a PSPICE model */ - if (ciprefix("*#", cut_line)) { - char *tmpstr = tprintf("* #%s", cut_line + 2); - tfree(card->line); - card->line = tmpstr; - continue; - } - - if (*cut_line == '*') - continue; - - if (*cut_line == '\0') - continue; - - /* exclude any command inside .control ... .endc */ - if (ciprefix(".control", cut_line)) { - skip_control++; - continue; - } - else if (ciprefix(".endc", cut_line)) { - skip_control--; - continue; - } - else if (skip_control > 0) { - continue; - } - if ((t = strstr(card->line, "&")) != NULL) { - while (t && (t[1] != '&')) { - char *tt = NULL; - char *tn = copy(t + 1); /*skip |*/ - char *strbeg = copy_substring(card->line, t); - tfree(card->line); - card->line = tprintf("%s&&%s", strbeg, tn); - tfree(strbeg); - tfree(tn); - t = card->line; - while ((t = strstr(t, "&&")) != NULL) - tt = t = t + 2; - if (!tt) - break; - else - t = strstr(tt, "&"); - } - } - if ((t = strstr(card->line, "|")) != NULL) { - while (t && (t[1] != '|')) { - char *tt = NULL; - char *tn = copy(t + 1); /*skip |*/ - char *strbeg = copy_substring(card->line, t); - tfree(card->line); - card->line = tprintf("%s||%s", strbeg, tn); - tfree(strbeg); - tfree(tn); - t = card->line; - while ((t = strstr(t, "||")) != NULL) - tt = t = t + 2; - if (!tt) - break; - else - t = strstr(tt, "|"); - } - } - /* We may have '~' in path names or A devices */ - if (ciprefix(".inc", card->line) || ciprefix(".lib", card->line) || - ciprefix("A", card->line)) - continue; - - if ((t = strstr(card->line, "~")) != NULL) { - while (t) { - *t = '!'; - t = strstr(t, "~"); - } - } - } - - /* replace T_ABS by temp, T_REL_GLOBAL by dtemp, and T_MEASURED by TNOM - in .model cards. What about T_REL_LOCAL ? T_REL_LOCAL is used in - conjunction with AKO and is not yet implemented. */ - for (card = newcard; card; card = card->nextcard) { - char *cut_line = card->line; - if (ciprefix(".model", cut_line)) { - char *t_str; - if ((t_str = strstr(cut_line, "t_abs")) != NULL) - memcpy(t_str, " temp", 5); - else if ((t_str = strstr(cut_line, "t_rel_global")) != NULL) - memcpy(t_str, " dtemp", 12); - else if ((t_str = strstr(cut_line, "t_measured")) != NULL) - memcpy(t_str, " tnom", 10); - } - } - - /* get the area factor for diodes and bipolar devices - d1 n1 n2 dmod 7 --> d1 n1 n2 dmod area=7 - q2 n1 n2 n3 [n4] bjtmod 1.35 --> q2 n1 n2 n3 n4 bjtmod area=1.35 - q3 1 2 3 4 bjtmod 1.45 --> q2 1 2 3 4 bjtmod area=1.45 - */ - for (card = newcard; card; card = card->nextcard) { - char *cut_line = card->line; - if (*cut_line == '*') - continue; - // exclude any command inside .control ... .endc - if (ciprefix(".control", cut_line)) { - skip_control++; - continue; - } - else if (ciprefix(".endc", cut_line)) { - skip_control--; - continue; - } - else if (skip_control > 0) { - continue; - } - if (*cut_line == 'q') { - /* According to PSPICE Reference Guide the fourth (substrate) node - has to be put into [] if it is not just a number */ - cut_line = nexttok(cut_line); //.model - cut_line = nexttok(cut_line); // node1 - cut_line = nexttok(cut_line); // node2 - cut_line = nexttok(cut_line); // node3 - if (!cut_line || *cut_line == '\0') { - fprintf(stderr, "Line no. %d, %s, missing tokens\n", - card->linenum_orig, card->line); - if (ft_stricterror) - controlled_exit(1); - else - continue; - } - if (*cut_line == '[') { // node4 not a number - *cut_line = ' '; - cut_line = strchr(cut_line, ']'); - *cut_line = ' '; - cut_line = skip_ws(cut_line); - cut_line = nexttok(cut_line); // model name - } - else { // if an integer number, it is node4 - bool is_node4 = TRUE; - while (*cut_line && !isspace_c(*cut_line)) - if (!isdigit_c(*cut_line++)) - is_node4 = FALSE; // already model name - if (is_node4) { - cut_line = nexttok(cut_line); // model name - } - } - if (cut_line && *cut_line && - atof(cut_line) > 0.0) { // size of area is a real number - char *tmpstr1 = copy_substring(card->line, cut_line); - char *tmpstr2 = tprintf("%s area=%s", tmpstr1, cut_line); - tfree(tmpstr1); - tfree(card->line); - card->line = tmpstr2; - } - else if (cut_line && *cut_line && - *(skip_ws(cut_line)) == - '{') { // size of area is parametrized inside {} - char *tmpstr1 = copy_substring(card->line, cut_line); - char *tmpstr2 = gettok_char(&cut_line, '}', TRUE, TRUE); - char *tmpstr3 = - tprintf("%s area=%s %s", tmpstr1, tmpstr2, cut_line); - tfree(tmpstr1); - tfree(tmpstr2); - tfree(card->line); - card->line = tmpstr3; - } - } - else if (*cut_line == 'd') { - cut_line = nexttok(cut_line); //.model - cut_line = nexttok(cut_line); // node1 - cut_line = nexttok(cut_line); // node2 - if (!cut_line || *cut_line == '\0') { - fprintf(stderr, "Line no. %d, %s, missing tokens\n", - card->linenum_orig, card->line); - if (ft_stricterror) - controlled_exit(1); - else - continue; - } - cut_line = nexttok(cut_line); // model name - if (cut_line && *cut_line && - atof(cut_line) > 0.0) { // size of area - char *tmpstr1 = copy_substring(card->line, cut_line); - char *tmpstr2 = tprintf("%s area=%s", tmpstr1, cut_line); - tfree(tmpstr1); - tfree(card->line); - card->line = tmpstr2; - } - } - } - - /* if vswitch part s, replace - * S1 D S DG GND SWN - * .MODEL SWN VSWITCH ( VON = {0.55} VOFF = {0.49} - * RON={1/(2*M*(W/LE)*(KPN/2)*10)} ROFF={1G} ) - * by - * a1 %v(DG) %gd(D S) swa - * .MODEL SWA aswitch(cntl_off=0.49 cntl_on=0.55 r_off=1G - * r_on={1/(2*M*(W/LE)*(KPN/2)*10)} log=TRUE) - * - * if vswitch part s_st, don't replace instance, only model - * replace - * S1 D S DG GND S_ST - * .MODEL S_ST VSWITCH(VT = { 1.5 } VH = { 0.s } - RON = { 1 / (2 * M*(W / LE)*(KPN / 2) * 10) } ROFF = { 1G }) - * by the classical voltage controlled ngspice switch - * S1 D S DG GND S_ST - * .MODEL S_ST SW(VT = { 1.5 } VH = { 0.s } - RON = { 1 / (2 * M*(W / LE)*(KPN / 2) * 10) } ROFF = { 1G }) - * vswitch delay parameter td is not yet supported - - * simple hierachy, as nested subcircuits are not allowed in PSPICE */ - - /* first scan: find the vswitch models, transform them and put the S models - into a list */ - for (card = newcard; card; card = card->nextcard) { - char *str; - static struct card *subcktline = NULL; - static int nesting = 0; - char *cut_line = card->line; - if (ciprefix(".subckt", cut_line)) { - subcktline = card; - nesting++; - } - if (ciprefix(".ends", cut_line)) - nesting--; - - if (ciprefix(".model", card->line) && strstr(card->line, "vswitch")) { - char *modname; - - str = card->line = inp_remove_ws(card->line); - str = nexttok(str); /* throw away '.model' */ - INPgetNetTok(&str, &modname, 0); /* model name */ - if (!ciprefix("vswitch", str)) { - tfree(modname); - continue; - } - str = nexttok_noparens(str); /* throw away 'vswitch' */ - /* S_ST switch (parameters ron, roff, vt, vh) - * we have to find 0 to 4 parameters, identified by 'vh=' etc. - * Parameters not found have to be replaced by their default values. */ - if (strstr(str, "vt=") || strstr(str, "vh=")) { - char* newstr; - char* lstr = copy(str); - char* partstr = strstr(lstr, "ron="); - if (!partstr) { - newstr = tprintf("%s %s", "ron=1.0", lstr); //default value - tfree(lstr); - lstr = newstr; - } - partstr = strstr(lstr, "roff="); - if (!partstr) { - newstr = tprintf("%s %s", "roff=1.0e12", lstr); //default value - tfree(lstr); - lstr = newstr; - } - partstr = strstr(lstr, "vt="); - if (!partstr) { - newstr = tprintf("%s %s", "vt=0", lstr); //default value - tfree(lstr); - lstr = newstr; - } - partstr = strstr(lstr, "vh="); - if (!partstr) { - newstr = tprintf("%s %s", "vh=0", lstr); //default value - tfree(lstr); - lstr = newstr; - } - tfree(card->line); - if (lstr[strlen(lstr) - 1] == ')') - card->line = tprintf(".model %s sw ( %s", modname, lstr); - else - card->line = tprintf(".model %s sw %s", modname, lstr); - tfree(lstr); - tfree(modname); - } - /* S vswitch (parameters ron, roff, von, voff) */ - /* We have to find 0 to 4 parameters, identified by 'von=' etc. and - * replace them by the pswitch code model parameters - * replace VON by cntl_on, VOFF by cntl_off, RON by r_on, and ROFF by r_off. - * Parameters not found have to be replaced by their default values. */ - else if (strstr(str, "von=") || strstr(str, "voff=")) { - char* newstr, *begstr; - char* lstr = copy(str); - /* ron */ - char* partstr = strstr(lstr, "ron="); - if (!partstr) { - newstr = tprintf("%s %s", "r_on=1.0", lstr); //default value - } - else { - begstr = copy_substring(lstr, partstr); - newstr = tprintf("%s r_on%s", begstr, partstr + 3); - tfree(begstr); - } - tfree(lstr); - lstr = newstr; - /* roff */ - partstr = strstr(lstr, "roff="); - if (!partstr) { - newstr = tprintf("%s %s", "r_off=1.0e6", lstr); //default value - } - else { - begstr = copy_substring(lstr, partstr); - newstr = tprintf("%s r_off%s", begstr, partstr + 4); - tfree(begstr); - } - tfree(lstr); - lstr = newstr; - /* von */ - partstr = strstr(lstr, "von="); - if (!partstr) { - newstr = tprintf("%s %s", "cntl_on=1", lstr); //default value - tfree(lstr); - lstr = newstr; - } - else { - begstr = copy_substring(lstr, partstr); - newstr = tprintf("%s cntl_on%s", begstr, partstr + 3); - tfree(begstr); - } - tfree(lstr); - lstr = newstr; - /* voff */ - partstr = strstr(lstr, "voff="); - if (!partstr) { - newstr = tprintf("%s %s", "cntl_off=0", lstr); //default value - tfree(lstr); - lstr = newstr; - } - else { - begstr = copy_substring(lstr, partstr); - newstr = tprintf("%s cntl_off%s", begstr, partstr + 4); - tfree(begstr); - } - tfree(lstr); - lstr = newstr; - tfree(card->line); - if (lstr[strlen(lstr) - 1] == ')') - card->line = tprintf(".model a%s pswitch( log=TRUE %s", modname, lstr); - else - card->line = tprintf(".model a%s pswitch(%s log=TRUE)", modname, lstr); - tfree(lstr); - /* add to list, to change vswitch instance to code model line */ - if (nesting > 0) - modelsfound = insert_new_model( - modelsfound, modname, subcktline->line); - else - modelsfound = insert_new_model(modelsfound, modname, "top"); - tfree(modname); - } - else { - fprintf(stderr, "Error: Bad switch model in line %s\n", card->line); - } - } - } - - /* no need to continue if no vswitch is found */ - if (!modelsfound) - goto iswi; - - /* second scan: find the switch instances s calling a vswitch model and - * transform them */ - for (card = newcard; card; card = card->nextcard) { - static struct card *subcktline = NULL; - static int nesting = 0; - char *cut_line = card->line; - if (*cut_line == '*') - continue; - // exclude any command inside .control ... .endc - if (ciprefix(".control", cut_line)) { - skip_control++; - continue; - } - else if (ciprefix(".endc", cut_line)) { - skip_control--; - continue; - } - else if (skip_control > 0) { - continue; - } - if (ciprefix(".subckt", cut_line)) { - subcktline = card; - nesting++; - } - if (ciprefix(".ends", cut_line)) - nesting--; - - if (ciprefix("s", cut_line)) { - /* check for the model name */ - int i; - bool good = TRUE; - char *stoks[6]; - for (i = 0; i < 6; i++) { - stoks[i] = gettok_node(&cut_line); - if (!stoks[i]) { - fprintf(stderr, "Error: Bad syntax in line:\n %s\n", card->line); - good = FALSE; - break; - } - } - if (!good) { - for (i = 0; i < 6; i++) - tfree(stoks[i]); - continue; - } - /* rewrite s line and replace it if a model is found */ - if ((nesting > 0) && - find_a_model(modelsfound, stoks[5], subcktline->line)) { - tfree(card->line); - card->line = tprintf("a%s %%gd(%s %s) %%gd(%s %s) a%s", - stoks[0], stoks[3], stoks[4], stoks[1], stoks[2], - stoks[5]); - } - /* if model is not within same subcircuit, search at top level */ - else if (find_a_model(modelsfound, stoks[5], "top")) { - tfree(card->line); - card->line = tprintf("a%s %%gd(%s %s) %%gd(%s %s) a%s", - stoks[0], stoks[3], stoks[4], stoks[1], stoks[2], - stoks[5]); - } - for (i = 0; i < 6; i++) - tfree(stoks[i]); - } - } - del_models(modelsfound); - modelsfound = NULL; - -iswi:; - - /* if iswitch part s, replace - * W1 D S VC SWN - * .MODEL SWN ISWITCH ( ION = {0.55} IOFF = {0.49} - * RON={1/(2*M*(W/LE)*(KPN/2)*10)} ROFF={1G} ) - * by - * a1 %v(DG) %gd(D S) swa - * .MODEL SWA aswitch(cntl_off=0.49 cntl_on=0.55 r_off=1G - * r_on={1/(2*M*(W/LE)*(KPN/2)*10)} log=TRUE) - * - * if iswitch part s_st (short transition), don't replace instance, but only model - * replace - * W1 D S VC S_ST - * .MODEL S_ST ISWITCH(IT = { 1.5 } IH = { 0.2 } - RON = { 1 / (2 * M*(W / LE)*(KPN / 2) * 10) } ROFF = { 1G }) - * by the classical current controlled ngspice switch - * W1 D S DG GND S_ST - * .MODEL S_ST CSW(IT = { 1.5 } IH = { 0.2 } - RON = { 1 / (2 * M*(W / LE)*(KPN / 2) * 10) } ROFF = { 1G }) - * iswitch delay parameter td is not yet supported - - * simple hierachy, as nested subcircuits are not allowed in PSPICE */ - - /* first scan: find the iswitch models, transform them and put them into a - * list */ - for (card = newcard; card; card = card->nextcard) { - char* str; - static struct card* subcktline = NULL; - static int nesting = 0; - char* cut_line = card->line; - if (ciprefix(".subckt", cut_line)) { - subcktline = card; - nesting++; - } - if (ciprefix(".ends", cut_line)) - nesting--; - - if (ciprefix(".model", card->line) && strstr(card->line, "iswitch")) { - char* modname; - - card->line = str = inp_remove_ws(card->line); - str = nexttok(str); /* throw away '.model' */ - INPgetNetTok(&str, &modname, 0); /* model name */ - if (!ciprefix("iswitch", str)) { - tfree(modname); - continue; - } - str = nexttok_noparens(str); /* throw away 'iswitch' */ - /* S_ST switch (parameters ron, roff, it, ih) - * we have to find 0 to 4 parameters, identified by 'ih=' etc. - * Parameters not found have to be replaced by their default values. */ - if (strstr(str, "it=") || strstr(str, "ih=")) { - char* newstr; - char* lstr = copy(str); - char* partstr = strstr(lstr, "ron="); - if (!partstr) { - newstr = tprintf("%s %s", "ron=1.0", lstr); //default value - tfree(lstr); - lstr = newstr; - } - partstr = strstr(lstr, "roff="); - if (!partstr) { - newstr = tprintf("%s %s", "roff=1.0e12", lstr); //default value - tfree(lstr); - lstr = newstr; - } - partstr = strstr(lstr, "it="); - if (!partstr) { - newstr = tprintf("%s %s", "it=0", lstr); //default value - tfree(lstr); - lstr = newstr; - } - partstr = strstr(lstr, "ih="); - if (!partstr) { - newstr = tprintf("%s %s", "ih=0", lstr); //default value - tfree(lstr); - lstr = newstr; - } - tfree(card->line); - if (lstr[strlen(lstr) - 1] == ')') - card->line = tprintf(".model %s csw ( %s", modname, lstr); - else - card->line = tprintf(".model %s csw %s", modname, lstr); - tfree(lstr); - tfree(modname); - } - /* S vswitch (parameters ron, roff, ion, ioff) */ - /* We have to find 0 to 4 parameters, identified by 'ion=' etc. and - * replace them by the pswitch code model parameters - * replace VON by cntl_on, VOFF by cntl_off, RON by r_on, and ROFF by r_off. - * Parameters not found have to be replaced by their default values. */ - else if (strstr(str, "ion=") || strstr(str, "ioff=")) { - char* newstr, * begstr; - char* lstr = copy(str); - /* ron */ - char* partstr = strstr(lstr, "ron="); - if (!partstr) { - newstr = tprintf("%s %s", "r_on=1.0", lstr); //default value - } - else { - begstr = copy_substring(lstr, partstr); - newstr = tprintf("%s r_on%s", begstr, partstr + 3); - } - tfree(lstr); - lstr = newstr; - /* roff */ - partstr = strstr(lstr, "roff="); - if (!partstr) { - newstr = tprintf("%s %s", "r_off=1.0e6", lstr); //default value - } - else { - begstr = copy_substring(lstr, partstr); - newstr = tprintf("%s r_off%s", begstr, partstr + 4); - } - tfree(lstr); - lstr = newstr; - /* von */ - partstr = strstr(lstr, "ion="); - if (!partstr) { - newstr = tprintf("%s %s", "cntl_on=1", lstr); //default value - tfree(lstr); - lstr = newstr; - } - else { - begstr = copy_substring(lstr, partstr); - newstr = tprintf("%s cntl_on%s", begstr, partstr + 3); - } - tfree(lstr); - lstr = newstr; - /* voff */ - partstr = strstr(lstr, "ioff="); - if (!partstr) { - newstr = tprintf("%s %s", "cntl_off=0", lstr); //default value - tfree(lstr); - lstr = newstr; - } - else { - begstr = copy_substring(lstr, partstr); - newstr = tprintf("%s cntl_off%s", begstr, partstr + 4); - } - tfree(lstr); - lstr = newstr; - tfree(card->line); - if (lstr[strlen(lstr) - 1] == ')') - card->line = tprintf(".model a%s aswitch( log=TRUE limit=TRUE %s", modname, lstr); - else - card->line = tprintf(".model a%s aswitch(%s log=TRUE limit=TRUE)", modname, lstr); - tfree(lstr); - /* add to list, to change vswitch instance to code model line */ - if (nesting > 0) - modelsfound = insert_new_model( - modelsfound, modname, subcktline->line); - else - modelsfound = insert_new_model(modelsfound, modname, "top"); - tfree(modname); - } - else { - fprintf(stderr, "Error: Bad switch model in line %s\n", card->line); - } - } - } - -#if(0) - /* we have to find 4 parameters, identified by '=', separated by - * spaces */ - char* equalptr[4]; - equalptr[0] = strstr(str, "="); - if (!equalptr[0]) { - fprintf(stderr, - "Error: not enough parameters in iswitch model\n " - "%s\n", - card->line); - controlled_exit(1); - } - for (i = 1; i < 4; i++) { - equalptr[i] = strstr(equalptr[i - 1] + 1, "="); - if (!equalptr[i]) { - fprintf(stderr, - "Error: not enough parameters in iswitch model\n " - " %s\n", - card->line); - controlled_exit(1); - } - } - for (i = 0; i < 4; i++) { - equalptr[i] = skip_back_ws(equalptr[i], str); - while (*(equalptr[i]) != '(' && !isspace_c(*(equalptr[i])) && - *(equalptr[i]) != ',') - (equalptr[i])--; - (equalptr[i])++; - } - for (i = 0; i < 3; i++) - modpar[i] = copy_substring(equalptr[i], equalptr[i + 1] - 1); - if (strrchr(equalptr[3], ')')) - modpar[3] = copy_substring( - equalptr[3], strrchr(equalptr[3], ')')); - else - /* iswitch defined without parens */ - modpar[3] = copy(equalptr[3]); - - /* check if we have parameters IT and IH */ - for (i = 0; i < 4; i++) { - if (ciprefix("ih", modpar[i])) - have_ih = TRUE; - if (ciprefix("it", modpar[i])) - have_it = TRUE; - } - if (have_ih && have_it) { - /* replace iswitch by csw */ - char* vs = strstr(card->line, "iswitch"); - memmove(vs, " csw", 7); - } - else { - /* replace ION by cntl_on, IOFF by cntl_off, RON by r_on, and - * ROFF by r_off */ - tfree(card->line); - rep_spar(modpar); - card->line = tprintf( - /* FIXME: a new switch derived from pswitch with vnam input is due */ - ".model a%s aswitch(%s %s %s %s log=TRUE limit=TRUE)", modname, - modpar[0], modpar[1], modpar[2], modpar[3]); - } - for (i = 0; i < 4; i++) - tfree(modpar[i]); - if (nesting > 0) - modelsfound = insert_new_model( - modelsfound, modname, subcktline->line); - else - modelsfound = insert_new_model(modelsfound, modname, "top"); - tfree(modname); - } - } -#endif - /* no need to continue if no iswitch is found */ - if (!modelsfound) - return newcard; - - /* second scan: find the switch instances s calling an iswitch model and - * transform them */ - for (card = newcard; card; card = card->nextcard) { - static struct card* subcktline = NULL; - static int nesting = 0; - char* cut_line = card->line; - if (*cut_line == '*') - continue; - // exclude any command inside .control ... .endc - if (ciprefix(".control", cut_line)) { - skip_control++; - continue; - } - else if (ciprefix(".endc", cut_line)) { - skip_control--; - continue; - } - else if (skip_control > 0) { - continue; - } - if (ciprefix(".subckt", cut_line)) { - subcktline = card; - nesting++; - } - if (ciprefix(".ends", cut_line)) - nesting--; - - if (ciprefix("w", cut_line)) { - /* check for the model name */ - int i; - char* stoks[5]; - for (i = 0; i < 5; i++) - stoks[i] = gettok_node(&cut_line); - /* rewrite w line and replace it if a model is found */ - if ((nesting > 0) && - find_a_model(modelsfound, stoks[4], subcktline->line)) { - tfree(card->line); - card->line = tprintf("a%s %%vnam(%s) %%gd(%s %s) a%s", - stoks[0], stoks[3], stoks[1], stoks[2], - stoks[4]); - } - /* if model is not within same subcircuit, search at top level */ - else if (find_a_model(modelsfound, stoks[4], "top")) { - tfree(card->line); - card->line = tprintf("a%s %%vnam(%s) %%gd(%s %s) a%s", - stoks[0], stoks[3], stoks[1], stoks[2], - stoks[4]); - } - for (i = 0; i < 5; i++) - tfree(stoks[i]); - } - } - del_models(modelsfound); - - return newcard; -} - - - -/* do not modify oldcard address, insert everything after first line only */ -static void pspice_compat_a(struct card *oldcard) -{ - oldcard->nextcard = pspice_compat(oldcard->nextcard); -} - - -/**** LTSPICE to ngspice ************** - * add functions uplim, dnlim - * Replace - * D1 A K SDMOD - * .MODEL SDMOD D (Roff=1000 Ron=0.7 Rrev=0.2 Vfwd=1 Vrev=10 Revepsilon=0.2 - * Epsilon=0.2 Ilimit=7 Revilimit=7) - * by - * ad1 a k asdmod - * .model asdmod sidiode(Roff=1000 Ron=0.7 Rrev=0.2 Vfwd=1 Vrev=10 - * Revepsilon=0.2 Epsilon=0.2 Ilimit=7 Revilimit=7) - * Remove '.backanno' - */ -static struct card *ltspice_compat(struct card *oldcard) -{ - struct card *card, *newcard, *nextcard; - struct vsmodels *modelsfound = NULL; - int skip_control = 0; - - - /* remove double braces only if not yet done in pspice_compat() */ - if (!newcompat.ps) - rem_double_braces(oldcard); - - /* add funcs uplim, dnlim to beginning of deck */ - char *new_str = - copy(".func uplim(x, pos, z) { min(x, pos - z) + (1 - " - "(min(max(0, x - pos + z), 2 * z) / 2 / z - 1)**2)*z }"); - newcard = insert_new_line(NULL, new_str, 1, 0); - new_str = copy(".func dnlim(x, neg, z) { max(x, neg + z) - (1 - " - "(min(max(0, -x + neg + z), 2 * z) / 2 / z - 1)**2)*z }"); - nextcard = insert_new_line(newcard, new_str, 2, 0); - new_str = copy(".func uplim_tanh(x, pos, z) { min(x, pos - z) + " - "tanh(max(0, x - pos + z) / z)*z }"); - nextcard = insert_new_line(nextcard, new_str, 3, 0); - new_str = copy(".func dnlim_tanh(x, neg, z) { max(x, neg + z) - " - "tanh(max(0, neg + z - x) / z)*z }"); - nextcard = insert_new_line(nextcard, new_str, 4, 0); - nextcard->nextcard = oldcard; - - /* remove .backanno, replace 'noiseless' by 'moisy=0' */ - for (card = nextcard; card; card = card->nextcard) { - char* cut_line = card->line; - if (ciprefix(".backanno", cut_line)) { - *cut_line = '*'; - } - else if (*cut_line == 'r') { - char* noi = strstr(cut_line, "noiseless"); - /* only if 'noiseless' is an unconnected token */ - if (noi && isspace_c(noi[-1]) && (isspace_c(noi[9]) || !isprint_c(noi[9]))) { - memcpy(noi, "noisy=0 ", 9); - } - } - } - - /* replace - * D1 A K SDMOD - * .MODEL SDMOD D (Roff=1000 Ron=0.7 Rrev=0.2 Vfwd=1 Vrev=10 - * Revepsilon=0.2 Epsilon=0.2 Ilimit=7 Revilimit=7) - * by - * a1 a k SDMOD - * .model SDMOD sidiode(Roff=1000 Ron=0.7 Rrev=0.2 Vfwd=1 Vrev=10 - * Revepsilon=0.2 Epsilon=0.2 Ilimit=7 Revilimit=7) - * Do this if one of the parameters, which are uncommon to standard diode - * model, has been found. - - * simple hierachy, as nested subcircuits are not allowed in PSPICE */ - - /* first scan: find the d models, transform them and put them into a list - */ - for (card = nextcard; card; card = card->nextcard) { - char *str; - static struct card *subcktline = NULL; - static int nesting = 0; - char *cut_line = card->line; - if (*cut_line == '*' || *cut_line == '\0') - continue; - else if (ciprefix(".subckt", cut_line)) { - subcktline = card; - nesting++; - } - else if (ciprefix(".ends", cut_line)) - nesting--; - - else if (ciprefix(".model", card->line) && - search_plain_identifier(card->line, "d")) { - if (search_plain_identifier(card->line, "roff") || - search_plain_identifier(card->line, "ron") || - search_plain_identifier(card->line, "rrev") || - search_plain_identifier(card->line, "vfwd") || - search_plain_identifier(card->line, "vrev") || - search_plain_identifier(card->line, "revepsilon") || - search_plain_identifier(card->line, "epsilon") || - search_plain_identifier(card->line, "revilimit") || - search_plain_identifier(card->line, "ilimit")) { - char *modname; - - /* remove parameter 'noiseless' (the model is noiseless anyway) */ - char *nonoise = search_plain_identifier(card->line, "noiseless"); - if (nonoise) { - size_t iii; - for (iii = 0; iii < 9; iii++) - nonoise[iii] = ' '; - } - card->line = str = inp_remove_ws(card->line); - str = nexttok(str); /* throw away '.model' */ - INPgetNetTok(&str, &modname, 0); /* model name */ - if (!ciprefix("d", str)) { - tfree(modname); - continue; - } - /* skip d */ - str++; - /* we take all the existing parameters */ - char *newstr = copy(str); - tfree(card->line); - card->line = tprintf(".model a%s sidiode%s", modname, newstr); - if (nesting > 0) - modelsfound = insert_new_model( - modelsfound, modname, subcktline->line); - else - modelsfound = - insert_new_model(modelsfound, modname, "top"); - tfree(modname); - tfree(newstr); - } - } - else - continue; - } - - /* no need to continue if no d is found */ - if (!modelsfound) - return newcard; - - /* second scan: find the diode instances d calling a simple diode model - * and transform them */ - for (card = nextcard; card; card = card->nextcard) { - static struct card *subcktline = NULL; - static int nesting = 0; - char *cut_line = card->line; - if (*cut_line == '*') - continue; - if (*cut_line == '\0') - continue; - // exclude any command inside .control ... .endc - if (ciprefix(".control", cut_line)) { - skip_control++; - continue; - } - else if (ciprefix(".endc", cut_line)) { - skip_control--; - continue; - } - else if (skip_control > 0) { - continue; - } - if (ciprefix(".subckt", cut_line)) { - subcktline = card; - nesting++; - } - if (ciprefix(".ends", cut_line)) - nesting--; - - if (ciprefix("d", cut_line)) { - /* check for the model name */ - int i; - char *stoks[4]; - for (i = 0; i < 4; i++) { - stoks[i] = gettok_node(&cut_line); - if (stoks[i] == NULL) { - fprintf(stderr, "Error in line %d: buggy diode instance line\n %s\n", card->linenum_orig, card->line); - fprintf(stderr, "At least 'Dxx n1 n2 d' is required.\n"); - controlled_exit(EXIT_BAD); - } - } - /* rewrite d line and replace it if a model is found */ - if ((nesting > 0) && - find_a_model(modelsfound, stoks[3], subcktline->line)) { - tfree(card->line); - card->line = tprintf("a%s %s %s a%s", - stoks[0], stoks[1], stoks[2], stoks[3]); - } - /* if model is not within same subcircuit, search at top level */ - else if (find_a_model(modelsfound, stoks[3], "top")) { - tfree(card->line); - card->line = tprintf("a%s %s %s a%s", - stoks[0], stoks[1], stoks[2], stoks[3]); - } - for (i = 0; i < 4; i++) - tfree(stoks[i]); - } - } - del_models(modelsfound); - - return newcard; -} - -/* do not modify oldcard address, insert everything after first line only */ -static void ltspice_compat_a(struct card *oldcard) -{ - oldcard->nextcard = ltspice_compat(oldcard->nextcard); -} /* syntax check: Check if we have a .control ... .endc pair, diff --git a/src/frontend/inpcom.h b/src/frontend/inpcom.h index fa8d243f8..e7cf5eaec 100644 --- a/src/frontend/inpcom.h +++ b/src/frontend/inpcom.h @@ -9,4 +9,8 @@ struct card *insert_new_line(struct card *card, char *line, int linenum, int linenum_orig); char *inp_pathresolve(const char *name); + +extern char* inp_remove_ws(char* s); +extern char* search_plain_identifier(char* str, const char* identifier); + #endif diff --git a/src/frontend/inpcompat.c b/src/frontend/inpcompat.c new file mode 100644 index 000000000..4c0ce979a --- /dev/null +++ b/src/frontend/inpcompat.c @@ -0,0 +1,1868 @@ +/********** +Copyright 2023 The ngspice team. All rights reserved. +License: Three-clause BCD +Author: 2023 Holger Vogt +**********/ + +/* + For dealing with compatibility transformations + + PSICE, LTSPICE and others +*/ + +#include "ngspice/ngspice.h" + +#include "ngspice/compatmode.h" +#include "ngspice/cpdefs.h" +#include "ngspice/dstring.h" +#include "ngspice/dvec.h" +#include "ngspice/ftedefs.h" +#include "ngspice/fteext.h" +#include "ngspice/fteinp.h" +#include "numparam/general.h" + +#include +#include + +#include +#include + +#if !defined(__MINGW32__) && !defined(_MSC_VER) +#include +#endif + +#include "../misc/util.h" /* ngdirname() */ +#include "inpcom.h" +#include "ngspice/stringskip.h" +#include "ngspice/stringutil.h" +#include "ngspice/wordlist.h" +#include "subckt.h" +#include "variable.h" + +#define INTEGRATE_UDEVICES +#ifdef INTEGRATE_UDEVICES +#include "ngspice/udevices.h" +#endif + +void print_compat_mode(void); +void set_compat_mode(void); +struct card* pspice_compat(struct card* newcard); +void pspice_compat_a(struct card* oldcard); +struct card* ltspice_compat(struct card* oldcard); +void ltspice_compat_a(struct card* oldcard); + + + +/* Set a compatibility flag. +Currently available are flags for: +- LTSPICE, HSPICE, Spice3, PSPICE, KiCad, Spectre, XSPICE +*/ +struct compat newcompat; +void set_compat_mode(void) +{ + char behaviour[80]; + newcompat.hs = FALSE; + newcompat.ps = FALSE; + newcompat.xs = FALSE; + newcompat.lt = FALSE; + newcompat.ki = FALSE; + newcompat.a = FALSE; + newcompat.spe = FALSE; + newcompat.isset = FALSE; + newcompat.s3 = FALSE; + newcompat.mc = FALSE; + if (cp_getvar("ngbehavior", CP_STRING, behaviour, sizeof(behaviour))) { + if (strstr(behaviour, "hs")) + newcompat.isset = newcompat.hs = TRUE; /*HSPICE*/ + if (strstr(behaviour, "ps")) + newcompat.isset = newcompat.ps = TRUE; /*PSPICE*/ + if (strstr(behaviour, "xs")) + newcompat.isset = newcompat.xs = TRUE; /*XSPICE*/ + if (strstr(behaviour, "lt")) + newcompat.isset = newcompat.lt = TRUE; /*LTSPICE*/ + if (strstr(behaviour, "ki")) + newcompat.isset = newcompat.ki = TRUE; /*KiCad*/ + if (strstr(behaviour, "a")) + newcompat.isset = newcompat.a = TRUE; /*complete netlist, used in conjuntion with other mode*/ + if (strstr(behaviour, "ll")) + newcompat.isset = newcompat.ll = TRUE; /*all (currently not used)*/ + if (strstr(behaviour, "s3")) + newcompat.isset = newcompat.s3 = TRUE; /*spice3 only*/ + if (strstr(behaviour, "eg")) + newcompat.isset = newcompat.eg = TRUE; /*EAGLE*/ + if (strstr(behaviour, "spe")) { + newcompat.isset = newcompat.spe = TRUE; /*Spectre*/ + newcompat.ps = newcompat.lt = newcompat.ki = newcompat.eg = FALSE; + } + if (strstr(behaviour, "mc")) { + newcompat.isset = FALSE; + newcompat.mc = TRUE; /*make check*/ + } + } + if (newcompat.hs && newcompat.ps) { + fprintf(stderr, "Warning: hs and ps compatibility are mutually exclusive, switch to ps!\n"); + newcompat.hs = FALSE; + } + /* reset everything for 'make check' */ + if (newcompat.mc) + newcompat.eg = newcompat.hs = newcompat.spe = newcompat.ps = newcompat.xs = + newcompat.ll = newcompat.lt = newcompat.ki = newcompat.a = FALSE; +} + +/* Print the compatibility flags */ +void print_compat_mode(void) { + if (newcompat.mc) /* make check */ + return; + if (newcompat.isset) { + fprintf(stdout, "\n"); + fprintf(stdout, "Note: Compatibility modes selected:"); + if (newcompat.hs) + fprintf(stdout, " hs"); + if (newcompat.ps) + fprintf(stdout, " ps"); + if (newcompat.xs) + fprintf(stdout, " xs"); + if (newcompat.lt) + fprintf(stdout, " lt"); + if (newcompat.ki) + fprintf(stdout, " ki"); + if (newcompat.ll) + fprintf(stdout, " ll"); + if (newcompat.s3) + fprintf(stdout, " s3"); + if (newcompat.eg) + fprintf(stdout, " eg"); + if (newcompat.spe) + fprintf(stdout, " spe"); + if (newcompat.a) + fprintf(stdout, " a"); + fprintf(stdout, "\n\n"); + } + else { + fprintf(stdout, "\n"); + fprintf(stdout, "Note: No compatibility mode selected!\n\n"); + } +} + + +/* replace the E and G source TABLE function by a B source pwl + * (used by ST OpAmps and comparators of Infineon models). + * E_RO_3 VB_3 VB_4 VALUE={ TABLE( V(VCCP,VCCN), 2 , 35 , 3.3 , 15 , 5 , 10 + * )*I(VreadIo)} + * will become + * BE_RO_3_1 TABLE_NEW_1 0 v = pwl( V(VCCP,VCCN), 2 , 35 , 3.3 , 15 , 5 , 10) + * E_RO_3 VB_3 VB_4 VALUE={ V(TABLE_NEW_1)*I(VreadIo)} + */ +static void replace_table(struct card *startcard) +{ + struct card *card; + static int numb = 0; + for (card = startcard; card; card = card->nextcard) { + char *cut_line = card->line; + if (*cut_line == 'e' || *cut_line == 'g') { + char *valp = search_plain_identifier(cut_line, "value"); + char *valp2 = search_plain_identifier(cut_line, "cur"); + if (valp || (valp2 && *cut_line == 'g')) { + char *ftablebeg = strstr(cut_line, "table("); + while (ftablebeg) { + /* get the beginning of the line */ + char *begline = copy_substring(cut_line, ftablebeg); + /* get the table function */ + char *tabfun = gettok_char(&ftablebeg, ')', TRUE, TRUE); + /* the new e, g line */ + char *neweline = tprintf("%s v(table_new_%d)%s", + begline, numb, ftablebeg); + char *newbline = + tprintf("btable_new_%d table_new_%d 0 v=pwl%s", + numb, numb, tabfun + 5); + numb++; + tfree(tabfun); + tfree(begline); + tfree(card->line); + card->line = cut_line = neweline; + insert_new_line(card, newbline, 0, card->linenum_orig); + /* read next TABLE function in cut_line */ + ftablebeg = strstr(cut_line, "table("); + } + continue; + } + } + } +} + +/* find the model requested by ako:model and do the replacement */ +static struct card *find_model(struct card *startcard, + struct card *changecard, char *searchname, char *newmname, + char *newmtype, char *endstr) +{ + struct card *nomod, *returncard = changecard; + char *origmname, *origmtype; + char *beginline = startcard->line; + if (ciprefix(".subckt", beginline)) + startcard = startcard->nextcard; + + int nesting2 = 0; + for (nomod = startcard; nomod; nomod = nomod->nextcard) { + char *origmodline = nomod->line; + if (ciprefix(".subckt", origmodline)) + nesting2++; + if (ciprefix(".ends", origmodline)) + nesting2--; + /* skip any subcircuit */ + if (nesting2 > 0) + continue; + if (nesting2 == -1) { + returncard = changecard; + break; + } + if (ciprefix(".model", origmodline)) { + origmodline = nexttok(origmodline); + origmname = gettok(&origmodline); + origmtype = gettok_noparens(&origmodline); + if (cieq(origmname, searchname)) { + if (!eq(origmtype, newmtype)) { + fprintf(stderr, + "Error: Original (%s) and new (%s) type for AKO " + "model disagree\n", + origmtype, newmtype); + controlled_exit(1); + } + /* we have got it */ + char *newmodcard = tprintf(".model %s %s %s%s", + newmname, newmtype, origmodline, endstr); + char *tmpstr = strstr(newmodcard, ")("); + if (tmpstr) { + tmpstr[0] = ' '; + tmpstr[1] = ' '; + } + tfree(changecard->line); + changecard->line = newmodcard; + tfree(origmname); + tfree(origmtype); + returncard = NULL; + break; + } + tfree(origmname); + tfree(origmtype); + } + else + returncard = changecard; + } + return returncard; +} + +/* Process any .distribution cards for PSPICE's Monte-Carlo feature. + * A .distribution card defines a probability distribution by a PWL + * density function. This could be rewritten as a function that + * returns a random value following that distribution. + * For now, just comment it away. + */ +static void do_distribution(struct card *oldcard) { + while (oldcard) { + char *line = oldcard->line; + + if (line && ciprefix(".distribution", line)) + *line = '*'; + oldcard = oldcard->nextcard; + } +} + +/* Do the .model replacement required by ako (a kind of) + * PSPICE does not support nested .subckt definitions, so + * a simple structure is needed: search for ako:modelname, + * then for modelname in the subcircuit or in the top level. + * .model qorig npn (BF=48 IS=2e-7) + * .model qbip1 ako:qorig NPN (BF=60 IKF=45m) + * after the replacement we have + * .model qbip1 NPN (BF=48 IS=2e-7 BF=60 IKF=45m) + * and we benefit from the fact that if parameters have + * doubled, the last entry of a parameter (e.g. BF=60) + * overwrites the previous one (BF=48). + */ +static struct card *ako_model(struct card *startcard) +{ + char *newmname, *newmtype; + struct card *card, *returncard = NULL, *subcktcard = NULL; + for (card = startcard; card; card = card->nextcard) { + char *akostr, *searchname; + char *cut_line = card->line; + + if (ciprefix(".subckt", cut_line)) + subcktcard = card; + else if (ciprefix(".ends", cut_line)) + subcktcard = NULL; + if (ciprefix(".model", cut_line)) { + if ((akostr = strstr(cut_line, "ako:")) != NULL && + isspace_c(akostr[-1])) { + akostr += 4; + searchname = gettok(&akostr); + cut_line = nexttok(cut_line); + newmname = gettok(&cut_line); + newmtype = gettok_noparens(&akostr); + + /* Find the model and do the replacement. */ + + if (subcktcard) + returncard = find_model(subcktcard, card, searchname, + newmname, newmtype, akostr); + if (returncard || !subcktcard) + returncard = find_model(startcard, card, searchname, + newmname, newmtype, akostr); + tfree(searchname); + tfree(newmname); + tfree(newmtype); + + /* Replacement not possible, bail out. */ + + if (returncard) + break; + } + } + } + return returncard; +} + +struct vsmodels { + char *modelname; + char *subcktline; + struct vsmodels *nextmodel; +}; + +/* insert a new model, just behind the given model */ +static struct vsmodels *insert_new_model( + struct vsmodels *vsmodel, char *name, char *subcktline) +{ + struct vsmodels *x = TMALLOC(struct vsmodels, 1); + + x->nextmodel = vsmodel ? vsmodel->nextmodel : NULL; + x->modelname = copy(name); + x->subcktline = copy(subcktline); + if (vsmodel) + vsmodel->nextmodel = x; + else + vsmodel = x; + + return vsmodel; +} + +/* find the model */ +static bool find_a_model( + struct vsmodels *vsmodel, char *name, char *subcktline) +{ + struct vsmodels *x; + for (x = vsmodel; vsmodel; vsmodel = vsmodel->nextmodel) + if (eq(vsmodel->modelname, name) && + eq(vsmodel->subcktline, subcktline)) + return TRUE; + return FALSE; +} + +/* delete the vsmodels list */ +static bool del_models(struct vsmodels *vsmodel) +{ + struct vsmodels *x; + + if (!vsmodel) + return FALSE; + + while (vsmodel) { + x = vsmodel->nextmodel; + tfree(vsmodel->modelname); + tfree(vsmodel->subcktline); + tfree(vsmodel); + vsmodel = x; + } + + return TRUE; +} + +/* Check for double '{', replace the inner '{', '}' by '(', ')' + in .subckt or .model (which both may stem from external sources) */ +static void rem_double_braces(struct card* newcard) +{ + struct card* card; + int slevel = 0; + + for (card = newcard; card; card = card->nextcard) { + char* cut_line = card->line; + if (ciprefix(".subckt", cut_line)) + slevel++; + else if (ciprefix(".ends", cut_line)) + slevel--; + if (ciprefix(".model", cut_line) || slevel > 0) { + cut_line = strchr(cut_line, '{'); + if (cut_line) { + int level = 1; + cut_line++; + while (*cut_line != '\0') { + if (*cut_line == '{') { + level++; + if (level > 1) + *cut_line = '('; + } + else if (*cut_line == '}') { + if (level > 1) + *cut_line = ')'; + level--; + } + cut_line++; + } + } + } + } +} + +#ifdef INTEGRATE_UDEVICES +static void list_the_cards(struct card *startcard, char *prefix) +{ + struct card *card; + if (!startcard) { return; } + for (card = startcard; card; card = card->nextcard) { + char* cut_line = card->line; + printf("%s %s\n", prefix, cut_line); + } +} + +static struct card *the_last_card(struct card *startcard) +{ + struct card *card, *lastcard = NULL; + if (!startcard) { return NULL; } + for (card = startcard; card; card = card->nextcard) { + lastcard = card; + } + return lastcard; +} + static void remove_old_cards(struct card *first, struct card *stop) +{ + struct card *x, *y, *next = NULL, *nexta = NULL; + if (!first || !stop || (first == stop)) { return; } + for (x = first; (x && (x != stop)); x = next) { + if (x->line) { tfree(x->line); } + if (x->error) { tfree(x->error); } + for (y = x->actualLine; y; y = nexta) { + if (y->line) { tfree(y->line); } + if (y->error) { tfree(y->error); } + nexta = y->nextcard; + tfree(y); + } + next = x->nextcard; + tfree(x); + } + +} + +static struct card *u_instances(struct card *startcard) +{ + struct card *card, *returncard = NULL, *subcktcard = NULL; + struct card *newcard = NULL, *last_newcard = NULL; + int models_ok = 0, models_not_ok = 0; + int udev_ok = 0, udev_not_ok = 0; + BOOL create_called = FALSE, repeat_pass = FALSE; + BOOL skip_next = FALSE; + + card = startcard; + while (card) { + char *cut_line = card->line; + + skip_next = FALSE; + if (ciprefix(".subckt", cut_line)) { + models_ok = models_not_ok = 0; + udev_ok = udev_not_ok = 0; + subcktcard = card; + if (!repeat_pass) { + if (create_called) { + cleanup_udevice(); + } + initialize_udevice(subcktcard->line); + create_called = TRUE; + } + } else if (ciprefix(".ends", cut_line)) { + if (repeat_pass) { + newcard = replacement_udevice_cards(); + if (newcard) { + char *tmp = NULL, *pos, *posp, *new_str = NULL, *cl; + /* Pspice definition of .subckt card: + .SUBCKT [node]* + + [OPTIONAL: < = >*] + + [PARAMS: < = >* ] + + [TEXT: < = >* ] + ... + .ENDS + */ + cl = subcktcard->line; + tmp = TMALLOC(char, strlen(cl) + 1); + (void) memcpy(tmp, cl, strlen(cl) + 1); + pos = strstr(tmp, "optional:"); + posp = strstr(tmp, "params:"); + /* If there is an optional: and a param: then posp > pos */ + if (pos) { + /* Remove the optional: section if present */ + *pos = '\0'; + if (posp) { + strcat(tmp, posp); + } + } + new_str = copy(tmp); + tfree(tmp); + remove_old_cards(subcktcard->nextcard, card); + subcktcard->nextcard = newcard; + tfree(subcktcard->line); + subcktcard->line = new_str; + if (ft_ngdebug) { + printf("%s\n", new_str); + list_the_cards(newcard, "Replacement:"); + } + last_newcard = the_last_card(newcard); + if (last_newcard) { + last_newcard->nextcard = card; // the .ends card + } + } else { + models_ok = models_not_ok = 0; + udev_ok = udev_not_ok = 0; + } + } + if (models_not_ok > 0 || udev_not_ok > 0) { + repeat_pass = FALSE; + cleanup_udevice(); + create_called = FALSE; + } else if (udev_ok > 0) { + repeat_pass = TRUE; + card = subcktcard; + skip_next = TRUE; + } else { + repeat_pass = FALSE; + cleanup_udevice(); + create_called = FALSE; + } + subcktcard = NULL; + } else if (ciprefix(".model", cut_line)) { + if (subcktcard && !repeat_pass) { + if (!u_process_model_line(cut_line)) { + models_not_ok++; + } else { + models_ok++; + } + } + } else if (ciprefix("u", cut_line)) { + if (subcktcard) { + if (repeat_pass) { + if (!u_process_instance(cut_line)) { + repeat_pass = FALSE; + cleanup_udevice(); + create_called = FALSE; + subcktcard = NULL; + models_ok = models_not_ok = 0; + udev_ok = udev_not_ok = 0; + skip_next = FALSE; + } + } else { + if (u_check_instance(cut_line)) { + udev_ok++; + } else { + udev_not_ok++; + } + } + } + } else { + if (!ciprefix("*", cut_line)) { + udev_not_ok++; + } + } + + if (!skip_next) { + card = card->nextcard; + } + } + if (create_called) { + cleanup_udevice(); + } + return returncard; +} +#endif + +/**** PSPICE to ngspice ************** +* .model replacement in ako (a kind of) model descriptions +* replace the E source TABLE function by a B source pwl +* add predefined params TEMP, VT, GMIN to beginning of deck +* add predefined params TEMP, VT, GMIN to beginning of each .subckt call +* add .functions limit, pwr, pwrs, stp, if, int +* replace vswitch part S + S1 D S DG GND SWN + .MODEL SWN VSWITCH(VON = { 0.55 } VOFF = { 0.49 } + RON = { 1 / (2 * M*(W / LE)*(KPN / 2) * 10) } ROFF = { 1G }) +* by + as1 %vd(DG GND) % gd(D S) aswn + .model aswn aswitch(cntl_off={0.49} cntl_on={0.55} r_off={1G} + + r_on={ 1 / (2 * M*(W / LE)*(KPN / 2) * 10) } log = TRUE) +* replace vswitch part S_ST + S1 D S DG GND S_ST + .MODEL S_ST VSWITCH(VT = { 1.5 } VH = { 0.3 } + RON = { 1 / (2 * M*(W / LE)*(KPN / 2) * 10) } ROFF = { 1G }) +* by the classical voltage controlled ngspice switch + S1 D S DG GND SWN + .MODEL S_ST SW(VT = { 1.5 } VH = { 0.3 } + RON = { 1 / (2 * M*(W / LE)*(KPN / 2) * 10) } ROFF = { 1G }) + switch parameter td is not yet supported +* replace & by && +* replace | by || +* in R instance, replace TC = xx1, xx2 by TC1=xx1 TC2=xx2 +* replace T_ABS by temp and T_REL_GLOBAL by dtemp in .model cards +* get the area factor for diodes and bipolar devices +* in subcircuit .subckt and X lines with 'params:' statement + replace comma separator by space. Do nothing if comma is inside of {}. +* in .model, if double curly braces {{}}, replace the inner by {()} */ +struct card *pspice_compat(struct card *oldcard) +{ + struct card *card, *newcard, *nextcard; + struct vsmodels *modelsfound = NULL; + int skip_control = 0; + + /* .model replacement in ako (a kind of) model descriptions + * in first .subckt and top level only */ + struct card *errcard; + if ((errcard = ako_model(oldcard)) != NULL) { + fprintf(stderr, "Error: no model found for %s\n", errcard->line); + controlled_exit(1); + } + + /* Process .distribution cards. */ + do_distribution(oldcard); + + /* replace TABLE function in E source */ + replace_table(oldcard); + + /* remove double braces */ + rem_double_braces(oldcard); + + /* add predefined params TEMP, VT, GMIN to beginning of deck */ + char *new_str = copy(".param temp = 'temper'"); + newcard = insert_new_line(NULL, new_str, 1, 0); + new_str = copy(".param vt = '(temper + 273.15) * 8.6173303e-5'"); + nextcard = insert_new_line(newcard, new_str, 2, 0); + new_str = copy(".param gmin = 1e-12"); + nextcard = insert_new_line(nextcard, new_str, 3, 0); + /* add funcs limit, pwr, pwrs, stp, if, int */ + /* LIMIT( Output Expression, Limit1, Limit2) + Output will stay between the two limits given. */ + new_str = copy(".func limit(x, a, b) { ternary_fcn(a > b, max(min(x, a), b), max(min(x, b), a)) }"); + nextcard = insert_new_line(nextcard, new_str, 4, 0); + new_str = copy(".func pwr(x, a) { pow(x, a) }"); + nextcard = insert_new_line(nextcard, new_str, 5, 0); + new_str = copy(".func pwrs(x, a) { sgn(x) * pow(x, a) }"); + nextcard = insert_new_line(nextcard, new_str, 6, 0); + new_str = copy(".func stp(x) { u(x) }"); + nextcard = insert_new_line(nextcard, new_str, 7, 0); + new_str = copy(".func if(a, b, c) {ternary_fcn( a , b , c )}"); + nextcard = insert_new_line(nextcard, new_str, 8, 0); + new_str = copy(".func int(x) { sign(x)*floor(abs(x)) }"); + nextcard = insert_new_line(nextcard, new_str, 9, 0); + nextcard->nextcard = oldcard; + +#ifdef INTEGRATE_UDEVICES + { + struct card *ucard; +#ifdef TRACE + list_the_cards(newcard, "Before udevices"); +#endif + ucard = u_instances(newcard); +#ifdef TRACE + list_the_cards(newcard, "After udevices"); +#endif + } +#endif + + + /* add predefined parameters TEMP, VT after each subckt call */ + /* FIXME: This should not be necessary if we had a better sense of + hierarchy during the evaluation of TEMPER */ + for (card = newcard; card; card = card->nextcard) { + char *cut_line = card->line; + if (ciprefix(".subckt", cut_line)) { + new_str = copy(".param temp = 'temper'"); + nextcard = insert_new_line(card, new_str, 0, 0); + new_str = copy(".param vt = '(temper + 273.15) * 8.6173303e-5'"); + nextcard = insert_new_line(nextcard, new_str, 1, 0); + /* params: replace comma separator by space. + Do nothing if you are inside of { }. */ + char* parastr = strstr(cut_line, "params:"); + int brace = 0; + if (parastr) { + parastr += 8; + while (*parastr) { + if (*parastr == '{') + brace++; + else if (*parastr == '}') + brace--; + if (brace == 0 && *parastr == ',') + *parastr = ' '; + parastr++; + } + } + } + } + + /* .model xxx NMOS/PMOS level=6 --> level = 8, version=3.2.4 + .model xxx NMOS/PMOS level=7 --> level = 8, version=3.2.4 + .model xxx NMOS/PMOS level=5 --> level = 44 + .model xxx NMOS/PMOS level=8 --> level = 14, version=4.5.0 + .model xxx NPN/PNP level=2 --> level = 6 + .model xxx LPNP level=n --> level = 1 subs=-1 + Remove any Monte - Carlo variation parameters from .model cards.*/ + for (card = newcard; card; card = card->nextcard) { + char* cut_line = card->line; + if (ciprefix(".model", cut_line)) { + char* modname, *modtype, *curr_line; + int i; + char *cut_del = curr_line = cut_line = inp_remove_ws(copy(cut_line)); + cut_line = nexttok(cut_line); /* skip .model */ + modname = gettok(&cut_line); /* save model name */ + if (!modname) { + fprintf(stderr, "Error: No model name given for %s\n", curr_line); + controlled_exit(EXIT_BAD); + } + modtype = gettok_noparens(&cut_line); /* save model type */ + if (!modtype) { + fprintf(stderr, "Error: No model type given for %s\n", curr_line); + controlled_exit(EXIT_BAD); + } + if (cieq(modtype, "NMOS") || cieq(modtype, "PMOS")) { + char* lv = strstr(cut_line, "level="); + if (lv) { + int ll; + lv = lv + 6; + char* ntok = gettok(&lv); + ll = atoi(ntok); + switch (ll) { + case 5: + { + /* EKV 2.6 in the adms branch */ + char* newline = tprintf(".model %s %s level=44 %s", modname, modtype, lv); + tfree(card->line); + card->line = curr_line = newline; + } + break; + case 6: + case 7: + { + /* BSIM3 version 3.2.4 */ + char* newline = tprintf(".model %s %s level=8 version=3.2.4 %s", modname, modtype, lv); + tfree(card->line); + card->line = curr_line = newline; + } + break; + case 8: + { + /* BSIM4 version 4.5.0 */ + char* newline = tprintf(".model %s %s level=14 version=4.5.0 %s", modname, modtype, lv); + tfree(card->line); + card->line = curr_line = newline; + } + break; + default: + break; + } + tfree(ntok); + } + } + else if (cieq(modtype, "NPN") || cieq(modtype, "PNP")) { + char* lv = strstr(cut_line, "level="); + if (lv) { + int ll; + lv = lv + 6; + char* ntok = gettok(&lv); + ll = atoi(ntok); + switch (ll) { + case 2: + { + /* MEXTRAM 504.12.1 in the adms branch */ + char* newline = tprintf(".model %s %s level=6 %s", modname, modtype, lv); + tfree(card->line); + card->line = curr_line = newline; + } + break; + default: + break; + } + tfree(ntok); + } + } + else if (cieq(modtype, "LPNP")) { + /* lateral PNP enabled */ + char* newline = tprintf(".model %s PNP level=1 subs=-1 %s", modname, cut_line); + tfree(card->line); + card->line = curr_line = newline; + } + tfree(modname); + tfree(modtype); + + /* Remove any Monte-Carlo variation parameters. They qualify + * a previous parameter, so there must be at least 3 tokens. + * There are two keywords "dev" (different values for each device), + * and "lot" (all devices of this model share a value). + * The keyword may be optionally followed by '/' and + * a probability distribution name, then there must be '=' and + * a value, then an optional '%' indicating relative rather than + * absolute variation. Allow muliple lot and dev on a single .model line. + */ + bool remdevlot = FALSE; + cut_line = curr_line; + for (i = 0; i < 3; i++) + cut_line = nexttok(cut_line); + while (cut_line) { + if (!strncmp(cut_line, "dev=", 4) || + !strncmp(cut_line, "lot=", 4)) { + while (*cut_line && !isspace_c(*cut_line)) { + *cut_line++ = ' '; + } + remdevlot = TRUE; + cut_line = skip_ws(cut_line); + continue; + } + cut_line = nexttok(cut_line); + } + if (remdevlot) { + tfree(card->line); + card->line = curr_line; + } + else + tfree(cut_del); + } // if .model + } // for loop through all cards + + /* x ... params: p1=val1, p2=val2 replace comma separator by space. + Do nothing if you are inside of { }. */ + for (card = newcard; card; card = card->nextcard) { + char* cut_line = card->line; + if (ciprefix("x", cut_line)) { + char* parastr = strstr(cut_line, "params:"); + int brace = 0; + if (parastr) { + parastr += 8; + while (*parastr) { + if (*parastr == '{') + brace++; + else if (*parastr == '}') + brace--; + if (brace == 0 && *parastr == ',') + *parastr = ' '; + parastr++; + } + } + } + } + + /* in R instance, replace TC = xx1, xx2 by TC1=xx1 TC2=xx2 */ + for (card = newcard; card; card = card->nextcard) { + char *cut_line = card->line; + + /* exclude any command inside .control ... .endc */ + if (ciprefix(".control", cut_line)) { + skip_control++; + continue; + } + else if (ciprefix(".endc", cut_line)) { + skip_control--; + continue; + } + else if (skip_control > 0) { + continue; + } + + if (*cut_line == 'r' || *cut_line == 'l' || *cut_line == 'c') { + /* Skip name and two nodes */ + char *ntok = nexttok(cut_line); + ntok = nexttok(ntok); + ntok = nexttok(ntok); + if (!ntok || *ntok == '\0') { + fprintf(stderr, "Error: Missing token in line %d:\n%s\n", + card->linenum, cut_line); + fprintf(stderr, " Please correct the input file\n"); + if (ft_stricterror) + controlled_exit(1); + else + continue; + } + char *tctok = search_plain_identifier(ntok, "tc"); + if (tctok) { + char *tc1, *tc2; + char *tctok1 = strchr(tctok, '='); + if (tctok1) + /* skip '=' */ + tctok1 += 1; + else + /* no '=' found, skip 'tc' */ + tctok1 = tctok + 2; + /* tc1 may be an expression, enclosed in {} */ + if (*tctok1 == '{') { + tc1 = gettok_char(&tctok1, '}', TRUE, TRUE); + } + else { + tc1 = gettok_node(&tctok1); + } + /* skip spaces and commas */ + while (isspace_c(*tctok1) || (*tctok1 == ',')) + tctok1++; + /* tc2 may be an expression, enclosed in {} */ + if (*tctok1 == '{') { + tc2 = gettok_char(&tctok1, '}', TRUE, TRUE); + } + else { + tc2 = gettok_node(&tctok1); + } + tctok[-1] = '\0'; + char *newstring; + if (tc1 && tc2) + newstring = tprintf("%s tc1=%s tc2=%s", + cut_line, tc1, tc2); + else if (tc1) + newstring = tprintf("%s tc1=%s", cut_line, tc1); + else { + fprintf(stderr, + "Warning: tc without parameters removed in line " + "\n %s\n", + cut_line); + continue; + } + tfree(card->line); + card->line = newstring; + tfree(tc1); + tfree(tc2); + } + } + } + + /* replace & with && , | with || , *# with * # , and ~ with ! */ + for (card = newcard; card; card = card->nextcard) { + char *t; + char *cut_line = card->line; + + /* we don't have command lines in a PSPICE model */ + if (ciprefix("*#", cut_line)) { + char *tmpstr = tprintf("* #%s", cut_line + 2); + tfree(card->line); + card->line = tmpstr; + continue; + } + + if (*cut_line == '*') + continue; + + if (*cut_line == '\0') + continue; + + /* exclude any command inside .control ... .endc */ + if (ciprefix(".control", cut_line)) { + skip_control++; + continue; + } + else if (ciprefix(".endc", cut_line)) { + skip_control--; + continue; + } + else if (skip_control > 0) { + continue; + } + if ((t = strstr(card->line, "&")) != NULL) { + while (t && (t[1] != '&')) { + char *tt = NULL; + char *tn = copy(t + 1); /*skip |*/ + char *strbeg = copy_substring(card->line, t); + tfree(card->line); + card->line = tprintf("%s&&%s", strbeg, tn); + tfree(strbeg); + tfree(tn); + t = card->line; + while ((t = strstr(t, "&&")) != NULL) + tt = t = t + 2; + if (!tt) + break; + else + t = strstr(tt, "&"); + } + } + if ((t = strstr(card->line, "|")) != NULL) { + while (t && (t[1] != '|')) { + char *tt = NULL; + char *tn = copy(t + 1); /*skip |*/ + char *strbeg = copy_substring(card->line, t); + tfree(card->line); + card->line = tprintf("%s||%s", strbeg, tn); + tfree(strbeg); + tfree(tn); + t = card->line; + while ((t = strstr(t, "||")) != NULL) + tt = t = t + 2; + if (!tt) + break; + else + t = strstr(tt, "|"); + } + } + /* We may have '~' in path names or A devices */ + if (ciprefix(".inc", card->line) || ciprefix(".lib", card->line) || + ciprefix("A", card->line)) + continue; + + if ((t = strstr(card->line, "~")) != NULL) { + while (t) { + *t = '!'; + t = strstr(t, "~"); + } + } + } + + /* replace T_ABS by temp, T_REL_GLOBAL by dtemp, and T_MEASURED by TNOM + in .model cards. What about T_REL_LOCAL ? T_REL_LOCAL is used in + conjunction with AKO and is not yet implemented. */ + for (card = newcard; card; card = card->nextcard) { + char *cut_line = card->line; + if (ciprefix(".model", cut_line)) { + char *t_str; + if ((t_str = strstr(cut_line, "t_abs")) != NULL) + memcpy(t_str, " temp", 5); + else if ((t_str = strstr(cut_line, "t_rel_global")) != NULL) + memcpy(t_str, " dtemp", 12); + else if ((t_str = strstr(cut_line, "t_measured")) != NULL) + memcpy(t_str, " tnom", 10); + } + } + + /* get the area factor for diodes and bipolar devices + d1 n1 n2 dmod 7 --> d1 n1 n2 dmod area=7 + q2 n1 n2 n3 [n4] bjtmod 1.35 --> q2 n1 n2 n3 n4 bjtmod area=1.35 + q3 1 2 3 4 bjtmod 1.45 --> q2 1 2 3 4 bjtmod area=1.45 + */ + for (card = newcard; card; card = card->nextcard) { + char *cut_line = card->line; + if (*cut_line == '*') + continue; + // exclude any command inside .control ... .endc + if (ciprefix(".control", cut_line)) { + skip_control++; + continue; + } + else if (ciprefix(".endc", cut_line)) { + skip_control--; + continue; + } + else if (skip_control > 0) { + continue; + } + if (*cut_line == 'q') { + /* According to PSPICE Reference Guide the fourth (substrate) node + has to be put into [] if it is not just a number */ + cut_line = nexttok(cut_line); //.model + cut_line = nexttok(cut_line); // node1 + cut_line = nexttok(cut_line); // node2 + cut_line = nexttok(cut_line); // node3 + if (!cut_line || *cut_line == '\0') { + fprintf(stderr, "Line no. %d, %s, missing tokens\n", + card->linenum_orig, card->line); + if (ft_stricterror) + controlled_exit(1); + else + continue; + } + if (*cut_line == '[') { // node4 not a number + *cut_line = ' '; + cut_line = strchr(cut_line, ']'); + *cut_line = ' '; + cut_line = skip_ws(cut_line); + cut_line = nexttok(cut_line); // model name + } + else { // if an integer number, it is node4 + bool is_node4 = TRUE; + while (*cut_line && !isspace_c(*cut_line)) + if (!isdigit_c(*cut_line++)) + is_node4 = FALSE; // already model name + if (is_node4) { + cut_line = nexttok(cut_line); // model name + } + } + if (cut_line && *cut_line && + atof(cut_line) > 0.0) { // size of area is a real number + char *tmpstr1 = copy_substring(card->line, cut_line); + char *tmpstr2 = tprintf("%s area=%s", tmpstr1, cut_line); + tfree(tmpstr1); + tfree(card->line); + card->line = tmpstr2; + } + else if (cut_line && *cut_line && + *(skip_ws(cut_line)) == + '{') { // size of area is parametrized inside {} + char *tmpstr1 = copy_substring(card->line, cut_line); + char *tmpstr2 = gettok_char(&cut_line, '}', TRUE, TRUE); + char *tmpstr3 = + tprintf("%s area=%s %s", tmpstr1, tmpstr2, cut_line); + tfree(tmpstr1); + tfree(tmpstr2); + tfree(card->line); + card->line = tmpstr3; + } + } + else if (*cut_line == 'd') { + cut_line = nexttok(cut_line); //.model + cut_line = nexttok(cut_line); // node1 + cut_line = nexttok(cut_line); // node2 + if (!cut_line || *cut_line == '\0') { + fprintf(stderr, "Line no. %d, %s, missing tokens\n", + card->linenum_orig, card->line); + if (ft_stricterror) + controlled_exit(1); + else + continue; + } + cut_line = nexttok(cut_line); // model name + if (cut_line && *cut_line && + atof(cut_line) > 0.0) { // size of area + char *tmpstr1 = copy_substring(card->line, cut_line); + char *tmpstr2 = tprintf("%s area=%s", tmpstr1, cut_line); + tfree(tmpstr1); + tfree(card->line); + card->line = tmpstr2; + } + } + } + + /* if vswitch part s, replace + * S1 D S DG GND SWN + * .MODEL SWN VSWITCH ( VON = {0.55} VOFF = {0.49} + * RON={1/(2*M*(W/LE)*(KPN/2)*10)} ROFF={1G} ) + * by + * a1 %v(DG) %gd(D S) swa + * .MODEL SWA aswitch(cntl_off=0.49 cntl_on=0.55 r_off=1G + * r_on={1/(2*M*(W/LE)*(KPN/2)*10)} log=TRUE) + * + * if vswitch part s_st, don't replace instance, only model + * replace + * S1 D S DG GND S_ST + * .MODEL S_ST VSWITCH(VT = { 1.5 } VH = { 0.s } + RON = { 1 / (2 * M*(W / LE)*(KPN / 2) * 10) } ROFF = { 1G }) + * by the classical voltage controlled ngspice switch + * S1 D S DG GND S_ST + * .MODEL S_ST SW(VT = { 1.5 } VH = { 0.s } + RON = { 1 / (2 * M*(W / LE)*(KPN / 2) * 10) } ROFF = { 1G }) + * vswitch delay parameter td is not yet supported + + * simple hierachy, as nested subcircuits are not allowed in PSPICE */ + + /* first scan: find the vswitch models, transform them and put the S models + into a list */ + for (card = newcard; card; card = card->nextcard) { + char *str; + static struct card *subcktline = NULL; + static int nesting = 0; + char *cut_line = card->line; + if (ciprefix(".subckt", cut_line)) { + subcktline = card; + nesting++; + } + if (ciprefix(".ends", cut_line)) + nesting--; + + if (ciprefix(".model", card->line) && strstr(card->line, "vswitch")) { + char *modname; + + str = card->line = inp_remove_ws(card->line); + str = nexttok(str); /* throw away '.model' */ + INPgetNetTok(&str, &modname, 0); /* model name */ + if (!ciprefix("vswitch", str)) { + tfree(modname); + continue; + } + str = nexttok_noparens(str); /* throw away 'vswitch' */ + /* S_ST switch (parameters ron, roff, vt, vh) + * we have to find 0 to 4 parameters, identified by 'vh=' etc. + * Parameters not found have to be replaced by their default values. */ + if (strstr(str, "vt=") || strstr(str, "vh=")) { + char* newstr; + char* lstr = copy(str); + char* partstr = strstr(lstr, "ron="); + if (!partstr) { + newstr = tprintf("%s %s", "ron=1.0", lstr); //default value + tfree(lstr); + lstr = newstr; + } + partstr = strstr(lstr, "roff="); + if (!partstr) { + newstr = tprintf("%s %s", "roff=1.0e12", lstr); //default value + tfree(lstr); + lstr = newstr; + } + partstr = strstr(lstr, "vt="); + if (!partstr) { + newstr = tprintf("%s %s", "vt=0", lstr); //default value + tfree(lstr); + lstr = newstr; + } + partstr = strstr(lstr, "vh="); + if (!partstr) { + newstr = tprintf("%s %s", "vh=0", lstr); //default value + tfree(lstr); + lstr = newstr; + } + tfree(card->line); + if (lstr[strlen(lstr) - 1] == ')') + card->line = tprintf(".model %s sw ( %s", modname, lstr); + else + card->line = tprintf(".model %s sw %s", modname, lstr); + tfree(lstr); + tfree(modname); + } + /* S vswitch (parameters ron, roff, von, voff) */ + /* We have to find 0 to 4 parameters, identified by 'von=' etc. and + * replace them by the pswitch code model parameters + * replace VON by cntl_on, VOFF by cntl_off, RON by r_on, and ROFF by r_off. + * Parameters not found have to be replaced by their default values. */ + else if (strstr(str, "von=") || strstr(str, "voff=")) { + char* newstr, *begstr; + char* lstr = copy(str); + /* ron */ + char* partstr = strstr(lstr, "ron="); + if (!partstr) { + newstr = tprintf("%s %s", "r_on=1.0", lstr); //default value + } + else { + begstr = copy_substring(lstr, partstr); + newstr = tprintf("%s r_on%s", begstr, partstr + 3); + tfree(begstr); + } + tfree(lstr); + lstr = newstr; + /* roff */ + partstr = strstr(lstr, "roff="); + if (!partstr) { + newstr = tprintf("%s %s", "r_off=1.0e6", lstr); //default value + } + else { + begstr = copy_substring(lstr, partstr); + newstr = tprintf("%s r_off%s", begstr, partstr + 4); + tfree(begstr); + } + tfree(lstr); + lstr = newstr; + /* von */ + partstr = strstr(lstr, "von="); + if (!partstr) { + newstr = tprintf("%s %s", "cntl_on=1", lstr); //default value + tfree(lstr); + lstr = newstr; + } + else { + begstr = copy_substring(lstr, partstr); + newstr = tprintf("%s cntl_on%s", begstr, partstr + 3); + tfree(begstr); + } + tfree(lstr); + lstr = newstr; + /* voff */ + partstr = strstr(lstr, "voff="); + if (!partstr) { + newstr = tprintf("%s %s", "cntl_off=0", lstr); //default value + tfree(lstr); + lstr = newstr; + } + else { + begstr = copy_substring(lstr, partstr); + newstr = tprintf("%s cntl_off%s", begstr, partstr + 4); + tfree(begstr); + } + tfree(lstr); + lstr = newstr; + tfree(card->line); + if (lstr[strlen(lstr) - 1] == ')') + card->line = tprintf(".model a%s pswitch( log=TRUE %s", modname, lstr); + else + card->line = tprintf(".model a%s pswitch(%s log=TRUE)", modname, lstr); + tfree(lstr); + /* add to list, to change vswitch instance to code model line */ + if (nesting > 0) + modelsfound = insert_new_model( + modelsfound, modname, subcktline->line); + else + modelsfound = insert_new_model(modelsfound, modname, "top"); + tfree(modname); + } + else { + fprintf(stderr, "Error: Bad switch model in line %s\n", card->line); + } + } + } + + /* no need to continue if no vswitch is found */ + if (!modelsfound) + goto iswi; + + /* second scan: find the switch instances s calling a vswitch model and + * transform them */ + for (card = newcard; card; card = card->nextcard) { + static struct card *subcktline = NULL; + static int nesting = 0; + char *cut_line = card->line; + if (*cut_line == '*') + continue; + // exclude any command inside .control ... .endc + if (ciprefix(".control", cut_line)) { + skip_control++; + continue; + } + else if (ciprefix(".endc", cut_line)) { + skip_control--; + continue; + } + else if (skip_control > 0) { + continue; + } + if (ciprefix(".subckt", cut_line)) { + subcktline = card; + nesting++; + } + if (ciprefix(".ends", cut_line)) + nesting--; + + if (ciprefix("s", cut_line)) { + /* check for the model name */ + int i; + bool good = TRUE; + char *stoks[6]; + for (i = 0; i < 6; i++) { + stoks[i] = gettok_node(&cut_line); + if (!stoks[i]) { + fprintf(stderr, "Error: Bad syntax in line:\n %s\n", card->line); + good = FALSE; + break; + } + } + if (!good) { + for (i = 0; i < 6; i++) + tfree(stoks[i]); + continue; + } + /* rewrite s line and replace it if a model is found */ + if ((nesting > 0) && + find_a_model(modelsfound, stoks[5], subcktline->line)) { + tfree(card->line); + card->line = tprintf("a%s %%gd(%s %s) %%gd(%s %s) a%s", + stoks[0], stoks[3], stoks[4], stoks[1], stoks[2], + stoks[5]); + } + /* if model is not within same subcircuit, search at top level */ + else if (find_a_model(modelsfound, stoks[5], "top")) { + tfree(card->line); + card->line = tprintf("a%s %%gd(%s %s) %%gd(%s %s) a%s", + stoks[0], stoks[3], stoks[4], stoks[1], stoks[2], + stoks[5]); + } + for (i = 0; i < 6; i++) + tfree(stoks[i]); + } + } + del_models(modelsfound); + modelsfound = NULL; + +iswi:; + + /* if iswitch part s, replace + * W1 D S VC SWN + * .MODEL SWN ISWITCH ( ION = {0.55} IOFF = {0.49} + * RON={1/(2*M*(W/LE)*(KPN/2)*10)} ROFF={1G} ) + * by + * a1 %v(DG) %gd(D S) swa + * .MODEL SWA aswitch(cntl_off=0.49 cntl_on=0.55 r_off=1G + * r_on={1/(2*M*(W/LE)*(KPN/2)*10)} log=TRUE) + * + * if iswitch part s_st (short transition), don't replace instance, but only model + * replace + * W1 D S VC S_ST + * .MODEL S_ST ISWITCH(IT = { 1.5 } IH = { 0.2 } + RON = { 1 / (2 * M*(W / LE)*(KPN / 2) * 10) } ROFF = { 1G }) + * by the classical current controlled ngspice switch + * W1 D S DG GND S_ST + * .MODEL S_ST CSW(IT = { 1.5 } IH = { 0.2 } + RON = { 1 / (2 * M*(W / LE)*(KPN / 2) * 10) } ROFF = { 1G }) + * iswitch delay parameter td is not yet supported + + * simple hierachy, as nested subcircuits are not allowed in PSPICE */ + + /* first scan: find the iswitch models, transform them and put them into a + * list */ + for (card = newcard; card; card = card->nextcard) { + char* str; + static struct card* subcktline = NULL; + static int nesting = 0; + char* cut_line = card->line; + if (ciprefix(".subckt", cut_line)) { + subcktline = card; + nesting++; + } + if (ciprefix(".ends", cut_line)) + nesting--; + + if (ciprefix(".model", card->line) && strstr(card->line, "iswitch")) { + char* modname; + + card->line = str = inp_remove_ws(card->line); + str = nexttok(str); /* throw away '.model' */ + INPgetNetTok(&str, &modname, 0); /* model name */ + if (!ciprefix("iswitch", str)) { + tfree(modname); + continue; + } + str = nexttok_noparens(str); /* throw away 'iswitch' */ + /* S_ST switch (parameters ron, roff, it, ih) + * we have to find 0 to 4 parameters, identified by 'ih=' etc. + * Parameters not found have to be replaced by their default values. */ + if (strstr(str, "it=") || strstr(str, "ih=")) { + char* newstr; + char* lstr = copy(str); + char* partstr = strstr(lstr, "ron="); + if (!partstr) { + newstr = tprintf("%s %s", "ron=1.0", lstr); //default value + tfree(lstr); + lstr = newstr; + } + partstr = strstr(lstr, "roff="); + if (!partstr) { + newstr = tprintf("%s %s", "roff=1.0e12", lstr); //default value + tfree(lstr); + lstr = newstr; + } + partstr = strstr(lstr, "it="); + if (!partstr) { + newstr = tprintf("%s %s", "it=0", lstr); //default value + tfree(lstr); + lstr = newstr; + } + partstr = strstr(lstr, "ih="); + if (!partstr) { + newstr = tprintf("%s %s", "ih=0", lstr); //default value + tfree(lstr); + lstr = newstr; + } + tfree(card->line); + if (lstr[strlen(lstr) - 1] == ')') + card->line = tprintf(".model %s csw ( %s", modname, lstr); + else + card->line = tprintf(".model %s csw %s", modname, lstr); + tfree(lstr); + tfree(modname); + } + /* S vswitch (parameters ron, roff, ion, ioff) */ + /* We have to find 0 to 4 parameters, identified by 'ion=' etc. and + * replace them by the pswitch code model parameters + * replace VON by cntl_on, VOFF by cntl_off, RON by r_on, and ROFF by r_off. + * Parameters not found have to be replaced by their default values. */ + else if (strstr(str, "ion=") || strstr(str, "ioff=")) { + char* newstr, * begstr; + char* lstr = copy(str); + /* ron */ + char* partstr = strstr(lstr, "ron="); + if (!partstr) { + newstr = tprintf("%s %s", "r_on=1.0", lstr); //default value + } + else { + begstr = copy_substring(lstr, partstr); + newstr = tprintf("%s r_on%s", begstr, partstr + 3); + } + tfree(lstr); + lstr = newstr; + /* roff */ + partstr = strstr(lstr, "roff="); + if (!partstr) { + newstr = tprintf("%s %s", "r_off=1.0e6", lstr); //default value + } + else { + begstr = copy_substring(lstr, partstr); + newstr = tprintf("%s r_off%s", begstr, partstr + 4); + } + tfree(lstr); + lstr = newstr; + /* von */ + partstr = strstr(lstr, "ion="); + if (!partstr) { + newstr = tprintf("%s %s", "cntl_on=1", lstr); //default value + tfree(lstr); + lstr = newstr; + } + else { + begstr = copy_substring(lstr, partstr); + newstr = tprintf("%s cntl_on%s", begstr, partstr + 3); + } + tfree(lstr); + lstr = newstr; + /* voff */ + partstr = strstr(lstr, "ioff="); + if (!partstr) { + newstr = tprintf("%s %s", "cntl_off=0", lstr); //default value + tfree(lstr); + lstr = newstr; + } + else { + begstr = copy_substring(lstr, partstr); + newstr = tprintf("%s cntl_off%s", begstr, partstr + 4); + } + tfree(lstr); + lstr = newstr; + tfree(card->line); + if (lstr[strlen(lstr) - 1] == ')') + card->line = tprintf(".model a%s aswitch( log=TRUE limit=TRUE %s", modname, lstr); + else + card->line = tprintf(".model a%s aswitch(%s log=TRUE limit=TRUE)", modname, lstr); + tfree(lstr); + /* add to list, to change vswitch instance to code model line */ + if (nesting > 0) + modelsfound = insert_new_model( + modelsfound, modname, subcktline->line); + else + modelsfound = insert_new_model(modelsfound, modname, "top"); + tfree(modname); + } + else { + fprintf(stderr, "Error: Bad switch model in line %s\n", card->line); + } + } + } + +#if(0) + /* we have to find 4 parameters, identified by '=', separated by + * spaces */ + char* equalptr[4]; + equalptr[0] = strstr(str, "="); + if (!equalptr[0]) { + fprintf(stderr, + "Error: not enough parameters in iswitch model\n " + "%s\n", + card->line); + controlled_exit(1); + } + for (i = 1; i < 4; i++) { + equalptr[i] = strstr(equalptr[i - 1] + 1, "="); + if (!equalptr[i]) { + fprintf(stderr, + "Error: not enough parameters in iswitch model\n " + " %s\n", + card->line); + controlled_exit(1); + } + } + for (i = 0; i < 4; i++) { + equalptr[i] = skip_back_ws(equalptr[i], str); + while (*(equalptr[i]) != '(' && !isspace_c(*(equalptr[i])) && + *(equalptr[i]) != ',') + (equalptr[i])--; + (equalptr[i])++; + } + for (i = 0; i < 3; i++) + modpar[i] = copy_substring(equalptr[i], equalptr[i + 1] - 1); + if (strrchr(equalptr[3], ')')) + modpar[3] = copy_substring( + equalptr[3], strrchr(equalptr[3], ')')); + else + /* iswitch defined without parens */ + modpar[3] = copy(equalptr[3]); + + /* check if we have parameters IT and IH */ + for (i = 0; i < 4; i++) { + if (ciprefix("ih", modpar[i])) + have_ih = TRUE; + if (ciprefix("it", modpar[i])) + have_it = TRUE; + } + if (have_ih && have_it) { + /* replace iswitch by csw */ + char* vs = strstr(card->line, "iswitch"); + memmove(vs, " csw", 7); + } + else { + /* replace ION by cntl_on, IOFF by cntl_off, RON by r_on, and + * ROFF by r_off */ + tfree(card->line); + rep_spar(modpar); + card->line = tprintf( + /* FIXME: a new switch derived from pswitch with vnam input is due */ + ".model a%s aswitch(%s %s %s %s log=TRUE limit=TRUE)", modname, + modpar[0], modpar[1], modpar[2], modpar[3]); + } + for (i = 0; i < 4; i++) + tfree(modpar[i]); + if (nesting > 0) + modelsfound = insert_new_model( + modelsfound, modname, subcktline->line); + else + modelsfound = insert_new_model(modelsfound, modname, "top"); + tfree(modname); + } + } +#endif + /* no need to continue if no iswitch is found */ + if (!modelsfound) + return newcard; + + /* second scan: find the switch instances s calling an iswitch model and + * transform them */ + for (card = newcard; card; card = card->nextcard) { + static struct card* subcktline = NULL; + static int nesting = 0; + char* cut_line = card->line; + if (*cut_line == '*') + continue; + // exclude any command inside .control ... .endc + if (ciprefix(".control", cut_line)) { + skip_control++; + continue; + } + else if (ciprefix(".endc", cut_line)) { + skip_control--; + continue; + } + else if (skip_control > 0) { + continue; + } + if (ciprefix(".subckt", cut_line)) { + subcktline = card; + nesting++; + } + if (ciprefix(".ends", cut_line)) + nesting--; + + if (ciprefix("w", cut_line)) { + /* check for the model name */ + int i; + char* stoks[5]; + for (i = 0; i < 5; i++) + stoks[i] = gettok_node(&cut_line); + /* rewrite w line and replace it if a model is found */ + if ((nesting > 0) && + find_a_model(modelsfound, stoks[4], subcktline->line)) { + tfree(card->line); + card->line = tprintf("a%s %%vnam(%s) %%gd(%s %s) a%s", + stoks[0], stoks[3], stoks[1], stoks[2], + stoks[4]); + } + /* if model is not within same subcircuit, search at top level */ + else if (find_a_model(modelsfound, stoks[4], "top")) { + tfree(card->line); + card->line = tprintf("a%s %%vnam(%s) %%gd(%s %s) a%s", + stoks[0], stoks[3], stoks[1], stoks[2], + stoks[4]); + } + for (i = 0; i < 5; i++) + tfree(stoks[i]); + } + } + del_models(modelsfound); + + return newcard; +} + + + +/* do not modify oldcard address, insert everything after first line only */ +void pspice_compat_a(struct card *oldcard) +{ + oldcard->nextcard = pspice_compat(oldcard->nextcard); +} + + +/**** LTSPICE to ngspice ************** + * add functions uplim, dnlim + * Replace + * D1 A K SDMOD + * .MODEL SDMOD D (Roff=1000 Ron=0.7 Rrev=0.2 Vfwd=1 Vrev=10 Revepsilon=0.2 + * Epsilon=0.2 Ilimit=7 Revilimit=7) + * by + * ad1 a k asdmod + * .model asdmod sidiode(Roff=1000 Ron=0.7 Rrev=0.2 Vfwd=1 Vrev=10 + * Revepsilon=0.2 Epsilon=0.2 Ilimit=7 Revilimit=7) + * Remove '.backanno' + */ +struct card *ltspice_compat(struct card *oldcard) +{ + struct card *card, *newcard, *nextcard; + struct vsmodels *modelsfound = NULL; + int skip_control = 0; + + + /* remove double braces only if not yet done in pspice_compat() */ + if (!newcompat.ps) + rem_double_braces(oldcard); + + /* add funcs uplim, dnlim to beginning of deck */ + char *new_str = + copy(".func uplim(x, pos, z) { min(x, pos - z) + (1 - " + "(min(max(0, x - pos + z), 2 * z) / 2 / z - 1)**2)*z }"); + newcard = insert_new_line(NULL, new_str, 1, 0); + new_str = copy(".func dnlim(x, neg, z) { max(x, neg + z) - (1 - " + "(min(max(0, -x + neg + z), 2 * z) / 2 / z - 1)**2)*z }"); + nextcard = insert_new_line(newcard, new_str, 2, 0); + new_str = copy(".func uplim_tanh(x, pos, z) { min(x, pos - z) + " + "tanh(max(0, x - pos + z) / z)*z }"); + nextcard = insert_new_line(nextcard, new_str, 3, 0); + new_str = copy(".func dnlim_tanh(x, neg, z) { max(x, neg + z) - " + "tanh(max(0, neg + z - x) / z)*z }"); + nextcard = insert_new_line(nextcard, new_str, 4, 0); + nextcard->nextcard = oldcard; + + /* remove .backanno, replace 'noiseless' by 'moisy=0' */ + for (card = nextcard; card; card = card->nextcard) { + char* cut_line = card->line; + if (ciprefix(".backanno", cut_line)) { + *cut_line = '*'; + } + else if (*cut_line == 'r') { + char* noi = strstr(cut_line, "noiseless"); + /* only if 'noiseless' is an unconnected token */ + if (noi && isspace_c(noi[-1]) && (isspace_c(noi[9]) || !isprint_c(noi[9]))) { + memcpy(noi, "noisy=0 ", 9); + } + } + } + + /* replace + * D1 A K SDMOD + * .MODEL SDMOD D (Roff=1000 Ron=0.7 Rrev=0.2 Vfwd=1 Vrev=10 + * Revepsilon=0.2 Epsilon=0.2 Ilimit=7 Revilimit=7) + * by + * a1 a k SDMOD + * .model SDMOD sidiode(Roff=1000 Ron=0.7 Rrev=0.2 Vfwd=1 Vrev=10 + * Revepsilon=0.2 Epsilon=0.2 Ilimit=7 Revilimit=7) + * Do this if one of the parameters, which are uncommon to standard diode + * model, has been found. + + * simple hierachy, as nested subcircuits are not allowed in PSPICE */ + + /* first scan: find the d models, transform them and put them into a list + */ + for (card = nextcard; card; card = card->nextcard) { + char *str; + static struct card *subcktline = NULL; + static int nesting = 0; + char *cut_line = card->line; + if (*cut_line == '*' || *cut_line == '\0') + continue; + else if (ciprefix(".subckt", cut_line)) { + subcktline = card; + nesting++; + } + else if (ciprefix(".ends", cut_line)) + nesting--; + + else if (ciprefix(".model", card->line) && + search_plain_identifier(card->line, "d")) { + if (search_plain_identifier(card->line, "roff") || + search_plain_identifier(card->line, "ron") || + search_plain_identifier(card->line, "rrev") || + search_plain_identifier(card->line, "vfwd") || + search_plain_identifier(card->line, "vrev") || + search_plain_identifier(card->line, "revepsilon") || + search_plain_identifier(card->line, "epsilon") || + search_plain_identifier(card->line, "revilimit") || + search_plain_identifier(card->line, "ilimit")) { + char *modname; + + /* remove parameter 'noiseless' (the model is noiseless anyway) */ + char *nonoise = search_plain_identifier(card->line, "noiseless"); + if (nonoise) { + size_t iii; + for (iii = 0; iii < 9; iii++) + nonoise[iii] = ' '; + } + card->line = str = inp_remove_ws(card->line); + str = nexttok(str); /* throw away '.model' */ + INPgetNetTok(&str, &modname, 0); /* model name */ + if (!ciprefix("d", str)) { + tfree(modname); + continue; + } + /* skip d */ + str++; + /* we take all the existing parameters */ + char *newstr = copy(str); + tfree(card->line); + card->line = tprintf(".model a%s sidiode%s", modname, newstr); + if (nesting > 0) + modelsfound = insert_new_model( + modelsfound, modname, subcktline->line); + else + modelsfound = + insert_new_model(modelsfound, modname, "top"); + tfree(modname); + tfree(newstr); + } + } + else + continue; + } + + /* no need to continue if no d is found */ + if (!modelsfound) + return newcard; + + /* second scan: find the diode instances d calling a simple diode model + * and transform them */ + for (card = nextcard; card; card = card->nextcard) { + static struct card *subcktline = NULL; + static int nesting = 0; + char *cut_line = card->line; + if (*cut_line == '*') + continue; + if (*cut_line == '\0') + continue; + // exclude any command inside .control ... .endc + if (ciprefix(".control", cut_line)) { + skip_control++; + continue; + } + else if (ciprefix(".endc", cut_line)) { + skip_control--; + continue; + } + else if (skip_control > 0) { + continue; + } + if (ciprefix(".subckt", cut_line)) { + subcktline = card; + nesting++; + } + if (ciprefix(".ends", cut_line)) + nesting--; + + if (ciprefix("d", cut_line)) { + /* check for the model name */ + int i; + char *stoks[4]; + for (i = 0; i < 4; i++) { + stoks[i] = gettok_node(&cut_line); + if (stoks[i] == NULL) { + fprintf(stderr, "Error in line %d: buggy diode instance line\n %s\n", card->linenum_orig, card->line); + fprintf(stderr, "At least 'Dxx n1 n2 d' is required.\n"); + controlled_exit(EXIT_BAD); + } + } + /* rewrite d line and replace it if a model is found */ + if ((nesting > 0) && + find_a_model(modelsfound, stoks[3], subcktline->line)) { + tfree(card->line); + card->line = tprintf("a%s %s %s a%s", + stoks[0], stoks[1], stoks[2], stoks[3]); + } + /* if model is not within same subcircuit, search at top level */ + else if (find_a_model(modelsfound, stoks[3], "top")) { + tfree(card->line); + card->line = tprintf("a%s %s %s a%s", + stoks[0], stoks[1], stoks[2], stoks[3]); + } + for (i = 0; i < 4; i++) + tfree(stoks[i]); + } + } + del_models(modelsfound); + + return newcard; +} + +/* do not modify oldcard address, insert everything after first line only */ +void ltspice_compat_a(struct card *oldcard) +{ + oldcard->nextcard = ltspice_compat(oldcard->nextcard); +} diff --git a/src/frontend/inpcompat.h b/src/frontend/inpcompat.h new file mode 100644 index 000000000..d657a8b58 --- /dev/null +++ b/src/frontend/inpcompat.h @@ -0,0 +1,20 @@ +/********** +Copyright 2023 The ngspice team. All rights reserved. +License: Three-clause BCD +Author: 2023 Holger Vogt +**********/ + +/* + For dealing with compatibility transformations + + PSICE, LTSPICE and others +*/ + +extern void print_compat_mode(void); +extern void set_compat_mode(void); +extern void pspice_compat_a(struct card* oldcard); +extern void ltspice_compat_a(struct card* oldcard); +extern struct card* pspice_compat(struct card* newcard); +extern struct card* ltspice_compat(struct card* oldcard); + + diff --git a/src/spicelib/devices/vbic/vbic.c b/src/spicelib/devices/vbic/vbic.c index 2ac939058..28e5ace6e 100644 --- a/src/spicelib/devices/vbic/vbic.c +++ b/src/spicelib/devices/vbic/vbic.c @@ -66,6 +66,7 @@ IFparm VBICpTable[] = { /* parameters */ IFparm VBICmPTable[] = { /* model parameters */ OP("type", VBIC_MOD_TYPE, IF_STRING, "NPN or PNP"), + IOP("selft", VBIC_MOD_SELFT, IF_INTEGER, "0: self-heating off, 1: self-heating on"), IOPU("npn", VBIC_MOD_NPN, IF_FLAG, "NPN type device"), IOPU("pnp", VBIC_MOD_PNP, IF_FLAG, "PNP type device"), IOP("tnom", VBIC_MOD_TNOM, IF_REAL, "Parameter measurement temperature"), @@ -73,6 +74,7 @@ IFparm VBICmPTable[] = { /* model parameters */ IOP("rcx", VBIC_MOD_RCX, IF_REAL, "Extrinsic coll resistance"), IOP("rci", VBIC_MOD_RCI, IF_REAL, "Intrinsic coll resistance"), IOP("vo", VBIC_MOD_VO, IF_REAL, "Epi drift saturation voltage"), + IOPR("v0", VBIC_MOD_VO, IF_REAL, "Epi drift saturation voltage"), IOP("gamm", VBIC_MOD_GAMM, IF_REAL, "Epi doping parameter"), IOP("hrcf", VBIC_MOD_HRCF, IF_REAL, "High current RC factor"), IOP("rbx", VBIC_MOD_RBX, IF_REAL, "Extrinsic base resistance"), @@ -85,13 +87,16 @@ IFparm VBICmPTable[] = { /* model parameters */ IOP("nr", VBIC_MOD_NR, IF_REAL, "Reverse emission coefficient"), IOP("fc", VBIC_MOD_FC, IF_REAL, "Fwd bias depletion capacitance limit"), IOP("cbeo", VBIC_MOD_CBEO, IF_REAL, "Extrinsic B-E overlap capacitance"), + IOPR("cbe0", VBIC_MOD_CBEO, IF_REAL, "Extrinsic B-E overlap capacitance"), IOP("cje", VBIC_MOD_CJE, IF_REAL, "Zero bias B-E depletion capacitance"), IOP("pe", VBIC_MOD_PE, IF_REAL, "B-E built in potential"), IOP("me", VBIC_MOD_ME, IF_REAL, "B-E junction grading coefficient"), IOP("aje", VBIC_MOD_AJE, IF_REAL, "B-E capacitance smoothing factor"), IOP("cbco", VBIC_MOD_CBCO, IF_REAL, "Extrinsic B-C overlap capacitance"), + IOPR("cbc0", VBIC_MOD_CBCO, IF_REAL, "Extrinsic B-C overlap capacitance"), IOP("cjc", VBIC_MOD_CJC, IF_REAL, "Zero bias B-C depletion capacitance"), IOP("qco", VBIC_MOD_QCO, IF_REAL, "Epi charge parameter"), + IOPR("qc0", VBIC_MOD_QCO, IF_REAL, "Epi charge parameter"), IOP("cjep", VBIC_MOD_CJEP, IF_REAL, "B-C extrinsic zero bias capacitance"), IOP("pc", VBIC_MOD_PC, IF_REAL, "B-C built in potential"), IOP("mc", VBIC_MOD_MC, IF_REAL, "B-C junction grading coefficient"), @@ -128,20 +133,19 @@ IFparm VBICmPTable[] = { /* model parameters */ IOP("tf", VBIC_MOD_TF, IF_REAL, "Ideal forward transit time"), IOP("qtf", VBIC_MOD_QTF, IF_REAL, "Variation of TF with base-width modulation"), IOP("xtf", VBIC_MOD_XTF, IF_REAL, "Coefficient for bias dependence of TF"), - IOP("vtf", VBIC_MOD_VTF, IF_REAL, "Voltage giving VBC dependence of TF"), - IOP("itf", VBIC_MOD_ITF, IF_REAL, "High current dependence of TF"), - IOP("tr", VBIC_MOD_TR, IF_REAL, "Ideal reverse transit time"), - IOP("td", VBIC_MOD_TD, IF_REAL, "Forward excess-phase delay time"), + IOP("vtf", VBIC_MOD_VTF, IF_REAL, "Voltage giving VBC dependence of TF"), + IOP("itf", VBIC_MOD_ITF, IF_REAL, "High current dependence of TF"), + IOP("tr", VBIC_MOD_TR, IF_REAL, "Ideal reverse transit time"), + IOP("td", VBIC_MOD_TD, IF_REAL, "Forward excess-phase delay time"), IOP("kfn", VBIC_MOD_KFN, IF_REAL, "B-E Flicker Noise Coefficient"), IOP("afn", VBIC_MOD_AFN, IF_REAL, "B-E Flicker Noise Exponent"), IOP("bfn", VBIC_MOD_BFN, IF_REAL, "B-E Flicker Noise 1/f dependence"), IOP("xre", VBIC_MOD_XRE, IF_REAL, "Temperature exponent of RE"), - IOP("xrb", VBIC_MOD_XRB, IF_REAL, "Temperature exponent of RB"), IOP("xrbi", VBIC_MOD_XRBI, IF_REAL, "Temperature exponent of RBI"), - IOP("xrc", VBIC_MOD_XRC, IF_REAL, "Temperature exponent of RC"), IOP("xrci", VBIC_MOD_XRCI, IF_REAL, "Temperature exponent of RCI"), IOP("xrs", VBIC_MOD_XRS, IF_REAL, "Temperature exponent of RS"), IOP("xvo", VBIC_MOD_XVO, IF_REAL, "Temperature exponent of VO"), + IOPR("xv0", VBIC_MOD_XVO, IF_REAL, "Temperature exponent of VO"), IOP("ea", VBIC_MOD_EA, IF_REAL, "Activation energy for IS"), IOP("eaie", VBIC_MOD_EAIE, IF_REAL, "Activation energy for IBEI"), IOP("eaic", VBIC_MOD_EAIC, IF_REAL, "Activation energy for IBCI/IBEIP"), @@ -163,7 +167,9 @@ IFparm VBICmPTable[] = { /* model parameters */ IOP("nkf", VBIC_MOD_NKF, IF_REAL, "High current beta rolloff"), IOP("xikf", VBIC_MOD_XIKF, IF_REAL, "Temperature exponent of IKF"), IOP("xrcx", VBIC_MOD_XRCX, IF_REAL, "Temperature exponent of RCX"), + IOPR("xrc", VBIC_MOD_XRCX, IF_REAL, "Temperature exponent of RCX"), IOP("xrbx", VBIC_MOD_XRBX, IF_REAL, "Temperature exponent of RBX"), + IOPR("xrb", VBIC_MOD_XRBX, IF_REAL, "Temperature exponent of RBX"), IOP("xrbp", VBIC_MOD_XRBP, IF_REAL, "Temperature exponent of RBP"), IOP("isrr", VBIC_MOD_ISRR, IF_REAL, "Separate IS for fwd and rev"), IOP("xisr", VBIC_MOD_XISR, IF_REAL, "Temperature exponent of ISR"), @@ -189,8 +195,7 @@ IFparm VBICmPTable[] = { /* model parameters */ IOPR("bvsub", VBIC_MOD_VSUB_MAX, IF_REAL, "maximum voltage C-substrate branch"), IOP("vbefwd", VBIC_MOD_VBEFWD_MAX, IF_REAL, "maximum forward voltage B-E junction"), IOP("vbcfwd", VBIC_MOD_VBCFWD_MAX, IF_REAL, "maximum forward voltage B-C junction"), - IOP("vsubfwd", VBIC_MOD_VSUBFWD_MAX, IF_REAL, "maximum forward voltage C-substrate junction"), - IOP("selft", VBIC_MOD_SELFT, IF_INTEGER, "0: self-heating off, 1: self-heating on") + IOP("vsubfwd", VBIC_MOD_VSUBFWD_MAX, IF_REAL, "maximum forward voltage C-substrate junction") }; char *VBICnames[] = { @@ -202,8 +207,8 @@ char *VBICnames[] = { }; -int VBICnSize = NUMELEMS(VBICnames); -int VBICpTSize = NUMELEMS(VBICpTable); -int VBICmPTSize = NUMELEMS(VBICmPTable); -int VBICiSize = sizeof(VBICinstance); -int VBICmSize = sizeof(VBICmodel); +int VBICnSize = NUMELEMS(VBICnames); +int VBICpTSize = NUMELEMS(VBICpTable); +int VBICmPTSize = NUMELEMS(VBICmPTable); +int VBICiSize = sizeof(VBICinstance); +int VBICmSize = sizeof(VBICmodel); diff --git a/src/spicelib/devices/vbic/vbicdefs.h b/src/spicelib/devices/vbic/vbicdefs.h index fd28eebf0..632de3f84 100644 --- a/src/spicelib/devices/vbic/vbicdefs.h +++ b/src/spicelib/devices/vbic/vbicdefs.h @@ -369,7 +369,7 @@ typedef struct sVBICmodel { /* model structure for a vbic */ #define VBICmodName gen.GENmodName int VBICtype; - + int VBICselft; double VBICtnom; double VBICextCollResist; double VBICintCollResist; @@ -437,9 +437,7 @@ typedef struct sVBICmodel { /* model structure for a vbic */ double VBICfNexpA; double VBICfNexpB; double VBICtempExpRE; - double VBICtempExpRB; double VBICtempExpRBI; - double VBICtempExpRC; double VBICtempExpRCI; double VBICtempExpRS; double VBICtempExpVO; @@ -457,7 +455,6 @@ typedef struct sVBICmodel { /* model structure for a vbic */ double VBICtempExpAVC; double VBICthermalResist; double VBICthermalCapacitance; - int VBICselft; double VBICpunchThroughVoltageBC; double VBICdeplCapCoeff1; double VBICfixedCapacitanceCS; @@ -490,6 +487,7 @@ typedef struct sVBICmodel { /* model structure for a vbic */ double VBICvbefwdMax; /* maximum forward voltage over C-E branch */ double VBICvsubfwdMax; /* maximum forward voltage over C-substrate branch */ + unsigned VBICselftGiven : 1; unsigned VBICtnomGiven : 1; unsigned VBICextCollResistGiven : 1; unsigned VBICintCollResistGiven : 1; @@ -576,7 +574,6 @@ typedef struct sVBICmodel { /* model structure for a vbic */ unsigned VBICtempExpNFGiven : 1; unsigned VBICtempExpAVCGiven : 1; unsigned VBICthermalResistGiven : 1; - unsigned VBICselftGiven : 1; unsigned VBICthermalCapacitanceGiven : 1; unsigned VBICpunchThroughVoltageBCGiven : 1; unsigned VBICdeplCapCoeff1Given : 1; @@ -751,7 +748,7 @@ enum { VBIC_MOD_SELFT, }; -/* device questions */ +/* device questions */ enum { VBIC_QUEST_FT = 221, VBIC_QUEST_COLLNODE, diff --git a/src/spicelib/devices/vbic/vbicload.c b/src/spicelib/devices/vbic/vbicload.c index 5ebf217e6..af723c4b8 100644 --- a/src/spicelib/devices/vbic/vbicload.c +++ b/src/spicelib/devices/vbic/vbicload.c @@ -18,30 +18,42 @@ Spice3 Implementation: 2003 Dietmar Warning DAnalyse GmbH #include "ngspice/sperror.h" #include "ngspice/devdefs.h" -int vbic_4T_et_cf_fj(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 *,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 *,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 *, +int vbic_4T_et_cf_fj( + 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 *,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 *,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 *,double *); +int vbic_4T_it_cf_fj( + 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 *,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 *); int VBICload(GENmodel *inModel, CKTcircuit *ckt) - /* actually load the current resistance value into the - * sparse matrix previously provided + /* actually load the current resistance value into the + * sparse matrix previously provided */ { VBICmodel *model = (VBICmodel*)inModel; @@ -117,12 +129,14 @@ VBICload(GENmodel *inModel, CKTcircuit *ckt) /* * model parameters */ - p[0] = model->VBICtnom; + memcpy (&p, &model->VBICtnom, 108*8); + + p[0] = here->VBICtemp - CONSTCtoK + p[105]; + /* temperature dependent parameter are already calculated */ p[1] = here->VBICtextCollResist; p[2] = here->VBICtintCollResist; p[3] = here->VBICtepiSatVoltage; p[4] = here->VBICtepiDoping; - p[5] = model->VBIChighCurFac; p[6] = here->VBICtextBaseResist; p[7] = here->VBICtintBaseResist; p[8] = here->VBICtemitterResist; @@ -131,100 +145,27 @@ VBICload(GENmodel *inModel, CKTcircuit *ckt) p[11] = here->VBICtsatCur; p[12] = here->VBICtemissionCoeffF; p[13] = here->VBICtemissionCoeffR; - p[14] = model->VBICdeplCapLimitF; - p[15] = model->VBICextOverlapCapBE; p[16] = here->VBICtdepletionCapBE; p[17] = here->VBICtpotentialBE; - p[18] = model->VBICjunctionExpBE; - p[19] = model->VBICsmoothCapBE; - p[20] = model->VBICextOverlapCapBC; p[21] = here->VBICtdepletionCapBC; - p[22] = model->VBICepiCharge; p[23] = here->VBICtextCapBC; p[24] = here->VBICtpotentialBC; - p[25] = model->VBICjunctionExpBC; - p[26] = model->VBICsmoothCapBC; p[27] = here->VBICtextCapSC; p[28] = here->VBICtpotentialSC; - p[29] = model->VBICjunctionExpSC; - p[30] = model->VBICsmoothCapSC; p[31] = here->VBICtidealSatCurBE; - p[32] = model->VBICportionIBEI; - p[33] = model->VBICidealEmissCoeffBE; p[34] = here->VBICtnidealSatCurBE; - p[35] = model->VBICnidealEmissCoeffBE; p[36] = here->VBICtidealSatCurBC; - p[37] = model->VBICidealEmissCoeffBC; p[38] = here->VBICtnidealSatCurBC; - p[39] = model->VBICnidealEmissCoeffBC; - p[40] = model->VBICavalanchePar1BC; p[41] = here->VBICtavalanchePar2BC; p[42] = here->VBICtparasitSatCur; - p[43] = model->VBICportionICCP; - p[44] = model->VBICparasitFwdEmissCoeff; p[45] = here->VBICtidealParasitSatCurBE; p[46] = here->VBICtnidealParasitSatCurBE; p[47] = here->VBICtidealParasitSatCurBC; - p[48] = model->VBICidealParasitEmissCoeffBC; p[49] = here->VBICtnidealParasitSatCurBC; - p[50] = model->VBICnidealParasitEmissCoeffBC; - p[51] = model->VBICearlyVoltF; - p[52] = model->VBICearlyVoltR; p[53] = here->VBICtrollOffF; - p[54] = model->VBICrollOffR; - p[55] = model->VBICparRollOff; - p[56] = model->VBICtransitTimeF; - p[57] = model->VBICvarTransitTimeF; - p[58] = model->VBICtransitTimeBiasCoeffF; - p[59] = model->VBICtransitTimeFVBC; - p[60] = model->VBICtransitTimeHighCurrentF; - p[61] = model->VBICtransitTimeR; - p[62] = model->VBICdelayTimeF; - p[63] = model->VBICfNcoef; - p[64] = model->VBICfNexpA; - p[65] = model->VBICfNexpB; - p[66] = model->VBICtempExpRE; - p[67] = model->VBICtempExpRBI; - p[68] = model->VBICtempExpRCI; - p[69] = model->VBICtempExpRS; - p[70] = model->VBICtempExpVO; - p[71] = model->VBICactivEnergyEA; - p[72] = model->VBICactivEnergyEAIE; - p[73] = model->VBICactivEnergyEAIC; - p[74] = model->VBICactivEnergyEAIS; - p[75] = model->VBICactivEnergyEANE; - p[76] = model->VBICactivEnergyEANC; - p[77] = model->VBICactivEnergyEANS; - p[78] = model->VBICtempExpIS; - p[79] = model->VBICtempExpII; - p[80] = model->VBICtempExpIN; - p[81] = model->VBICtempExpNF; - p[82] = model->VBICtempExpAVC; - p[83] = model->VBICthermalResist; - p[84] = model->VBICthermalCapacitance; - p[85] = model->VBICpunchThroughVoltageBC; - p[86] = model->VBICdeplCapCoeff1; - p[87] = model->VBICfixedCapacitanceCS; - p[88] = model->VBICsgpQBselector; - p[89] = model->VBIChighCurrentBetaRolloff; - p[90] = model->VBICtempExpIKF; - p[91] = model->VBICtempExpRCX; - p[92] = model->VBICtempExpRBX; - p[93] = model->VBICtempExpRBP; p[94] = here->VBICtsepISRR; - p[95] = model->VBICtempExpXISR; - p[96] = model->VBICdear; - p[97] = model->VBICeap; p[98] = here->VBICtvbbe; p[99] = here->VBICtnbbe; - p[100] = model->VBICibbe; - p[101] = model->VBICtvbbe1; - p[102] = model->VBICtvbbe2; - p[103] = model->VBICtnbbe; - p[104] = model->VBICebbe; - p[105] = model->VBIClocTempDiff; - p[106] = model->VBICrevVersion; - p[107] = model->VBICrefVersion; SCALE = here->VBICarea * here->VBICm; @@ -292,7 +233,7 @@ VBICload(GENmodel *inModel, CKTcircuit *ckt) *(ckt->CKTrhsOld+here->VBICsubsSINode)); if (here->VBIC_selfheat) Vrth = *(ckt->CKTstate1 + here->VBICvrth); - } else if((ckt->CKTmode & MODEINITJCT) && + } else if((ckt->CKTmode & MODEINITJCT) && (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)){ Vbe=model->VBICtype*here->VBICicVBE; Vbei=Vbex=Vbe; @@ -348,104 +289,104 @@ VBICload(GENmodel *inModel, CKTcircuit *ckt) *(ckt->CKTstate0 + here->VBICvrth) = *(ckt->CKTstate1 + here->VBICvrth); } - *(ckt->CKTstate0 + here->VBICvbei) = + *(ckt->CKTstate0 + here->VBICvbei) = *(ckt->CKTstate1 + here->VBICvbei); - *(ckt->CKTstate0 + here->VBICvbex) = + *(ckt->CKTstate0 + here->VBICvbex) = *(ckt->CKTstate1 + here->VBICvbex); - *(ckt->CKTstate0 + here->VBICvbci) = + *(ckt->CKTstate0 + here->VBICvbci) = *(ckt->CKTstate1 + here->VBICvbci); - *(ckt->CKTstate0 + here->VBICvbcx) = + *(ckt->CKTstate0 + here->VBICvbcx) = *(ckt->CKTstate1 + here->VBICvbcx); - *(ckt->CKTstate0 + here->VBICvbep) = + *(ckt->CKTstate0 + here->VBICvbep) = *(ckt->CKTstate1 + here->VBICvbep); - *(ckt->CKTstate0 + here->VBICvrci) = + *(ckt->CKTstate0 + here->VBICvrci) = *(ckt->CKTstate1 + here->VBICvrci); - *(ckt->CKTstate0 + here->VBICvrbi) = + *(ckt->CKTstate0 + here->VBICvrbi) = *(ckt->CKTstate1 + here->VBICvrbi); - *(ckt->CKTstate0 + here->VBICvrbp) = + *(ckt->CKTstate0 + here->VBICvrbp) = *(ckt->CKTstate1 + here->VBICvrbp); - *(ckt->CKTstate0 + here->VBICvbcp) = + *(ckt->CKTstate0 + here->VBICvbcp) = *(ckt->CKTstate1 + here->VBICvbcp); - *(ckt->CKTstate0 + here->VBICibe) = + *(ckt->CKTstate0 + here->VBICibe) = *(ckt->CKTstate1 + here->VBICibe); - *(ckt->CKTstate0 + here->VBICibe_Vbei) = + *(ckt->CKTstate0 + here->VBICibe_Vbei) = *(ckt->CKTstate1 + here->VBICibe_Vbei); - *(ckt->CKTstate0 + here->VBICibex) = + *(ckt->CKTstate0 + here->VBICibex) = *(ckt->CKTstate1 + here->VBICibex); - *(ckt->CKTstate0 + here->VBICibex_Vbex) = + *(ckt->CKTstate0 + here->VBICibex_Vbex) = *(ckt->CKTstate1 + here->VBICibex_Vbex); - *(ckt->CKTstate0 + here->VBICitzf) = + *(ckt->CKTstate0 + here->VBICitzf) = *(ckt->CKTstate1 + here->VBICitzf); - *(ckt->CKTstate0 + here->VBICitzf_Vbei) = + *(ckt->CKTstate0 + here->VBICitzf_Vbei) = *(ckt->CKTstate1 + here->VBICitzf_Vbei); - *(ckt->CKTstate0 + here->VBICitzf_Vbci) = + *(ckt->CKTstate0 + here->VBICitzf_Vbci) = *(ckt->CKTstate1 + here->VBICitzf_Vbci); - *(ckt->CKTstate0 + here->VBICitzr) = + *(ckt->CKTstate0 + here->VBICitzr) = *(ckt->CKTstate1 + here->VBICitzr); - *(ckt->CKTstate0 + here->VBICitzr_Vbei) = + *(ckt->CKTstate0 + here->VBICitzr_Vbei) = *(ckt->CKTstate1 + here->VBICitzf_Vbei); - *(ckt->CKTstate0 + here->VBICitzr_Vbci) = + *(ckt->CKTstate0 + here->VBICitzr_Vbci) = *(ckt->CKTstate1 + here->VBICitzr_Vbci); - *(ckt->CKTstate0 + here->VBICibc) = + *(ckt->CKTstate0 + here->VBICibc) = *(ckt->CKTstate1 + here->VBICibc); - *(ckt->CKTstate0 + here->VBICibc_Vbci) = + *(ckt->CKTstate0 + here->VBICibc_Vbci) = *(ckt->CKTstate1 + here->VBICibc_Vbci); - *(ckt->CKTstate0 + here->VBICibc_Vbei) = + *(ckt->CKTstate0 + here->VBICibc_Vbei) = *(ckt->CKTstate1 + here->VBICibc_Vbei); - *(ckt->CKTstate0 + here->VBICibep) = + *(ckt->CKTstate0 + here->VBICibep) = *(ckt->CKTstate1 + here->VBICibep); - *(ckt->CKTstate0 + here->VBICibep_Vbep) = + *(ckt->CKTstate0 + here->VBICibep_Vbep) = *(ckt->CKTstate1 + here->VBICibep_Vbep); - *(ckt->CKTstate0 + here->VBICirci) = + *(ckt->CKTstate0 + here->VBICirci) = *(ckt->CKTstate1 + here->VBICirci); - *(ckt->CKTstate0 + here->VBICirci_Vrci) = + *(ckt->CKTstate0 + here->VBICirci_Vrci) = *(ckt->CKTstate1 + here->VBICirci_Vrci); - *(ckt->CKTstate0 + here->VBICirci_Vbci) = + *(ckt->CKTstate0 + here->VBICirci_Vbci) = *(ckt->CKTstate1 + here->VBICirci_Vbci); - *(ckt->CKTstate0 + here->VBICirci_Vbcx) = + *(ckt->CKTstate0 + here->VBICirci_Vbcx) = *(ckt->CKTstate1 + here->VBICirci_Vbcx); - *(ckt->CKTstate0 + here->VBICirbi) = + *(ckt->CKTstate0 + here->VBICirbi) = *(ckt->CKTstate1 + here->VBICirbi); - *(ckt->CKTstate0 + here->VBICirbi_Vrbi) = + *(ckt->CKTstate0 + here->VBICirbi_Vrbi) = *(ckt->CKTstate1 + here->VBICirbi_Vrbi); - *(ckt->CKTstate0 + here->VBICirbi_Vbei) = + *(ckt->CKTstate0 + here->VBICirbi_Vbei) = *(ckt->CKTstate1 + here->VBICirbi_Vbei); - *(ckt->CKTstate0 + here->VBICirbi_Vbci) = + *(ckt->CKTstate0 + here->VBICirbi_Vbci) = *(ckt->CKTstate1 + here->VBICirbi_Vbci); - *(ckt->CKTstate0 + here->VBICirbp) = + *(ckt->CKTstate0 + here->VBICirbp) = *(ckt->CKTstate1 + here->VBICirbp); - *(ckt->CKTstate0 + here->VBICirbp_Vrbp) = + *(ckt->CKTstate0 + here->VBICirbp_Vrbp) = *(ckt->CKTstate1 + here->VBICirbp_Vrbp); - *(ckt->CKTstate0 + here->VBICirbp_Vbep) = + *(ckt->CKTstate0 + here->VBICirbp_Vbep) = *(ckt->CKTstate1 + here->VBICirbp_Vbep); - *(ckt->CKTstate0 + here->VBICirbp_Vbci) = + *(ckt->CKTstate0 + here->VBICirbp_Vbci) = *(ckt->CKTstate1 + here->VBICirbp_Vbci); - *(ckt->CKTstate0 + here->VBICibcp) = + *(ckt->CKTstate0 + here->VBICibcp) = *(ckt->CKTstate1 + here->VBICibcp); - *(ckt->CKTstate0 + here->VBICibcp_Vbcp) = + *(ckt->CKTstate0 + here->VBICibcp_Vbcp) = *(ckt->CKTstate1 + here->VBICibcp_Vbcp); - *(ckt->CKTstate0 + here->VBICiccp) = + *(ckt->CKTstate0 + here->VBICiccp) = *(ckt->CKTstate1 + here->VBICiccp); - *(ckt->CKTstate0 + here->VBICiccp_Vbep) = + *(ckt->CKTstate0 + here->VBICiccp_Vbep) = *(ckt->CKTstate1 + here->VBICiccp_Vbep); - *(ckt->CKTstate0 + here->VBICiccp_Vbci) = + *(ckt->CKTstate0 + here->VBICiccp_Vbci) = *(ckt->CKTstate1 + here->VBICiccp_Vbci); - *(ckt->CKTstate0 + here->VBICiccp_Vbcp) = + *(ckt->CKTstate0 + here->VBICiccp_Vbcp) = *(ckt->CKTstate1 + here->VBICiccp_Vbcp); - *(ckt->CKTstate0 + here->VBICgqbeo) = + *(ckt->CKTstate0 + here->VBICgqbeo) = *(ckt->CKTstate1 + here->VBICgqbeo); - *(ckt->CKTstate0 + here->VBICgqbco) = + *(ckt->CKTstate0 + here->VBICgqbco) = *(ckt->CKTstate1 + here->VBICgqbco); - *(ckt->CKTstate0 + here->VBICircx_Vrcx) = + *(ckt->CKTstate0 + here->VBICircx_Vrcx) = *(ckt->CKTstate1 + here->VBICircx_Vrcx); - *(ckt->CKTstate0 + here->VBICirbx_Vrbx) = + *(ckt->CKTstate0 + here->VBICirbx_Vrbx) = *(ckt->CKTstate1 + here->VBICirbx_Vrbx); - *(ckt->CKTstate0 + here->VBICirs_Vrs) = + *(ckt->CKTstate0 + here->VBICirs_Vrs) = *(ckt->CKTstate1 + here->VBICirs_Vrs); - *(ckt->CKTstate0 + here->VBICire_Vre) = + *(ckt->CKTstate0 + here->VBICire_Vre) = *(ckt->CKTstate1 + here->VBICire_Vre); if (here->VBIC_selfheat) - *(ckt->CKTstate0 + here->VBICqcth) = + *(ckt->CKTstate0 + here->VBICqcth) = *(ckt->CKTstate1 + here->VBICqcth); } else { #endif /* PREDICTOR */ @@ -515,17 +456,17 @@ VBICload(GENmodel *inModel, CKTcircuit *ckt) if (here->VBIC_selfheat) Vrth = *(ckt->CKTrhsOld + here->VBICtempNode); - ibehat = *(ckt->CKTstate0 + here->VBICibe) + + ibehat = *(ckt->CKTstate0 + here->VBICibe) + *(ckt->CKTstate0 + here->VBICibe_Vbei)*delvbei; - ibexhat = *(ckt->CKTstate0 + here->VBICibex) + + ibexhat = *(ckt->CKTstate0 + here->VBICibex) + *(ckt->CKTstate0 + here->VBICibex_Vbex)*delvbex; - itzfhat = *(ckt->CKTstate0 + here->VBICitzf) + + itzfhat = *(ckt->CKTstate0 + here->VBICitzf) + *(ckt->CKTstate0 + here->VBICitzf_Vbei)*delvbei + *(ckt->CKTstate0 + here->VBICitzf_Vbci)*delvbci; - itzrhat = *(ckt->CKTstate0 + here->VBICitzr) + + itzrhat = *(ckt->CKTstate0 + here->VBICitzr) + *(ckt->CKTstate0 + here->VBICitzr_Vbei)*delvbei + *(ckt->CKTstate0 + here->VBICitzr_Vbci)*delvbci; - ibchat = *(ckt->CKTstate0 + here->VBICibc) + + ibchat = *(ckt->CKTstate0 + here->VBICibc) + *(ckt->CKTstate0 + here->VBICibc_Vbei)*delvbei + *(ckt->CKTstate0 + here->VBICibc_Vbci)*delvbci; - ibephat = *(ckt->CKTstate0 + here->VBICibep) + + ibephat = *(ckt->CKTstate0 + here->VBICibep) + *(ckt->CKTstate0 + here->VBICibep_Vbep)*delvbep; ircihat = *(ckt->CKTstate0 + here->VBICirci) + *(ckt->CKTstate0 + here->VBICirci_Vrci)*delvrci + *(ckt->CKTstate0 + here->VBICirci_Vbcx)*delvbcx + *(ckt->CKTstate0 + here->VBICirci_Vbci)*delvbci; @@ -533,9 +474,9 @@ VBICload(GENmodel *inModel, CKTcircuit *ckt) *(ckt->CKTstate0 + here->VBICirbi_Vbei)*delvbei + *(ckt->CKTstate0 + here->VBICirbi_Vbci)*delvbci; irbphat = *(ckt->CKTstate0 + here->VBICirbp) + *(ckt->CKTstate0 + here->VBICirbp_Vrbp)*delvrbp + *(ckt->CKTstate0 + here->VBICirbp_Vbep)*delvbep + *(ckt->CKTstate0 + here->VBICirbp_Vbci)*delvbci; - ibcphat = *(ckt->CKTstate0 + here->VBICibcp) + + ibcphat = *(ckt->CKTstate0 + here->VBICibcp) + *(ckt->CKTstate0 + here->VBICibcp_Vbcp)*delvbcp; - iccphat = *(ckt->CKTstate0 + here->VBICiccp) + *(ckt->CKTstate0 + here->VBICiccp_Vbep)*delvbep + + iccphat = *(ckt->CKTstate0 + here->VBICiccp) + *(ckt->CKTstate0 + here->VBICiccp_Vbep)*delvbep + *(ckt->CKTstate0 + here->VBICiccp_Vbci)*delvbci + *(ckt->CKTstate0 + here->VBICiccp_Vbcp)*delvbcp; /* * bypass if solution has not changed @@ -573,47 +514,47 @@ VBICload(GENmodel *inModel, CKTcircuit *ckt) if( (fabs(delvbcp) < ckt->CKTreltol*MAX(fabs(Vbcp), fabs(*(ckt->CKTstate0 + here->VBICvbcp)))+ ckt->CKTvoltTol) ) - if( (fabs(ibehat-*(ckt->CKTstate0 + here->VBICibe)) < + if( (fabs(ibehat-*(ckt->CKTstate0 + here->VBICibe)) < ckt->CKTreltol* MAX(fabs(ibehat), fabs(*(ckt->CKTstate0 + here->VBICibe)))+ ckt->CKTabstol) ) - if( (fabs(ibexhat-*(ckt->CKTstate0 + here->VBICibex)) < + if( (fabs(ibexhat-*(ckt->CKTstate0 + here->VBICibex)) < ckt->CKTreltol* MAX(fabs(ibexhat), fabs(*(ckt->CKTstate0 + here->VBICibex)))+ ckt->CKTabstol) ) - if( (fabs(itzfhat-*(ckt->CKTstate0 + here->VBICitzf)) < + if( (fabs(itzfhat-*(ckt->CKTstate0 + here->VBICitzf)) < ckt->CKTreltol* MAX(fabs(itzfhat), fabs(*(ckt->CKTstate0 + here->VBICitzf)))+ ckt->CKTabstol) ) - if( (fabs(itzrhat-*(ckt->CKTstate0 + here->VBICitzr)) < + if( (fabs(itzrhat-*(ckt->CKTstate0 + here->VBICitzr)) < ckt->CKTreltol* MAX(fabs(itzrhat), fabs(*(ckt->CKTstate0 + here->VBICitzr)))+ ckt->CKTabstol) ) - if( (fabs(ibchat-*(ckt->CKTstate0 + here->VBICibc)) < + if( (fabs(ibchat-*(ckt->CKTstate0 + here->VBICibc)) < ckt->CKTreltol* MAX(fabs(ibchat), fabs(*(ckt->CKTstate0 + here->VBICibc)))+ ckt->CKTabstol) ) - if( (fabs(ibephat-*(ckt->CKTstate0 + here->VBICibep)) < + if( (fabs(ibephat-*(ckt->CKTstate0 + here->VBICibep)) < ckt->CKTreltol* MAX(fabs(ibephat), fabs(*(ckt->CKTstate0 + here->VBICibep)))+ ckt->CKTabstol) ) - if( (fabs(ircihat-*(ckt->CKTstate0 + here->VBICirci)) < + if( (fabs(ircihat-*(ckt->CKTstate0 + here->VBICirci)) < ckt->CKTreltol* MAX(fabs(ircihat), fabs(*(ckt->CKTstate0 + here->VBICirci)))+ ckt->CKTabstol) ) - if( (fabs(irbihat-*(ckt->CKTstate0 + here->VBICirbi)) < + if( (fabs(irbihat-*(ckt->CKTstate0 + here->VBICirbi)) < ckt->CKTreltol* MAX(fabs(irbihat), fabs(*(ckt->CKTstate0 + here->VBICirbi)))+ ckt->CKTabstol) ) - if( (fabs(irbphat-*(ckt->CKTstate0 + here->VBICirbp)) < + if( (fabs(irbphat-*(ckt->CKTstate0 + here->VBICirbp)) < ckt->CKTreltol* MAX(fabs(irbphat), fabs(*(ckt->CKTstate0 + here->VBICirbp)))+ ckt->CKTabstol) ) - if( (fabs(ibcphat-*(ckt->CKTstate0 + here->VBICibcp)) < + if( (fabs(ibcphat-*(ckt->CKTstate0 + here->VBICibcp)) < ckt->CKTreltol* MAX(fabs(ibcphat), fabs(*(ckt->CKTstate0 + here->VBICibcp)))+ ckt->CKTabstol) ) - if( (fabs(iccphat-*(ckt->CKTstate0 + here->VBICiccp)) < + if( (fabs(iccphat-*(ckt->CKTstate0 + here->VBICiccp)) < ckt->CKTreltol* MAX(fabs(iccphat), fabs(*(ckt->CKTstate0 + here->VBICiccp)))+ ckt->CKTabstol) ) { @@ -696,28 +637,42 @@ VBICload(GENmodel *inModel, CKTcircuit *ckt) /* * determine dc current and derivatives */ - Vcei = Vbei - Vbci; - Vcep = Vbep - Vbcp; - iret = vbic_4T_et_cf_fj(p - ,&Vrth, &Vbei, &Vbex, &Vbci, &Vbep, &Vbcp - ,&Vrcx, &Vbcx, &Vrci, &Vrbx, &Vrbi, &Vre, &Vrbp - ,&Vrs, &Vbe, &Vbc, &Vcei, &Vcep, &Ibe, &Ibe_Vrth - ,&Ibe_Vbei, &Ibex, &Ibex_Vrth, &Ibex_Vbex, &Itzf, &Itzf_Vrth, &Itzf_Vbei - ,&Itzf_Vbci, &Itzr, &Itzr_Vrth, &Itzr_Vbci, &Itzr_Vbei, &Ibc, &Ibc_Vrth - ,&Ibc_Vbci, &Ibc_Vbei, &Ibep, &Ibep_Vrth, &Ibep_Vbep, &Ircx, &Ircx_Vrcx - ,&Ircx_Vrth, &Irci, &Irci_Vrci, &Irci_Vrth, &Irci_Vbci, &Irci_Vbcx, &Irbx - ,&Irbx_Vrbx, &Irbx_Vrth, &Irbi, &Irbi_Vrbi, &Irbi_Vrth, &Irbi_Vbei, &Irbi_Vbci - ,&Ire, &Ire_Vre, &Ire_Vrth, &Irbp, &Irbp_Vrbp, &Irbp_Vrth, &Irbp_Vbep - ,&Irbp_Vbci, &Qbe, &Qbe_Vrth, &Qbe_Vbei, &Qbe_Vbci, &Qbex, &Qbex_Vrth - ,&Qbex_Vbex, &Qbc, &Qbc_Vrth, &Qbc_Vbci, &Qbcx, &Qbcx_Vrth, &Qbcx_Vbcx - ,&Qbep, &Qbep_Vrth, &Qbep_Vbep, &Qbep_Vbci, &Qbeo, &Qbeo_Vbe, &Qbco - ,&Qbco_Vbc, &Ibcp, &Ibcp_Vrth, &Ibcp_Vbcp, &Iccp, &Iccp_Vrth, &Iccp_Vbep - ,&Iccp_Vbci, &Iccp_Vbcp, &Irs, &Irs_Vrs, &Irs_Vrth, &Qbcp, &Qbcp_Vrth - ,&Qbcp_Vbcp, &Irth, &Irth_Vrth, &Ith, &Ith_Vrth, &Ith_Vbei, &Ith_Vbci - ,&Ith_Vcei, &Ith_Vbex, &Ith_Vbep, &Ith_Vrs, &Ith_Vbcp, &Ith_Vcep, &Ith_Vrcx - ,&Ith_Vrci, &Ith_Vbcx, &Ith_Vrbx, &Ith_Vrbi, &Ith_Vre, &Ith_Vrbp, &Qcth - ,&Qcth_Vrth, &SCALE); - + Vcei = Vbei - Vbci; + Vcep = Vbep - Vbcp; + if (here->VBIC_selfheat) { + iret = vbic_4T_et_cf_fj(p + ,&Vrth, &Vbei, &Vbex, &Vbci, &Vbep, &Vbcp + ,&Vrcx, &Vbcx, &Vrci, &Vrbx, &Vrbi, &Vre, &Vrbp + ,&Vrs, &Vbe, &Vbc, &Vcei, &Vcep, &Ibe, &Ibe_Vrth + ,&Ibe_Vbei, &Ibex, &Ibex_Vrth, &Ibex_Vbex, &Itzf, &Itzf_Vrth, &Itzf_Vbei + ,&Itzf_Vbci, &Itzr, &Itzr_Vrth, &Itzr_Vbci, &Itzr_Vbei, &Ibc, &Ibc_Vrth + ,&Ibc_Vbci, &Ibc_Vbei, &Ibep, &Ibep_Vrth, &Ibep_Vbep, &Ircx, &Ircx_Vrcx + ,&Ircx_Vrth, &Irci, &Irci_Vrci, &Irci_Vrth, &Irci_Vbci, &Irci_Vbcx, &Irbx + ,&Irbx_Vrbx, &Irbx_Vrth, &Irbi, &Irbi_Vrbi, &Irbi_Vrth, &Irbi_Vbei, &Irbi_Vbci + ,&Ire, &Ire_Vre, &Ire_Vrth, &Irbp, &Irbp_Vrbp, &Irbp_Vrth, &Irbp_Vbep + ,&Irbp_Vbci, &Qbe, &Qbe_Vrth, &Qbe_Vbei, &Qbe_Vbci, &Qbex, &Qbex_Vrth + ,&Qbex_Vbex, &Qbc, &Qbc_Vrth, &Qbc_Vbci, &Qbcx, &Qbcx_Vrth, &Qbcx_Vbcx + ,&Qbep, &Qbep_Vrth, &Qbep_Vbep, &Qbep_Vbci, &Qbeo, &Qbeo_Vbe, &Qbco + ,&Qbco_Vbc, &Ibcp, &Ibcp_Vrth, &Ibcp_Vbcp, &Iccp, &Iccp_Vrth, &Iccp_Vbep + ,&Iccp_Vbci, &Iccp_Vbcp, &Irs, &Irs_Vrs, &Irs_Vrth, &Qbcp, &Qbcp_Vrth + ,&Qbcp_Vbcp, &Irth, &Irth_Vrth, &Ith, &Ith_Vrth, &Ith_Vbei, &Ith_Vbci + ,&Ith_Vcei, &Ith_Vbex, &Ith_Vbep, &Ith_Vrs, &Ith_Vbcp, &Ith_Vcep, &Ith_Vrcx + ,&Ith_Vrci, &Ith_Vbcx, &Ith_Vrbx, &Ith_Vrbi, &Ith_Vre, &Ith_Vrbp, &Qcth + ,&Qcth_Vrth, &SCALE); + } else { + iret = vbic_4T_it_cf_fj(p + ,&Vbei, &Vbex, &Vbci, &Vbep, &Vbcp, &Vrcx + ,&Vbcx, &Vrci, &Vrbx, &Vrbi, &Vre, &Vrbp, &Vrs + ,&Vbe, &Vbc, &Ibe, &Ibe_Vbei, &Ibex, &Ibex_Vbex, &Itzf + ,&Itzf_Vbei, &Itzf_Vbci, &Itzr, &Itzr_Vbci, &Itzr_Vbei, &Ibc, &Ibc_Vbci + ,&Ibc_Vbei, &Ibep, &Ibep_Vbep, &Ircx, &Ircx_Vrcx, &Irci, &Irci_Vrci + ,&Irci_Vbci, &Irci_Vbcx, &Irbx, &Irbx_Vrbx, &Irbi, &Irbi_Vrbi, &Irbi_Vbei + ,&Irbi_Vbci, &Ire, &Ire_Vre, &Irbp, &Irbp_Vrbp, &Irbp_Vbep, &Irbp_Vbci + ,&Qbe, &Qbe_Vbei, &Qbe_Vbci, &Qbex, &Qbex_Vbex, &Qbc, &Qbc_Vbci + ,&Qbcx, &Qbcx_Vbcx, &Qbep, &Qbep_Vbep, &Qbep_Vbci, &Qbeo, &Qbeo_Vbe + ,&Qbco, &Qbco_Vbc, &Ibcp, &Ibcp_Vbcp, &Iccp, &Iccp_Vbep, &Iccp_Vbci + ,&Iccp_Vbcp, &Irs, &Irs_Vrs, &Qbcp, &Qbcp_Vbcp, &SCALE); + } Ibe += ckt->CKTgmin*Vbei; Ibe_Vbei += ckt->CKTgmin; Ibex += ckt->CKTgmin*Vbex; @@ -3978,3 +3933,1180 @@ double Ith_Iccp,Ith_Ircx,Ith_Irci,Ith_Irbx,Ith_Irbi,Ith_Ire,Ith_Irbp; } return(0); } +int vbic_4T_it_cf_fj(double *p + ,double *Vbei, double *Vbex, double *Vbci, double *Vbep, double *Vbcp, double *Vrcx + ,double *Vbcx, double *Vrci, double *Vrbx, double *Vrbi, double *Vre, double *Vrbp, double *Vrs + ,double *Vbe, double *Vbc, double *Ibe, double *Ibe_Vbei, double *Ibex, double *Ibex_Vbex, double *Itzf + ,double *Itzf_Vbei, double *Itzf_Vbci, double *Itzr, double *Itzr_Vbci, double *Itzr_Vbei, double *Ibc, double *Ibc_Vbci + ,double *Ibc_Vbei, double *Ibep, double *Ibep_Vbep, double *Ircx, double *Ircx_Vrcx, double *Irci, double *Irci_Vrci + ,double *Irci_Vbci, double *Irci_Vbcx, double *Irbx, double *Irbx_Vrbx, double *Irbi, double *Irbi_Vrbi, double *Irbi_Vbei + ,double *Irbi_Vbci, double *Ire, double *Ire_Vre, double *Irbp, double *Irbp_Vrbp, double *Irbp_Vbep, double *Irbp_Vbci + ,double *Qbe, double *Qbe_Vbei, double *Qbe_Vbci, double *Qbex, double *Qbex_Vbex, double *Qbc, double *Qbc_Vbci + ,double *Qbcx, double *Qbcx_Vbcx, double *Qbep, double *Qbep_Vbep, double *Qbep_Vbci, double *Qbeo, double *Qbeo_Vbe + ,double *Qbco, double *Qbco_Vbc, double *Ibcp, double *Ibcp_Vbcp, double *Iccp, double *Iccp_Vbep, double *Iccp_Vbci + ,double *Iccp_Vbcp, double *Irs, double *Irs_Vrs, double *Qbcp, double *Qbcp_Vbcp, double *SCALE) +{ +double Vtv,IVEF,IVER,IIKF,IIKR,IIKP,IVO; +double IHRCF,IVTF,IITF,slTF,dv0,dvh,dvh_Vbei; +double xvar1,xvar2,pwq,qlo,qlo_Vbei,qhi,qhi_dvh; +double qhi_Vbei,xvar1_Vbei,xvar3,xvar3_xvar1,xvar3_Vbei,qlo_xvar3,qdbe; +double qdbe_qlo,qdbe_Vbei,qdbe_qhi,mv0,vl0,q0,dv; +double dv_Vbei,mv,mv_dv,mv_Vbei,vl,vl_dv,vl_Vbei; +double vl_mv,xvar1_vl,qdbe_vl,dvh_Vbex,qlo_Vbex,qhi_Vbex,xvar1_Vbex; +double xvar3_Vbex,qdbex,qdbex_qlo,qdbex_Vbex,qdbex_qhi,dv_Vbex,mv_Vbex; +double vl_Vbex,qdbex_vl,dvh_Vbci,qlo_Vbci,qhi_Vbci,xvar1_Vbci,xvar3_Vbci; +double qdbc,qdbc_qlo,qdbc_Vbci,qdbc_qhi,vn0,vnl0,qlo0; +double vn,vn_Vbci,vnl,vnl_vn,vnl_Vbci,vl_vnl,vl_Vbci; +double sel,sel_vnl,sel_Vbci,crt,cmx,cl,cl_sel; +double cl_Vbci,ql,ql_Vbci,ql_vl,ql_cl,qdbc_ql,dv_Vbci; +double mv_Vbci,qdbc_vl,dvh_Vbep,qlo_Vbep,qhi_Vbep,xvar1_Vbep,xvar3_Vbep; +double qdbep,qdbep_qlo,qdbep_Vbep,qdbep_qhi,vn_Vbep,vnl_Vbep,vl_Vbep; +double sel_Vbep,cl_Vbep,ql_Vbep,qdbep_ql,dv_Vbep,mv_Vbep,qdbep_vl; +double dvh_Vbcp,qlo_Vbcp,qhi_Vbcp,xvar1_Vbcp,xvar3_Vbcp,qdbcp,qdbcp_qlo; +double qdbcp_Vbcp,qdbcp_Vbep,qdbcp_qhi,dv_Vbcp,mv_Vbcp,vl_Vbcp,qdbcp_vl; +double argi,argi_Vbei,expi,expi_argi,expi_Vbei,Ifi,Ifi_expi; +double Ifi_Vbei,argi_Vbci,expi_Vbci,Iri,Iri_expi,Iri_Vbci,q1z; +double q1z_qdbe,q1z_Vbei,q1z_qdbc,q1z_Vbci,q1,q1_q1z,q1_Vbei; +double q1_Vbci,q2,q2_Ifi,q2_Vbei,q2_Iri,q2_Vbci,xvar3_q1; +double xvar1_xvar3,xvar1_q2,xvar4,xvar4_xvar1,xvar4_Vbei,xvar4_Vbci,qb; +double qb_q1,qb_Vbei,qb_Vbci,qb_xvar4,xvar2_xvar1,xvar2_Vbei,xvar2_Vbci; +double qb_xvar2,Itzr_Iri,Itzr_qb,Itzf_Ifi,Itzf_qb,argi_Vbep,expi_Vbep; +double argx,argx_Vbci,expx,expx_argx,expx_Vbci,Ifp,Ifp_expi; +double Ifp_Vbep,Ifp_expx,Ifp_Vbci,q2p,q2p_Ifp,q2p_Vbep,q2p_Vbci; +double qbp,qbp_q2p,qbp_Vbep,qbp_Vbci,argi_Vbcp,expi_Vbcp,Irp; +double Irp_expi,Irp_Vbcp,Iccp_Ifp,Iccp_Irp,Iccp_qbp,argn,argn_Vbei; +double expn,expn_argn,expn_Vbei,argx_Vbei,expx_Vbei,Ibe_expi,Ibe_expn; +double Ibe_expx,argi_Vbex,expi_Vbex,argn_Vbex,expn_Vbex,argx_Vbex,expx_Vbex; +double Ibex_expi,Ibex_expn,Ibex_expx,argn_Vbci,expn_Vbci,Ibcj,Ibcj_expi; +double Ibcj_Vbci,Ibcj_expn,argn_Vbep,expn_Vbep,Ibep_expi,Ibep_expn,xvar3_vl; +double avalf,avalf_vl,avalf_Vbci,avalf_xvar4,Igc,Igc_Itzf,Igc_Vbei; +double Igc_Vbci,Igc_Itzr,Igc_Ibcj,Igc_avalf,Ibc_Ibcj,Ibc_Igc,argx_Vbcx; +double expx_Vbcx,Kbci,Kbci_expi,Kbci_Vbci,Kbcx,Kbcx_expx,Kbcx_Vbcx; +double rKp1,rKp1_Kbci,rKp1_Vbci,rKp1_Kbcx,rKp1_Vbcx,xvar1_rKp1,xvar1_Vbcx; +double Iohm,Iohm_Vrci,Iohm_Kbci,Iohm_Vbci,Iohm_Kbcx,Iohm_Vbcx,Iohm_xvar1; +double derf,derf_Iohm,derf_Vrci,derf_Vbci,derf_Vbcx,Irci_Iohm,Irci_derf; +double Irbi_qb,Irbp_qbp,argn_Vbcp,expn_Vbcp,Ibcp_expi,Ibcp_expn,sgIf; +double rIf,rIf_Ifi,rIf_Vbei,mIf,mIf_rIf,mIf_Vbei,tff; +double tff_q1,tff_Vbei,tff_Vbci,tff_xvar2,tff_mIf,Qbe_qdbe,Qbe_tff; +double Qbe_Ifi,Qbe_qb,Qbex_qdbex,Qbc_qdbc,Qbc_Iri,Qbc_Kbci,Qbcx_Kbcx; +double Qbep_qdbep,Qbep_Ifp,Qbcp_qdbcp; + +/* Function and derivative code */ + + Vtv=1.380662e-23*(2.731500e+02+p[0])/1.602189e-19; + if(p[51]>0.0){ + IVEF=1.0/p[51]; + }else{ + IVEF=0.0; + } + if(p[52]>0.0){ + IVER=1.0/p[52]; + }else{ + IVER=0.0; + } + if(p[53]>0.0){ + IIKF=1.0/p[53]; + }else{ + IIKF=0.0; + } + if(p[54]>0.0){ + IIKR=1.0/p[54]; + }else{ + IIKR=0.0; + } + if(p[55]>0.0){ + IIKP=1.0/p[55]; + }else{ + IIKP=0.0; + } + if(p[3]>0.0){ + IVO=1.0/p[3]; + }else{ + IVO=0.0; + } + if(p[5]>0.0){ + IHRCF=1.0/p[5]; + }else{ + IHRCF=0.0; + } + if(p[59]>0.0){ + IVTF=1.0/p[59]; + }else{ + IVTF=0.0; + } + if(p[60]>0.0){ + IITF=1.0/p[60]; + }else{ + IITF=0.0; + } + if(p[60]>0.0){ + slTF=0.0; + }else{ + slTF=1.0; + } + dv0=-p[17]*p[14]; + if(p[19]<=0.0){ + dvh=(*Vbei)+dv0; + dvh_Vbei=1.0; + if(dvh>0.0){ + xvar1=(1.0-p[14]); + xvar2=(-1.0-p[18]); + pwq=pow(xvar1,xvar2); + qlo=p[17]*(1.0-pwq*(1.0-p[14])*(1.0-p[14]))/(1.0-p[18]); + qlo_Vbei=0.0; + qhi=dvh*(1.0-p[14]+0.5*p[18]*dvh/p[17])*pwq; + qhi_dvh=(0.5*dvh*p[18]/p[17]-p[14]+1.0)*pwq+0.5*dvh*p[18]*pwq/p[17]; + qhi_Vbei=qhi_dvh*dvh_Vbei; + }else{ + xvar1=(1.0-(*Vbei)/p[17]); + xvar1_Vbei=-1.0/p[17]; + xvar2=(1.0-p[18]); + xvar3=pow(xvar1,xvar2); + xvar3_xvar1=xvar3*xvar2/xvar1; + xvar3_Vbei=xvar3_xvar1*xvar1_Vbei; + qlo=p[17]*(1.0-xvar3)/(1.0-p[18]); + qlo_xvar3=-p[17]/(1.0-p[18]); + qlo_Vbei=qlo_xvar3*xvar3_Vbei; + qhi=0.0; + qhi_Vbei=0.0; + } + qdbe=qlo+qhi; + qdbe_qlo=1.0; + qdbe_qhi=1.0; + qdbe_Vbei=qdbe_qlo*qlo_Vbei; + qdbe_Vbei=qdbe_Vbei+qdbe_qhi*qhi_Vbei; + }else{ + mv0=sqrt(dv0*dv0+4.0*p[19]*p[19]); + vl0=-0.5*(dv0+mv0); + xvar1=(1.0-vl0/p[17]); + xvar2=(1.0-p[18]); + xvar3=pow(xvar1,xvar2); + q0=-p[17]*xvar3/(1.0-p[18]); + dv=(*Vbei)+dv0; + dv_Vbei=1.0; + mv=sqrt(dv*dv+4.0*p[19]*p[19]); + mv_dv=dv/sqrt((dv*dv)+4.0*(p[19]*p[19])); + mv_Vbei=mv_dv*dv_Vbei; + vl=0.5*(dv-mv)-dv0; + vl_dv=0.5; + vl_mv=-0.5; + vl_Vbei=vl_dv*dv_Vbei; + vl_Vbei=vl_Vbei+vl_mv*mv_Vbei; + xvar1=(1.0-vl/p[17]); + xvar1_vl=-1.0/p[17]; + xvar1_Vbei=xvar1_vl*vl_Vbei; + xvar2=(1.0-p[18]); + xvar3=pow(xvar1,xvar2); + xvar3_xvar1=xvar3*xvar2/xvar1; + xvar3_Vbei=xvar3_xvar1*xvar1_Vbei; + qlo=-p[17]*xvar3/(1.0-p[18]); + qlo_xvar3=-p[17]/(1.0-p[18]); + qlo_Vbei=qlo_xvar3*xvar3_Vbei; + xvar1=(1.0-p[14]); + xvar2=(-p[18]); + xvar3=pow(xvar1,xvar2); + qdbe=qlo+xvar3*((*Vbei)-vl+vl0)-q0; + qdbe_qlo=1.0; + qdbe_Vbei=xvar3; + qdbe_vl=-xvar3; + qdbe_Vbei=qdbe_Vbei+qdbe_qlo*qlo_Vbei; + qdbe_Vbei=qdbe_Vbei+qdbe_vl*vl_Vbei; + } + dv0=-p[17]*p[14]; + if(p[19]<=0.0){ + dvh=(*Vbex)+dv0; + dvh_Vbex=1.0; + if(dvh>0.0){ + xvar1=(1.0-p[14]); + xvar2=(-1.0-p[18]); + pwq=pow(xvar1,xvar2); + qlo=p[17]*(1.0-pwq*(1.0-p[14])*(1.0-p[14]))/(1.0-p[18]); + qlo_Vbex=0.0; + qhi=dvh*(1.0-p[14]+0.5*p[18]*dvh/p[17])*pwq; + qhi_dvh=(0.5*dvh*p[18]/p[17]-p[14]+1.0)*pwq+0.5*dvh*p[18]*pwq/p[17]; + qhi_Vbex=qhi_dvh*dvh_Vbex; + }else{ + xvar1=(1.0-(*Vbex)/p[17]); + xvar1_Vbex=-1.0/p[17]; + xvar2=(1.0-p[18]); + xvar3=pow(xvar1,xvar2); + xvar3_xvar1=xvar3*xvar2/xvar1; + xvar3_Vbex=xvar3_xvar1*xvar1_Vbex; + qlo=p[17]*(1.0-xvar3)/(1.0-p[18]); + qlo_xvar3=-p[17]/(1.0-p[18]); + qlo_Vbex=qlo_xvar3*xvar3_Vbex; + qhi=0.0; + qhi_Vbex=0.0; + } + qdbex=qlo+qhi; + qdbex_qlo=1.0; + qdbex_qhi=1.0; + qdbex_Vbex=qdbex_qlo*qlo_Vbex; + qdbex_Vbex=qdbex_Vbex+qdbex_qhi*qhi_Vbex; + }else{ + mv0=sqrt(dv0*dv0+4.0*p[19]*p[19]); + vl0=-0.5*(dv0+mv0); + xvar1=(1.0-vl0/p[17]); + xvar2=(1.0-p[18]); + xvar3=pow(xvar1,xvar2); + q0=-p[17]*xvar3/(1.0-p[18]); + dv=(*Vbex)+dv0; + dv_Vbex=1.0; + mv=sqrt(dv*dv+4.0*p[19]*p[19]); + mv_dv=dv/sqrt((dv*dv)+4.0*(p[19]*p[19])); + mv_Vbex=mv_dv*dv_Vbex; + vl=0.5*(dv-mv)-dv0; + vl_dv=0.5; + vl_mv=-0.5; + vl_Vbex=vl_dv*dv_Vbex; + vl_Vbex=vl_Vbex+vl_mv*mv_Vbex; + xvar1=(1.0-vl/p[17]); + xvar1_vl=-1.0/p[17]; + xvar1_Vbex=xvar1_vl*vl_Vbex; + xvar2=(1.0-p[18]); + xvar3=pow(xvar1,xvar2); + xvar3_xvar1=xvar3*xvar2/xvar1; + xvar3_Vbex=xvar3_xvar1*xvar1_Vbex; + qlo=-p[17]*xvar3/(1.0-p[18]); + qlo_xvar3=-p[17]/(1.0-p[18]); + qlo_Vbex=qlo_xvar3*xvar3_Vbex; + xvar1=(1.0-p[14]); + xvar2=(-p[18]); + xvar3=pow(xvar1,xvar2); + qdbex=qlo+xvar3*((*Vbex)-vl+vl0)-q0; + qdbex_qlo=1.0; + qdbex_Vbex=xvar3; + qdbex_vl=-xvar3; + qdbex_Vbex=qdbex_Vbex+qdbex_qlo*qlo_Vbex; + qdbex_Vbex=qdbex_Vbex+qdbex_vl*vl_Vbex; + } + dv0=-p[24]*p[14]; + if(p[26]<=0.0){ + dvh=(*Vbci)+dv0; + dvh_Vbci=1.0; + if(dvh>0.0){ + xvar1=(1.0-p[14]); + xvar2=(-1.0-p[25]); + pwq=pow(xvar1,xvar2); + qlo=p[24]*(1.0-pwq*(1.0-p[14])*(1.0-p[14]))/(1.0-p[25]); + qlo_Vbci=0.0; + qhi=dvh*(1.0-p[14]+0.5*p[25]*dvh/p[24])*pwq; + qhi_dvh=(0.5*dvh*p[25]/p[24]-p[14]+1.0)*pwq+0.5*dvh*p[25]*pwq/p[24]; + qhi_Vbci=qhi_dvh*dvh_Vbci; + }else{ + if((p[85]>0.0)&&((*Vbci)<-p[85])){ + xvar1=(1.0+p[85]/p[24]); + xvar2=(1.0-p[25]); + xvar3=pow(xvar1,xvar2); + qlo=p[24]*(1.0-xvar3*(1.0-((1.0-p[25])*((*Vbci)+p[85]))/(p[24]+p[85])))/(1.0-p[25]); + qlo_Vbci=p[24]*xvar3/(p[85]+p[24]); + }else{ + xvar1=(1.0-(*Vbci)/p[24]); + xvar1_Vbci=-1.0/p[24]; + xvar2=(1.0-p[25]); + xvar3=pow(xvar1,xvar2); + xvar3_xvar1=xvar3*xvar2/xvar1; + xvar3_Vbci=xvar3_xvar1*xvar1_Vbci; + qlo=p[24]*(1.0-xvar3)/(1.0-p[25]); + qlo_xvar3=-p[24]/(1.0-p[25]); + qlo_Vbci=qlo_xvar3*xvar3_Vbci; + } + qhi=0.0; + qhi_Vbci=0.0; + } + qdbc=qlo+qhi; + qdbc_qlo=1.0; + qdbc_qhi=1.0; + qdbc_Vbci=qdbc_qlo*qlo_Vbci; + qdbc_Vbci=qdbc_Vbci+qdbc_qhi*qhi_Vbci; + }else{ + if((p[85]>0.0)&&(p[86]>0.0)){ + vn0=(p[85]+dv0)/(p[85]-dv0); + vnl0=2.0*vn0/(sqrt((vn0-1.0)*(vn0-1.0)+4.0*p[26]*p[26])+sqrt((vn0+1.0)*(vn0+1.0)+4.0*p[86]*p[86])); + vl0=0.5*(vnl0*(p[85]-dv0)-p[85]-dv0); + xvar1=(1.0-vl0/p[24]); + xvar2=(1.0-p[25]); + xvar3=pow(xvar1,xvar2); + qlo0=p[24]*(1.0-xvar3)/(1.0-p[25]); + vn=(2.0*(*Vbci)+p[85]+dv0)/(p[85]-dv0); + vn_Vbci=2.0/(p[85]-dv0); + vnl=2.0*vn/(sqrt((vn-1.0)*(vn-1.0)+4.0*p[26]*p[26])+sqrt((vn+1.0)*(vn+1.0)+4.0*p[86]*p[86])); + vnl_vn=2.0/(sqrt(((vn+1.0)*(vn+1.0))+4.0*(p[86]*p[86]))+sqrt(((vn-1.0)*(vn-1.0))+4.0*(p[26]*p[26])))-2.0*vn*((vn+1.0)/sqrt(((vn+1.0)*(vn+1.0))+4.0*(p[86]*p[86]))+(vn-1.0)/sqrt(((vn-1.0)*(vn-1.0))+4.0*(p[26]*p[26])))/((sqrt(((vn+1.0)*(vn+1.0))+4.0*(p[86]*p[86]))+sqrt(((vn-1.0)*(vn-1.0))+4.0*(p[26]*p[26])))*(sqrt(((vn+1.0)*(vn+1.0))+4.0*(p[86]*p[86]))+sqrt(((vn-1.0)*(vn-1.0))+4.0*(p[26]*p[26])))); + vnl_Vbci=vnl_vn*vn_Vbci; + vl=0.5*(vnl*(p[85]-dv0)-p[85]-dv0); + vl_vnl=0.5*(p[85]-dv0); + vl_Vbci=vl_vnl*vnl_Vbci; + xvar1=(1.0-vl/p[24]); + xvar1_vl=-1.0/p[24]; + xvar1_Vbci=xvar1_vl*vl_Vbci; + xvar2=(1.0-p[25]); + xvar3=pow(xvar1,xvar2); + xvar3_xvar1=xvar3*xvar2/xvar1; + xvar3_Vbci=xvar3_xvar1*xvar1_Vbci; + qlo=p[24]*(1.0-xvar3)/(1.0-p[25]); + qlo_xvar3=-p[24]/(1.0-p[25]); + qlo_Vbci=qlo_xvar3*xvar3_Vbci; + sel=0.5*(vnl+1.0); + sel_vnl=0.5; + sel_Vbci=sel_vnl*vnl_Vbci; + xvar1=(1.0+p[85]/p[24]); + xvar2=(-p[25]); + crt=pow(xvar1,xvar2); + xvar1=(1.0+dv0/p[24]); + xvar2=(-p[25]); + cmx=pow(xvar1,xvar2); + cl=(1.0-sel)*crt+sel*cmx; + cl_sel=cmx-crt; + cl_Vbci=cl_sel*sel_Vbci; + ql=((*Vbci)-vl+vl0)*cl; + ql_Vbci=cl; + ql_vl=-cl; + ql_cl=vl0-vl+(*Vbci); + ql_Vbci=ql_Vbci+ql_vl*vl_Vbci; + ql_Vbci=ql_Vbci+ql_cl*cl_Vbci; + qdbc=ql+qlo-qlo0; + qdbc_ql=1.0; + qdbc_qlo=1.0; + qdbc_Vbci=qdbc_ql*ql_Vbci; + qdbc_Vbci=qdbc_Vbci+qdbc_qlo*qlo_Vbci; + }else{ + mv0=sqrt(dv0*dv0+4.0*p[26]*p[26]); + vl0=-0.5*(dv0+mv0); + xvar1=(1.0-vl0/p[24]); + xvar2=(1.0-p[25]); + xvar3=pow(xvar1,xvar2); + q0=-p[24]*xvar3/(1.0-p[25]); + dv=(*Vbci)+dv0; + dv_Vbci=1.0; + mv=sqrt(dv*dv+4.0*p[26]*p[26]); + mv_dv=dv/sqrt((dv*dv)+4.0*(p[26]*p[26])); + mv_Vbci=mv_dv*dv_Vbci; + vl=0.5*(dv-mv)-dv0; + vl_dv=0.5; + vl_mv=-0.5; + vl_Vbci=vl_dv*dv_Vbci; + vl_Vbci=vl_Vbci+vl_mv*mv_Vbci; + xvar1=(1.0-vl/p[24]); + xvar1_vl=-1.0/p[24]; + xvar1_Vbci=xvar1_vl*vl_Vbci; + xvar2=(1.0-p[25]); + xvar3=pow(xvar1,xvar2); + xvar3_xvar1=xvar3*xvar2/xvar1; + xvar3_Vbci=xvar3_xvar1*xvar1_Vbci; + qlo=-p[24]*xvar3/(1.0-p[25]); + qlo_xvar3=-p[24]/(1.0-p[25]); + qlo_Vbci=qlo_xvar3*xvar3_Vbci; + xvar1=(1.0-p[14]); + xvar2=(-p[25]); + xvar3=pow(xvar1,xvar2); + qdbc=qlo+xvar3*((*Vbci)-vl+vl0)-q0; + qdbc_qlo=1.0; + qdbc_Vbci=xvar3; + qdbc_vl=-xvar3; + qdbc_Vbci=qdbc_Vbci+qdbc_qlo*qlo_Vbci; + qdbc_Vbci=qdbc_Vbci+qdbc_vl*vl_Vbci; + } + } + dv0=-p[24]*p[14]; + if(p[26]<=0.0){ + dvh=(*Vbep)+dv0; + dvh_Vbep=1.0; + if(dvh>0.0){ + xvar1=(1.0-p[14]); + xvar2=(-1.0-p[25]); + pwq=pow(xvar1,xvar2); + qlo=p[24]*(1.0-pwq*(1.0-p[14])*(1.0-p[14]))/(1.0-p[25]); + qlo_Vbep=0.0; + qhi=dvh*(1.0-p[14]+0.5*p[25]*dvh/p[24])*pwq; + qhi_dvh=(0.5*dvh*p[25]/p[24]-p[14]+1.0)*pwq+0.5*dvh*p[25]*pwq/p[24]; + qhi_Vbep=qhi_dvh*dvh_Vbep; + }else{ + if((p[85]>0.0)&&((*Vbep)<-p[85])){ + xvar1=(1.0+p[85]/p[24]); + xvar2=(1.0-p[25]); + xvar3=pow(xvar1,xvar2); + qlo=p[24]*(1.0-xvar3*(1.0-((1.0-p[25])*((*Vbep)+p[85]))/(p[24]+p[85])))/(1.0-p[25]); + qlo_Vbep=p[24]*xvar3/(p[85]+p[24]); + }else{ + xvar1=(1.0-(*Vbep)/p[24]); + xvar1_Vbep=-1.0/p[24]; + xvar2=(1.0-p[25]); + xvar3=pow(xvar1,xvar2); + xvar3_xvar1=xvar3*xvar2/xvar1; + xvar3_Vbep=xvar3_xvar1*xvar1_Vbep; + qlo=p[24]*(1.0-xvar3)/(1.0-p[25]); + qlo_xvar3=-p[24]/(1.0-p[25]); + qlo_Vbep=qlo_xvar3*xvar3_Vbep; + } + qhi=0.0; + qhi_Vbep=0.0; + } + qdbep=qlo+qhi; + qdbep_qlo=1.0; + qdbep_qhi=1.0; + qdbep_Vbep=qdbep_qlo*qlo_Vbep; + qdbep_Vbep=qdbep_Vbep+qdbep_qhi*qhi_Vbep; + }else{ + if((p[85]>0.0)&&(p[86]>0.0)){ + vn0=(p[85]+dv0)/(p[85]-dv0); + vnl0=2.0*vn0/(sqrt((vn0-1.0)*(vn0-1.0)+4.0*p[26]*p[26])+sqrt((vn0+1.0)*(vn0+1.0)+4.0*p[86]*p[86])); + vl0=0.5*(vnl0*(p[85]-dv0)-p[85]-dv0); + xvar1=(1.0-vl0/p[24]); + xvar2=(1.0-p[25]); + xvar3=pow(xvar1,xvar2); + qlo0=p[24]*(1.0-xvar3)/(1.0-p[25]); + vn=(2.0*(*Vbep)+p[85]+dv0)/(p[85]-dv0); + vn_Vbep=2.0/(p[85]-dv0); + vnl=2.0*vn/(sqrt((vn-1.0)*(vn-1.0)+4.0*p[26]*p[26])+sqrt((vn+1.0)*(vn+1.0)+4.0*p[86]*p[86])); + vnl_vn=2.0/(sqrt(((vn+1.0)*(vn+1.0))+4.0*(p[86]*p[86]))+sqrt(((vn-1.0)*(vn-1.0))+4.0*(p[26]*p[26])))-2.0*vn*((vn+1.0)/sqrt(((vn+1.0)*(vn+1.0))+4.0*(p[86]*p[86]))+(vn-1.0)/sqrt(((vn-1.0)*(vn-1.0))+4.0*(p[26]*p[26])))/((sqrt(((vn+1.0)*(vn+1.0))+4.0*(p[86]*p[86]))+sqrt(((vn-1.0)*(vn-1.0))+4.0*(p[26]*p[26])))*(sqrt(((vn+1.0)*(vn+1.0))+4.0*(p[86]*p[86]))+sqrt(((vn-1.0)*(vn-1.0))+4.0*(p[26]*p[26])))); + vnl_Vbep=vnl_vn*vn_Vbep; + vl=0.5*(vnl*(p[85]-dv0)-p[85]-dv0); + vl_vnl=0.5*(p[85]-dv0); + vl_Vbep=vl_vnl*vnl_Vbep; + xvar1=(1.0-vl/p[24]); + xvar1_vl=-1.0/p[24]; + xvar1_Vbep=xvar1_vl*vl_Vbep; + xvar2=(1.0-p[25]); + xvar3=pow(xvar1,xvar2); + xvar3_xvar1=xvar3*xvar2/xvar1; + xvar3_Vbep=xvar3_xvar1*xvar1_Vbep; + qlo=p[24]*(1.0-xvar3)/(1.0-p[25]); + qlo_xvar3=-p[24]/(1.0-p[25]); + qlo_Vbep=qlo_xvar3*xvar3_Vbep; + sel=0.5*(vnl+1.0); + sel_vnl=0.5; + sel_Vbep=sel_vnl*vnl_Vbep; + xvar1=(1.0+p[85]/p[24]); + xvar2=(-p[25]); + crt=pow(xvar1,xvar2); + xvar1=(1.0+dv0/p[24]); + xvar2=(-p[25]); + cmx=pow(xvar1,xvar2); + cl=(1.0-sel)*crt+sel*cmx; + cl_sel=cmx-crt; + cl_Vbep=cl_sel*sel_Vbep; + ql=((*Vbep)-vl+vl0)*cl; + ql_Vbep=cl; + ql_vl=-cl; + ql_cl=vl0-vl+(*Vbep); + ql_Vbep=ql_Vbep+ql_vl*vl_Vbep; + ql_Vbep=ql_Vbep+ql_cl*cl_Vbep; + qdbep=ql+qlo-qlo0; + qdbep_ql=1.0; + qdbep_qlo=1.0; + qdbep_Vbep=qdbep_ql*ql_Vbep; + qdbep_Vbep=qdbep_Vbep+qdbep_qlo*qlo_Vbep; + }else{ + mv0=sqrt(dv0*dv0+4.0*p[26]*p[26]); + vl0=-0.5*(dv0+mv0); + xvar1=(1.0-vl0/p[24]); + xvar2=(1.0-p[25]); + xvar3=pow(xvar1,xvar2); + q0=-p[24]*xvar3/(1.0-p[25]); + dv=(*Vbep)+dv0; + dv_Vbep=1.0; + mv=sqrt(dv*dv+4.0*p[26]*p[26]); + mv_dv=dv/sqrt((dv*dv)+4.0*(p[26]*p[26])); + mv_Vbep=mv_dv*dv_Vbep; + vl=0.5*(dv-mv)-dv0; + vl_dv=0.5; + vl_mv=-0.5; + vl_Vbep=vl_dv*dv_Vbep; + vl_Vbep=vl_Vbep+vl_mv*mv_Vbep; + xvar1=(1.0-vl/p[24]); + xvar1_vl=-1.0/p[24]; + xvar1_Vbep=xvar1_vl*vl_Vbep; + xvar2=(1.0-p[25]); + xvar3=pow(xvar1,xvar2); + xvar3_xvar1=xvar3*xvar2/xvar1; + xvar3_Vbep=xvar3_xvar1*xvar1_Vbep; + qlo=-p[24]*xvar3/(1.0-p[25]); + qlo_xvar3=-p[24]/(1.0-p[25]); + qlo_Vbep=qlo_xvar3*xvar3_Vbep; + xvar1=(1.0-p[14]); + xvar2=(-p[25]); + xvar3=pow(xvar1,xvar2); + qdbep=qlo+xvar3*((*Vbep)-vl+vl0)-q0; + qdbep_qlo=1.0; + qdbep_Vbep=xvar3; + qdbep_vl=-xvar3; + qdbep_Vbep=qdbep_Vbep+qdbep_qlo*qlo_Vbep; + qdbep_Vbep=qdbep_Vbep+qdbep_vl*vl_Vbep; + } + } + if(p[27]>0.0){ + dv0=-p[28]*p[14]; + if(p[30]<=0.0){ + dvh=(*Vbcp)+dv0; + dvh_Vbcp=1.0; + if(dvh>0.0){ + xvar1=(1.0-p[14]); + xvar2=(-1.0-p[29]); + pwq=pow(xvar1,xvar2); + qlo=p[28]*(1.0-pwq*(1.0-p[14])*(1.0-p[14]))/(1.0-p[29]); + qlo_Vbep=0.0; + qlo_Vbcp=0.0; + qhi=dvh*(1.0-p[14]+0.5*p[29]*dvh/p[28])*pwq; + qhi_dvh=(0.5*dvh*p[29]/p[28]-p[14]+1.0)*pwq+0.5*dvh*p[29]*pwq/p[28]; + qhi_Vbep=0.0; + qhi_Vbcp=qhi_dvh*dvh_Vbcp; + }else{ + xvar1=(1.0-(*Vbcp)/p[28]); + xvar1_Vbcp=-1.0/p[28]; + xvar2=(1.0-p[29]); + xvar3=pow(xvar1,xvar2); + xvar3_xvar1=xvar3*xvar2/xvar1; + xvar3_Vbcp=xvar3_xvar1*xvar1_Vbcp; + qlo=p[28]*(1.0-xvar3)/(1.0-p[29]); + qlo_xvar3=-p[28]/(1.0-p[29]); + qlo_Vbep=0.0; + qlo_Vbcp=qlo_xvar3*xvar3_Vbcp; + qhi=0.0; + qhi_Vbep=0.0; + qhi_Vbcp=0.0; + } + qdbcp=qlo+qhi; + qdbcp_qlo=1.0; + qdbcp_qhi=1.0; + qdbcp_Vbcp=qdbcp_qlo*qlo_Vbcp; + qdbcp_Vbep=qdbcp_qlo*qlo_Vbep; + qdbcp_Vbep=qdbcp_Vbep+qdbcp_qhi*qhi_Vbep; + qdbcp_Vbcp=qdbcp_Vbcp+qdbcp_qhi*qhi_Vbcp; + }else{ + mv0=sqrt(dv0*dv0+4.0*p[30]*p[30]); + vl0=-0.5*(dv0+mv0); + xvar1=(1.0-vl0/p[28]); + xvar2=(1.0-p[29]); + xvar3=pow(xvar1,xvar2); + q0=-p[28]*xvar3/(1.0-p[29]); + dv=(*Vbcp)+dv0; + dv_Vbcp=1.0; + mv=sqrt(dv*dv+4.0*p[30]*p[30]); + mv_dv=dv/sqrt((dv*dv)+4.0*(p[30]*p[30])); + mv_Vbcp=mv_dv*dv_Vbcp; + vl=0.5*(dv-mv)-dv0; + vl_dv=0.5; + vl_mv=-0.5; + vl_Vbcp=vl_dv*dv_Vbcp; + vl_Vbcp=vl_Vbcp+vl_mv*mv_Vbcp; + xvar1=(1.0-vl/p[28]); + xvar1_vl=-1.0/p[28]; + xvar1_Vbcp=xvar1_vl*vl_Vbcp; + xvar2=(1.0-p[29]); + xvar3=pow(xvar1,xvar2); + xvar3_xvar1=xvar3*xvar2/xvar1; + xvar3_Vbcp=xvar3_xvar1*xvar1_Vbcp; + qlo=-p[28]*xvar3/(1.0-p[29]); + qlo_xvar3=-p[28]/(1.0-p[29]); + qlo_Vbep=0.0; + qlo_Vbcp=qlo_xvar3*xvar3_Vbcp; + xvar1=(1.0-p[14]); + xvar2=(-p[29]); + xvar3=pow(xvar1,xvar2); + qdbcp=qlo+xvar3*((*Vbcp)-vl+vl0)-q0; + qdbcp_qlo=1.0; + qdbcp_Vbcp=xvar3; + qdbcp_vl=-xvar3; + qdbcp_Vbcp=qdbcp_Vbcp+qdbcp_qlo*qlo_Vbcp; + qdbcp_Vbep=qdbcp_qlo*qlo_Vbep; + qdbcp_Vbcp=qdbcp_Vbcp+qdbcp_vl*vl_Vbcp; + } + }else{ + qdbcp=0.0; + qdbcp_Vbcp=0.0; + } + argi=(*Vbei)/(p[12]*Vtv); + argi_Vbei=1.0/(p[12]*Vtv); + expi=exp(argi); + expi_argi=expi; + expi_Vbei=expi_argi*argi_Vbei; + Ifi=p[11]*(expi-1.0); + Ifi_expi=p[11]; + Ifi_Vbei=Ifi_expi*expi_Vbei; + argi=(*Vbci)/(p[13]*Vtv); + argi_Vbci=1.0/(p[13]*Vtv); + expi=exp(argi); + expi_argi=expi; + expi_Vbci=expi_argi*argi_Vbci; + Iri=p[11]*p[94]*(expi-1.0); + Iri_expi=p[11]*p[94]; + Iri_Vbci=Iri_expi*expi_Vbci; + q1z=1.0+qdbe*IVER+qdbc*IVEF; + q1z_qdbe=IVER; + q1z_qdbc=IVEF; + q1z_Vbei=q1z_qdbe*qdbe_Vbei; + q1z_Vbci=q1z_qdbc*qdbc_Vbci; + q1=0.5*(sqrt((q1z-1.0e-4)*(q1z-1.0e-4)+1.0e-8)+q1z-1.0e-4)+1.0e-4; + q1_q1z=0.5*((q1z-1.0e-4)/sqrt(((q1z-1.0e-4)*(q1z-1.0e-4))+1.0e-8)+1.0); + q1_Vbei=q1_q1z*q1z_Vbei; + q1_Vbci=q1_q1z*q1z_Vbci; + q2=Ifi*IIKF+Iri*IIKR; + q2_Ifi=IIKF; + q2_Iri=IIKR; + q2_Vbei=q2_Ifi*Ifi_Vbei; + q2_Vbci=q2_Iri*Iri_Vbci; + if(p[88]<0.5){ + xvar2=1.0/p[89]; + xvar3=pow(q1,xvar2); + xvar3_q1=xvar3*xvar2/q1; + xvar3_Vbei=xvar3_q1*q1_Vbei; + xvar3_Vbci=xvar3_q1*q1_Vbci; + xvar1=(xvar3+4.0*q2); + xvar1_xvar3=1.0; + xvar1_q2=4.0; + xvar1_Vbei=xvar1_xvar3*xvar3_Vbei; + xvar1_Vbci=xvar1_xvar3*xvar3_Vbci; + xvar1_Vbei=xvar1_Vbei+xvar1_q2*q2_Vbei; + xvar1_Vbci=xvar1_Vbci+xvar1_q2*q2_Vbci; + xvar4=pow(xvar1,p[89]); + xvar4_xvar1=xvar4*p[89]/xvar1; + xvar4_Vbei=xvar4_xvar1*xvar1_Vbei; + xvar4_Vbci=xvar4_xvar1*xvar1_Vbci; + qb=0.5*(q1+xvar4); + qb_q1=0.5; + qb_xvar4=0.5; + qb_Vbei=qb_q1*q1_Vbei; + qb_Vbci=qb_q1*q1_Vbci; + qb_Vbei=qb_Vbei+qb_xvar4*xvar4_Vbei; + qb_Vbci=qb_Vbci+qb_xvar4*xvar4_Vbci; + }else{ + xvar1=(1.0+4.0*q2); + xvar1_q2=4.0; + xvar1_Vbei=xvar1_q2*q2_Vbei; + xvar1_Vbci=xvar1_q2*q2_Vbci; + xvar2=pow(xvar1,p[89]); + xvar2_xvar1=xvar2*p[89]/xvar1; + xvar2_Vbei=xvar2_xvar1*xvar1_Vbei; + xvar2_Vbci=xvar2_xvar1*xvar1_Vbci; + qb=0.5*q1*(1.0+xvar2); + qb_q1=0.5*(xvar2+1.0); + qb_xvar2=0.5*q1; + qb_Vbei=qb_q1*q1_Vbei; + qb_Vbci=qb_q1*q1_Vbci; + qb_Vbei=qb_Vbei+qb_xvar2*xvar2_Vbei; + qb_Vbci=qb_Vbci+qb_xvar2*xvar2_Vbci; + } + (*Itzr)=Iri/qb; + Itzr_Iri=1.0/qb; + Itzr_qb=-Iri/(qb*qb); + *Itzr_Vbci=Itzr_Iri*Iri_Vbci; + *Itzr_Vbei=Itzr_qb*qb_Vbei; + *Itzr_Vbci=(*Itzr_Vbci)+Itzr_qb*qb_Vbci; + (*Itzf)=Ifi/qb; + Itzf_Ifi=1.0/qb; + Itzf_qb=-Ifi/(qb*qb); + *Itzf_Vbei=Itzf_Ifi*Ifi_Vbei; + *Itzf_Vbei=(*Itzf_Vbei)+Itzf_qb*qb_Vbei; + *Itzf_Vbci=Itzf_qb*qb_Vbci; + if(p[42]>0.0){ + argi=(*Vbep)/(p[44]*Vtv); + argi_Vbep=1.0/(p[44]*Vtv); + expi=exp(argi); + expi_argi=expi; + expi_Vbep=expi_argi*argi_Vbep; + argx=(*Vbci)/(p[44]*Vtv); + argx_Vbci=1.0/(p[44]*Vtv); + expx=exp(argx); + expx_argx=expx; + expx_Vbci=expx_argx*argx_Vbci; + Ifp=p[42]*(p[43]*expi+(1.0-p[43])*expx-1.0); + Ifp_expi=p[42]*p[43]; + Ifp_expx=p[42]*(1.0-p[43]); + Ifp_Vbep=Ifp_expi*expi_Vbep; + Ifp_Vbci=Ifp_expx*expx_Vbci; + q2p=Ifp*IIKP; + q2p_Ifp=IIKP; + q2p_Vbep=q2p_Ifp*Ifp_Vbep; + q2p_Vbci=q2p_Ifp*Ifp_Vbci; + qbp=0.5*(1.0+sqrt(1.0+4.0*q2p)); + qbp_q2p=1.0/sqrt(4.0*q2p+1.0); + qbp_Vbep=qbp_q2p*q2p_Vbep; + qbp_Vbci=qbp_q2p*q2p_Vbci; + argi=(*Vbcp)/(p[44]*Vtv); + argi_Vbcp=1.0/(p[44]*Vtv); + expi=exp(argi); + expi_argi=expi; + expi_Vbcp=expi_argi*argi_Vbcp; + Irp=p[42]*(expi-1.0); + Irp_expi=p[42]; + Irp_Vbcp=Irp_expi*expi_Vbcp; + (*Iccp)=(Ifp-Irp)/qbp; + Iccp_Ifp=1.0/qbp; + Iccp_Irp=-1.0/qbp; + Iccp_qbp=-(Ifp-Irp)/(qbp*qbp); + *Iccp_Vbep=Iccp_Ifp*Ifp_Vbep; + *Iccp_Vbci=Iccp_Ifp*Ifp_Vbci; + *Iccp_Vbcp=Iccp_Irp*Irp_Vbcp; + *Iccp_Vbep=(*Iccp_Vbep)+Iccp_qbp*qbp_Vbep; + *Iccp_Vbci=(*Iccp_Vbci)+Iccp_qbp*qbp_Vbci; + }else{ + Ifp=0.0; + Ifp_Vbep=0.0; + Ifp_Vbci=0.0; + qbp=1.0; + qbp_Vbep=0.0; + qbp_Vbci=0.0; + (*Iccp)=0.0; + *Iccp_Vbep=0.0; + *Iccp_Vbci=0.0; + *Iccp_Vbcp=0.0; + } + if(p[32]==1.0){ + argi=(*Vbei)/(p[33]*Vtv); + argi_Vbei=1.0/(p[33]*Vtv); + expi=exp(argi); + expi_argi=expi; + expi_Vbei=expi_argi*argi_Vbei; + argn=(*Vbei)/(p[35]*Vtv); + argn_Vbei=1.0/(p[35]*Vtv); + expn=exp(argn); + expn_argn=expn; + expn_Vbei=expn_argn*argn_Vbei; + if(p[98]>0.0){ + argx=(-p[98]-(*Vbei))/(p[99]*Vtv); + argx_Vbei=-1.0/(p[99]*Vtv); + expx=exp(argx); + expx_argx=expx; + expx_Vbei=expx_argx*argx_Vbei; + (*Ibe)=p[31]*(expi-1.0)+p[34]*(expn-1.0)-p[100]*(expx-p[104]); + Ibe_expi=p[31]; + Ibe_expn=p[34]; + Ibe_expx=-p[100]; + *Ibe_Vbei=Ibe_expi*expi_Vbei; + *Ibe_Vbei=(*Ibe_Vbei)+Ibe_expn*expn_Vbei; + *Ibe_Vbei=(*Ibe_Vbei)+Ibe_expx*expx_Vbei; + }else{ + (*Ibe)=p[31]*(expi-1.0)+p[34]*(expn-1.0); + Ibe_expi=p[31]; + Ibe_expn=p[34]; + *Ibe_Vbei=Ibe_expi*expi_Vbei; + *Ibe_Vbei=(*Ibe_Vbei)+Ibe_expn*expn_Vbei; + } + (*Ibex)=0.0; + *Ibex_Vbex=0.0; + }else if(p[32]==0.0){ + (*Ibe)=0.0; + *Ibe_Vbei=0.0; + argi=(*Vbex)/(p[33]*Vtv); + argi_Vbex=1.0/(p[33]*Vtv); + expi=exp(argi); + expi_argi=expi; + expi_Vbex=expi_argi*argi_Vbex; + argn=(*Vbex)/(p[35]*Vtv); + argn_Vbex=1.0/(p[35]*Vtv); + expn=exp(argn); + expn_argn=expn; + expn_Vbex=expn_argn*argn_Vbex; + if(p[98]>0.0){ + argx=(-p[98]-(*Vbex))/(p[99]*Vtv); + argx_Vbex=-1.0/(p[99]*Vtv); + expx=exp(argx); + expx_argx=expx; + expx_Vbex=expx_argx*argx_Vbex; + (*Ibex)=p[31]*(expi-1.0)+p[34]*(expn-1.0)-p[100]*(expx-p[104]); + Ibex_expi=p[31]; + Ibex_expn=p[34]; + Ibex_expx=-p[100]; + *Ibex_Vbex=Ibex_expi*expi_Vbex; + *Ibex_Vbex=(*Ibex_Vbex)+Ibex_expn*expn_Vbex; + *Ibex_Vbex=(*Ibex_Vbex)+Ibex_expx*expx_Vbex; + }else{ + (*Ibex)=p[31]*(expi-1.0)+p[34]*(expn-1.0); + Ibex_expi=p[31]; + Ibex_expn=p[34]; + *Ibex_Vbex=Ibex_expi*expi_Vbex; + *Ibex_Vbex=(*Ibex_Vbex)+Ibex_expn*expn_Vbex; + } + }else{ + argi=(*Vbei)/(p[33]*Vtv); + argi_Vbei=1.0/(p[33]*Vtv); + expi=exp(argi); + expi_argi=expi; + expi_Vbei=expi_argi*argi_Vbei; + argn=(*Vbei)/(p[35]*Vtv); + argn_Vbei=1.0/(p[35]*Vtv); + expn=exp(argn); + expn_argn=expn; + expn_Vbei=expn_argn*argn_Vbei; + if(p[98]>0.0){ + argx=(-p[98]-(*Vbei))/(p[99]*Vtv); + argx_Vbei=-1.0/(p[99]*Vtv); + expx=exp(argx); + expx_argx=expx; + expx_Vbei=expx_argx*argx_Vbei; + (*Ibe)=p[32]*(p[31]*(expi-1.0)+p[34]*(expn-1.0)-p[100]*(expx-p[104])); + Ibe_expi=p[31]*p[32]; + Ibe_expn=p[34]*p[32]; + Ibe_expx=-p[100]*p[32]; + *Ibe_Vbei=Ibe_expi*expi_Vbei; + *Ibe_Vbei=(*Ibe_Vbei)+Ibe_expn*expn_Vbei; + *Ibe_Vbei=(*Ibe_Vbei)+Ibe_expx*expx_Vbei; + }else{ + (*Ibe)=p[32]*(p[31]*(expi-1.0)+p[34]*(expn-1.0)); + Ibe_expi=p[31]*p[32]; + Ibe_expn=p[34]*p[32]; + *Ibe_Vbei=Ibe_expi*expi_Vbei; + *Ibe_Vbei=(*Ibe_Vbei)+Ibe_expn*expn_Vbei; + } + argi=(*Vbex)/(p[33]*Vtv); + argi_Vbex=1.0/(p[33]*Vtv); + expi=exp(argi); + expi_argi=expi; + expi_Vbex=expi_argi*argi_Vbex; + argn=(*Vbex)/(p[35]*Vtv); + argn_Vbex=1.0/(p[35]*Vtv); + expn=exp(argn); + expn_argn=expn; + expn_Vbex=expn_argn*argn_Vbex; + if(p[98]>0.0){ + argx=(-p[98]-(*Vbex))/(p[99]*Vtv); + argx_Vbex=-1.0/(p[99]*Vtv); + expx=exp(argx); + expx_argx=expx; + expx_Vbex=expx_argx*argx_Vbex; + (*Ibex)=(1.0-p[32])*(p[31]*(expi-1.0)+p[34]*(expn-1.0)-p[100]*(expx-p[104])); + Ibex_expi=p[31]*(1.0-p[32]); + Ibex_expn=p[34]*(1.0-p[32]); + Ibex_expx=-p[100]*(1.0-p[32]); + *Ibex_Vbex=Ibex_expi*expi_Vbex; + *Ibex_Vbex=(*Ibex_Vbex)+Ibex_expn*expn_Vbex; + *Ibex_Vbex=(*Ibex_Vbex)+Ibex_expx*expx_Vbex; + }else{ + (*Ibex)=(1.0-p[32])*(p[31]*(expi-1.0)+p[34]*(expn-1.0)); + Ibex_expi=p[31]*(1.0-p[32]); + Ibex_expn=p[34]*(1.0-p[32]); + *Ibex_Vbex=Ibex_expi*expi_Vbex; + *Ibex_Vbex=(*Ibex_Vbex)+Ibex_expn*expn_Vbex; + } + } + argi=(*Vbci)/(p[37]*Vtv); + argi_Vbci=1.0/(p[37]*Vtv); + expi=exp(argi); + expi_argi=expi; + expi_Vbci=expi_argi*argi_Vbci; + argn=(*Vbci)/(p[39]*Vtv); + argn_Vbci=1.0/(p[39]*Vtv); + expn=exp(argn); + expn_argn=expn; + expn_Vbci=expn_argn*argn_Vbci; + Ibcj=p[36]*(expi-1.0)+p[38]*(expn-1.0); + Ibcj_expi=p[36]; + Ibcj_expn=p[38]; + Ibcj_Vbci=Ibcj_expi*expi_Vbci; + Ibcj_Vbci=Ibcj_Vbci+Ibcj_expn*expn_Vbci; + if((p[45]>0.0)||(p[46]>0.0)){ + argi=(*Vbep)/(p[37]*Vtv); + argi_Vbep=1.0/(p[37]*Vtv); + expi=exp(argi); + expi_argi=expi; + expi_Vbep=expi_argi*argi_Vbep; + argn=(*Vbep)/(p[39]*Vtv); + argn_Vbep=1.0/(p[39]*Vtv); + expn=exp(argn); + expn_argn=expn; + expn_Vbep=expn_argn*argn_Vbep; + (*Ibep)=p[45]*(expi-1.0)+p[46]*(expn-1.0); + Ibep_expi=p[45]; + Ibep_expn=p[46]; + *Ibep_Vbep=Ibep_expi*expi_Vbep; + *Ibep_Vbep=(*Ibep_Vbep)+Ibep_expn*expn_Vbep; + }else{ + (*Ibep)=0.0; + *Ibep_Vbep=0.0; + } + if(p[40]>0.0){ + vl=0.5*(sqrt((p[24]-(*Vbci))*(p[24]-(*Vbci))+0.01)+(p[24]-(*Vbci))); + vl_Vbci=0.5*(-(p[24]-(*Vbci))/sqrt(((p[24]-(*Vbci))*(p[24]-(*Vbci)))+0.01)-1.0); + xvar2=(p[25]-1.0); + xvar3=pow(vl,xvar2); + xvar3_vl=xvar3*xvar2/vl; + xvar3_Vbci=xvar3_vl*vl_Vbci; + xvar1=-p[41]*xvar3; + xvar1_xvar3=-p[41]; + xvar1_Vbci=xvar1_xvar3*xvar3_Vbci; + xvar4=exp(xvar1); + xvar4_xvar1=xvar4; + xvar4_Vbci=xvar4_xvar1*xvar1_Vbci; + avalf=p[40]*vl*xvar4; + avalf_vl=p[40]*xvar4; + avalf_xvar4=p[40]*vl; + avalf_Vbci=avalf_vl*vl_Vbci; + avalf_Vbci=avalf_Vbci+avalf_xvar4*xvar4_Vbci; + Igc=((*Itzf)-(*Itzr)-Ibcj)*avalf; + Igc_Itzf=avalf; + Igc_Itzr=-avalf; + Igc_Ibcj=-avalf; + Igc_avalf=-(*Itzr)+(*Itzf)-Ibcj; + Igc_Vbei=Igc_Itzf*(*Itzf_Vbei); + Igc_Vbci=Igc_Itzf*(*Itzf_Vbci); + Igc_Vbci=Igc_Vbci+Igc_Itzr*(*Itzr_Vbci); + Igc_Vbei=Igc_Vbei+Igc_Itzr*(*Itzr_Vbei); + Igc_Vbci=Igc_Vbci+Igc_Ibcj*Ibcj_Vbci; + Igc_Vbci=Igc_Vbci+Igc_avalf*avalf_Vbci; + }else{ + Igc=0.0; + Igc_Vbei=0.0; + Igc_Vbci=0.0; + } + (*Ibc)=Ibcj-Igc; + Ibc_Ibcj=1.0; + Ibc_Igc=-1.0; + *Ibc_Vbci=Ibc_Ibcj*Ibcj_Vbci; + *Ibc_Vbei=Ibc_Igc*Igc_Vbei; + *Ibc_Vbci=(*Ibc_Vbci)+Ibc_Igc*Igc_Vbci; + if(p[1]>0.0){ + (*Ircx)=(*Vrcx)/p[1]; + *Ircx_Vrcx=1.0/p[1]; + }else{ + (*Ircx)=0.0; + *Ircx_Vrcx=0.0; + } + argi=(*Vbci)/Vtv; + argi_Vbci=1.0/Vtv; + expi=exp(argi); + expi_argi=expi; + expi_Vbci=expi_argi*argi_Vbci; + argx=(*Vbcx)/Vtv; + argx_Vbcx=1.0/Vtv; + expx=exp(argx); + expx_argx=expx; + expx_Vbcx=expx_argx*argx_Vbcx; + Kbci=sqrt(1.0+p[4]*expi); + Kbci_expi=p[4]/(2.0*sqrt(expi*p[4]+1.0)); + Kbci_Vbci=Kbci_expi*expi_Vbci; + Kbcx=sqrt(1.0+p[4]*expx); + Kbcx_expx=p[4]/(2.0*sqrt(expx*p[4]+1.0)); + Kbcx_Vbcx=Kbcx_expx*expx_Vbcx; + if(p[2]>0.0){ + rKp1=(Kbci+1.0)/(Kbcx+1.0); + rKp1_Kbci=1.0/(Kbcx+1.0); + rKp1_Kbcx=-(Kbci+1.0)/((Kbcx+1.0)*(Kbcx+1.0)); + rKp1_Vbci=rKp1_Kbci*Kbci_Vbci; + rKp1_Vbcx=rKp1_Kbcx*Kbcx_Vbcx; + xvar1=log(rKp1); + xvar1_rKp1=1.0/rKp1; + xvar1_Vbci=xvar1_rKp1*rKp1_Vbci; + xvar1_Vbcx=xvar1_rKp1*rKp1_Vbcx; + Iohm=((*Vrci)+Vtv*(Kbci-Kbcx-xvar1))/p[2]; + Iohm_Vrci=1.0/p[2]; + Iohm_Kbci=Vtv/p[2]; + Iohm_Kbcx=-Vtv/p[2]; + Iohm_xvar1=-Vtv/p[2]; + Iohm_Vbci=Iohm_Kbci*Kbci_Vbci; + Iohm_Vbcx=Iohm_Kbcx*Kbcx_Vbcx; + Iohm_Vbci=Iohm_Vbci+Iohm_xvar1*xvar1_Vbci; + Iohm_Vbcx=Iohm_Vbcx+Iohm_xvar1*xvar1_Vbcx; + derf=IVO*p[2]*Iohm/(1.0+0.5*IVO*IHRCF*sqrt((*Vrci)*(*Vrci)+0.01)); + derf_Iohm=IVO*p[2]/(0.5*IHRCF*IVO*sqrt(((*Vrci)*(*Vrci))+0.01)+1.0); + derf_Vrci=-0.5*IHRCF*Iohm*(IVO*IVO)*p[2]*(*Vrci)/(sqrt(((*Vrci)*(*Vrci))+0.01)*((0.5*IHRCF*IVO*sqrt(((*Vrci)*(*Vrci))+0.01)+1.0)*(0.5*IHRCF*IVO*sqrt(((*Vrci)*(*Vrci))+0.01)+1.0))); + derf_Vrci=derf_Vrci+derf_Iohm*Iohm_Vrci; + derf_Vbci=derf_Iohm*Iohm_Vbci; + derf_Vbcx=derf_Iohm*Iohm_Vbcx; + (*Irci)=Iohm/sqrt(1.0+derf*derf); + Irci_Iohm=1.0/sqrt((derf*derf)+1.0); + Irci_derf=-derf*Iohm/pow(((derf*derf)+1.0),(3.0/2.0)); + *Irci_Vrci=Irci_Iohm*Iohm_Vrci; + *Irci_Vbci=Irci_Iohm*Iohm_Vbci; + *Irci_Vbcx=Irci_Iohm*Iohm_Vbcx; + *Irci_Vrci=(*Irci_Vrci)+Irci_derf*derf_Vrci; + *Irci_Vbci=(*Irci_Vbci)+Irci_derf*derf_Vbci; + *Irci_Vbcx=(*Irci_Vbcx)+Irci_derf*derf_Vbcx; + }else{ + (*Irci)=0.0; + *Irci_Vrci=0.0; + *Irci_Vbci=0.0; + *Irci_Vbcx=0.0; + } + if(p[6]>0.0){ + (*Irbx)=(*Vrbx)/p[6]; + *Irbx_Vrbx=1.0/p[6]; + }else{ + (*Irbx)=0.0; + *Irbx_Vrbx=0.0; + } + if(p[7]>0.0){ + (*Irbi)=(*Vrbi)*qb/p[7]; + *Irbi_Vrbi=qb/p[7]; + Irbi_qb=(*Vrbi)/p[7]; + *Irbi_Vbei=Irbi_qb*qb_Vbei; + *Irbi_Vbci=Irbi_qb*qb_Vbci; + }else{ + (*Irbi)=0.0; + *Irbi_Vrbi=0.0; + *Irbi_Vbei=0.0; + *Irbi_Vbci=0.0; + } + if(p[8]>0.0){ + (*Ire)=(*Vre)/p[8]; + *Ire_Vre=1.0/p[8]; + }else{ + (*Ire)=0.0; + *Ire_Vre=0.0; + } + if(p[10]>0.0){ + (*Irbp)=(*Vrbp)*qbp/p[10]; + *Irbp_Vrbp=qbp/p[10]; + Irbp_qbp=(*Vrbp)/p[10]; + *Irbp_Vbep=Irbp_qbp*qbp_Vbep; + *Irbp_Vbci=Irbp_qbp*qbp_Vbci; + }else{ + (*Irbp)=0.0; + *Irbp_Vrbp=0.0; + *Irbp_Vbep=0.0; + *Irbp_Vbci=0.0; + } + if((p[47]>0.0)||(p[49]>0.0)){ + argi=(*Vbcp)/(p[48]*Vtv); + argi_Vbcp=1.0/(p[48]*Vtv); + expi=exp(argi); + expi_argi=expi; + expi_Vbcp=expi_argi*argi_Vbcp; + argn=(*Vbcp)/(p[50]*Vtv); + argn_Vbcp=1.0/(p[50]*Vtv); + expn=exp(argn); + expn_argn=expn; + expn_Vbcp=expn_argn*argn_Vbcp; + (*Ibcp)=p[47]*(expi-1.0)+p[49]*(expn-1.0); + Ibcp_expi=p[47]; + Ibcp_expn=p[49]; + *Ibcp_Vbcp=Ibcp_expi*expi_Vbcp; + *Ibcp_Vbcp=(*Ibcp_Vbcp)+Ibcp_expn*expn_Vbcp; + }else{ + (*Ibcp)=0.0; + *Ibcp_Vbcp=0.0; + } + if(p[9]>0.0){ + (*Irs)=(*Vrs)/p[9]; + *Irs_Vrs=1.0/p[9]; + }else{ + (*Irs)=0.0; + *Irs_Vrs=0.0; + } + if(Ifi>0.0){ + sgIf=1.0; + }else{ + sgIf=0.0; + } + rIf=Ifi*sgIf*IITF; + rIf_Ifi=IITF*sgIf; + rIf_Vbei=rIf_Ifi*Ifi_Vbei; + mIf=rIf/(rIf+1.0); + mIf_rIf=1.0/(rIf+1.0)-rIf/((rIf+1.0)*(rIf+1.0)); + mIf_Vbei=mIf_rIf*rIf_Vbei; + xvar1=(*Vbci)*IVTF/1.44; + xvar1_Vbci=0.6944444*IVTF; + xvar2=exp(xvar1); + xvar2_xvar1=xvar2; + xvar2_Vbci=xvar2_xvar1*xvar1_Vbci; + tff=p[56]*(1.0+p[57]*q1)*(1.0+p[58]*xvar2*(slTF+mIf*mIf)*sgIf); + tff_q1=p[57]*p[56]*(sgIf*(slTF+(mIf*mIf))*p[58]*xvar2+1.0); + tff_xvar2=(q1*p[57]+1.0)*sgIf*(slTF+(mIf*mIf))*p[56]*p[58]; + tff_mIf=2.0*mIf*(q1*p[57]+1.0)*sgIf*p[56]*p[58]*xvar2; + tff_Vbei=tff_q1*q1_Vbei; + tff_Vbci=tff_q1*q1_Vbci; + tff_Vbci=tff_Vbci+tff_xvar2*xvar2_Vbci; + tff_Vbei=tff_Vbei+tff_mIf*mIf_Vbei; + (*Qbe)=p[16]*qdbe*p[32]+tff*Ifi/qb; + Qbe_qdbe=p[16]*p[32]; + Qbe_tff=Ifi/qb; + Qbe_Ifi=tff/qb; + Qbe_qb=-Ifi*tff/(qb*qb); + *Qbe_Vbei=Qbe_qdbe*qdbe_Vbei; + *Qbe_Vbei=(*Qbe_Vbei)+Qbe_tff*tff_Vbei; + *Qbe_Vbci=Qbe_tff*tff_Vbci; + *Qbe_Vbei=(*Qbe_Vbei)+Qbe_Ifi*Ifi_Vbei; + *Qbe_Vbei=(*Qbe_Vbei)+Qbe_qb*qb_Vbei; + *Qbe_Vbci=(*Qbe_Vbci)+Qbe_qb*qb_Vbci; + (*Qbex)=p[16]*qdbex*(1.0-p[32]); + Qbex_qdbex=p[16]*(1.0-p[32]); + *Qbex_Vbex=Qbex_qdbex*qdbex_Vbex; + (*Qbc)=p[21]*qdbc+p[61]*Iri+p[22]*Kbci; + Qbc_qdbc=p[21]; + Qbc_Iri=p[61]; + Qbc_Kbci=p[22]; + *Qbc_Vbci=Qbc_qdbc*qdbc_Vbci; + *Qbc_Vbci=(*Qbc_Vbci)+Qbc_Iri*Iri_Vbci; + *Qbc_Vbci=(*Qbc_Vbci)+Qbc_Kbci*Kbci_Vbci; + (*Qbcx)=p[22]*Kbcx; + Qbcx_Kbcx=p[22]; + *Qbcx_Vbcx=Qbcx_Kbcx*Kbcx_Vbcx; + (*Qbep)=p[23]*qdbep+p[61]*Ifp; + Qbep_qdbep=p[23]; + Qbep_Ifp=p[61]; + *Qbep_Vbep=Qbep_qdbep*qdbep_Vbep; + *Qbep_Vbep=(*Qbep_Vbep)+Qbep_Ifp*Ifp_Vbep; + *Qbep_Vbci=Qbep_Ifp*Ifp_Vbci; + (*Qbcp)=p[27]*qdbcp+p[87]*(*Vbcp); + Qbcp_qdbcp=p[27]; + *Qbcp_Vbcp=p[87]; + *Qbcp_Vbcp=(*Qbcp_Vbcp)+Qbcp_qdbcp*qdbcp_Vbcp; + (*Qbeo)=(*Vbe)*p[15]; + *Qbeo_Vbe=p[15]; + (*Qbco)=(*Vbc)*p[20]; + *Qbco_Vbc=p[20]; + +/* Scale outputs */ + + if((*SCALE)!=1.0){ + *Ibe=(*SCALE)*(*Ibe); + *Ibe_Vbei=(*SCALE)*(*Ibe_Vbei); + *Ibex=(*SCALE)*(*Ibex); + *Ibex_Vbex=(*SCALE)*(*Ibex_Vbex); + *Itzf=(*SCALE)*(*Itzf); + *Itzf_Vbei=(*SCALE)*(*Itzf_Vbei); + *Itzf_Vbci=(*SCALE)*(*Itzf_Vbci); + *Itzr=(*SCALE)*(*Itzr); + *Itzr_Vbci=(*SCALE)*(*Itzr_Vbci); + *Itzr_Vbei=(*SCALE)*(*Itzr_Vbei); + *Ibc=(*SCALE)*(*Ibc); + *Ibc_Vbci=(*SCALE)*(*Ibc_Vbci); + *Ibc_Vbei=(*SCALE)*(*Ibc_Vbei); + *Ibep=(*SCALE)*(*Ibep); + *Ibep_Vbep=(*SCALE)*(*Ibep_Vbep); + *Ircx=(*SCALE)*(*Ircx); + *Ircx_Vrcx=(*SCALE)*(*Ircx_Vrcx); + *Irci=(*SCALE)*(*Irci); + *Irci_Vrci=(*SCALE)*(*Irci_Vrci); + *Irci_Vbci=(*SCALE)*(*Irci_Vbci); + *Irci_Vbcx=(*SCALE)*(*Irci_Vbcx); + *Irbx=(*SCALE)*(*Irbx); + *Irbx_Vrbx=(*SCALE)*(*Irbx_Vrbx); + *Irbi=(*SCALE)*(*Irbi); + *Irbi_Vrbi=(*SCALE)*(*Irbi_Vrbi); + *Irbi_Vbei=(*SCALE)*(*Irbi_Vbei); + *Irbi_Vbci=(*SCALE)*(*Irbi_Vbci); + *Ire=(*SCALE)*(*Ire); + *Ire_Vre=(*SCALE)*(*Ire_Vre); + *Irbp=(*SCALE)*(*Irbp); + *Irbp_Vrbp=(*SCALE)*(*Irbp_Vrbp); + *Irbp_Vbep=(*SCALE)*(*Irbp_Vbep); + *Irbp_Vbci=(*SCALE)*(*Irbp_Vbci); + *Qbe=(*SCALE)*(*Qbe); + *Qbe_Vbei=(*SCALE)*(*Qbe_Vbei); + *Qbe_Vbci=(*SCALE)*(*Qbe_Vbci); + *Qbex=(*SCALE)*(*Qbex); + *Qbex_Vbex=(*SCALE)*(*Qbex_Vbex); + *Qbc=(*SCALE)*(*Qbc); + *Qbc_Vbci=(*SCALE)*(*Qbc_Vbci); + *Qbcx=(*SCALE)*(*Qbcx); + *Qbcx_Vbcx=(*SCALE)*(*Qbcx_Vbcx); + *Qbep=(*SCALE)*(*Qbep); + *Qbep_Vbep=(*SCALE)*(*Qbep_Vbep); + *Qbep_Vbci=(*SCALE)*(*Qbep_Vbci); + *Qbeo=(*SCALE)*(*Qbeo); + *Qbeo_Vbe=(*SCALE)*(*Qbeo_Vbe); + *Qbco=(*SCALE)*(*Qbco); + *Qbco_Vbc=(*SCALE)*(*Qbco_Vbc); + *Ibcp=(*SCALE)*(*Ibcp); + *Ibcp_Vbcp=(*SCALE)*(*Ibcp_Vbcp); + *Iccp=(*SCALE)*(*Iccp); + *Iccp_Vbep=(*SCALE)*(*Iccp_Vbep); + *Iccp_Vbci=(*SCALE)*(*Iccp_Vbci); + *Iccp_Vbcp=(*SCALE)*(*Iccp_Vbcp); + *Irs=(*SCALE)*(*Irs); + *Irs_Vrs=(*SCALE)*(*Irs_Vrs); + *Qbcp=(*SCALE)*(*Qbcp); + *Qbcp_Vbcp=(*SCALE)*(*Qbcp_Vbcp); + } + return(0); +} diff --git a/src/spicelib/devices/vbic/vbicmask.c b/src/spicelib/devices/vbic/vbicmask.c index 757ee7771..54d7e07f6 100644 --- a/src/spicelib/devices/vbic/vbicmask.c +++ b/src/spicelib/devices/vbic/vbicmask.c @@ -225,15 +225,9 @@ VBICmAsk(CKTcircuit *ckt, GENmodel *instPtr, int which, IFvalue *value) case VBIC_MOD_XRE: value->rValue = here->VBICtempExpRE; return(OK); - case VBIC_MOD_XRB: - value->rValue = here->VBICtempExpRB; - return(OK); case VBIC_MOD_XRBI: value->rValue = here->VBICtempExpRBI; return(OK); - case VBIC_MOD_XRC: - value->rValue = here->VBICtempExpRC; - return(OK); case VBIC_MOD_XRCI: value->rValue = here->VBICtempExpRCI; return(OK); diff --git a/src/spicelib/devices/vbic/vbicmpar.c b/src/spicelib/devices/vbic/vbicmpar.c index cac58ad3f..38e1339dd 100644 --- a/src/spicelib/devices/vbic/vbicmpar.c +++ b/src/spicelib/devices/vbic/vbicmpar.c @@ -325,18 +325,10 @@ VBICmParam(int param, IFvalue *value, GENmodel *inModel) mods->VBICtempExpRE = value->rValue; mods->VBICtempExpREGiven = TRUE; break; - case VBIC_MOD_XRB: - mods->VBICtempExpRB = value->rValue; - mods->VBICtempExpRBGiven = TRUE; - break; case VBIC_MOD_XRBI: mods->VBICtempExpRBI = value->rValue; mods->VBICtempExpRBIGiven = TRUE; break; - case VBIC_MOD_XRC: - mods->VBICtempExpRC = value->rValue; - mods->VBICtempExpRCGiven = TRUE; - break; case VBIC_MOD_XRCI: mods->VBICtempExpRCI = value->rValue; mods->VBICtempExpRCIGiven = TRUE; diff --git a/src/spicelib/devices/vbic/vbicsetup.c b/src/spicelib/devices/vbic/vbicsetup.c index e679fcf74..c82f36871 100644 --- a/src/spicelib/devices/vbic/vbicsetup.c +++ b/src/spicelib/devices/vbic/vbicsetup.c @@ -5,7 +5,7 @@ Model Author: 1995 Colin McAndrew Motorola Spice3 Implementation: 2003 Dietmar Warning DAnalyse GmbH **********/ -/* +/* * This routine should only be called when circuit topology * changes, since its computations do not depend on most * device or model parameters, only on topology (as @@ -23,8 +23,8 @@ Spice3 Implementation: 2003 Dietmar Warning DAnalyse GmbH int VBICsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) - /* load the VBIC structure with those pointers needed later - * for fast matrix loading + /* load the VBIC structure with those pointers needed later + * for fast matrix loading */ { VBICmodel *model = (VBICmodel*)inModel; @@ -239,15 +239,9 @@ VBICsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) if(!model->VBICtempExpREGiven) { model->VBICtempExpRE = 0.0; } - if(!model->VBICtempExpRBGiven) { - model->VBICtempExpRB = 0.0; - } if(!model->VBICtempExpRBIGiven) { model->VBICtempExpRBI = 0.0; } - if(!model->VBICtempExpRCGiven) { - model->VBICtempExpRC = 0.0; - } if(!model->VBICtempExpRCIGiven) { model->VBICtempExpRCI = 0.0; } @@ -369,19 +363,6 @@ VBICsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) model->VBICrefVersion = 0.0; } - if(model->VBICtempExpRBGiven && !model->VBICtempExpRBIGiven) { - model->VBICtempExpRBI = model->VBICtempExpRB; - } - if(model->VBICtempExpRBGiven && !model->VBICtempExpRBXGiven) { - model->VBICtempExpRBX = model->VBICtempExpRB; - } - if(model->VBICtempExpRCGiven && !model->VBICtempExpRCIGiven) { - model->VBICtempExpRCI = model->VBICtempExpRC; - } - if(model->VBICtempExpRCGiven && !model->VBICtempExpRCXGiven) { - model->VBICtempExpRCX = model->VBICtempExpRC; - } - if(!model->VBICvbeMaxGiven) { model->VBICvbeMax = 1e99; } @@ -435,8 +416,8 @@ VBICsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) if (ckt->CKTcopyNodesets) { if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) { if (tmpNode->nsGiven) { - tmp->nodeset=tmpNode->nodeset; - tmp->nsGiven=tmpNode->nsGiven; + tmp->nodeset=tmpNode->nodeset; + tmp->nsGiven=tmpNode->nsGiven; } } } @@ -450,8 +431,8 @@ VBICsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) if (ckt->CKTcopyNodesets) { if (CKTinst2Node(ckt,here,2,&tmpNode,&tmpName)==OK) { if (tmpNode->nsGiven) { - tmp->nodeset=tmpNode->nodeset; - tmp->nsGiven=tmpNode->nsGiven; + tmp->nodeset=tmpNode->nodeset; + tmp->nsGiven=tmpNode->nsGiven; } } } @@ -465,8 +446,8 @@ VBICsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) if (ckt->CKTcopyNodesets) { if (CKTinst2Node(ckt,here,3,&tmpNode,&tmpName)==OK) { if (tmpNode->nsGiven) { - tmp->nodeset=tmpNode->nodeset; - tmp->nsGiven=tmpNode->nsGiven; + tmp->nodeset=tmpNode->nodeset; + tmp->nsGiven=tmpNode->nsGiven; } } } @@ -480,8 +461,8 @@ VBICsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) if (ckt->CKTcopyNodesets) { if (CKTinst2Node(ckt,here,4,&tmpNode,&tmpName)==OK) { if (tmpNode->nsGiven) { - tmp->nodeset=tmpNode->nodeset; - tmp->nsGiven=tmpNode->nsGiven; + tmp->nodeset=tmpNode->nodeset; + tmp->nsGiven=tmpNode->nsGiven; } } } @@ -505,19 +486,19 @@ VBICsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) if(here->VBICcollCINode == 0) { error = CKTmkVolt(ckt, &tmp, here->VBICname, "collCI"); if(error) return(error); - here->VBICcollCINode = tmp->number; + here->VBICcollCINode = tmp->number; } if(here->VBICbaseBPNode == 0) { error = CKTmkVolt(ckt, &tmp, here->VBICname, "baseBP"); if(error) return(error); - here->VBICbaseBPNode = tmp->number; + here->VBICbaseBPNode = tmp->number; } if(here->VBICbaseBINode == 0) { error = CKTmkVolt(ckt, &tmp, here->VBICname, "baseBI"); if(error) return(error); - here->VBICbaseBINode = tmp->number; + here->VBICbaseBINode = tmp->number; } /* macro to make elements with built in test for out of memory */ diff --git a/src/spicelib/devices/vbic/vbictemp.c b/src/spicelib/devices/vbic/vbictemp.c index 9b35acdfe..84cb2121b 100644 --- a/src/spicelib/devices/vbic/vbictemp.c +++ b/src/spicelib/devices/vbic/vbictemp.c @@ -41,118 +41,11 @@ VBICtemp(GENmodel *inModel, CKTcircuit *ckt) if(here->VBICdtempGiven) here->VBICtemp = here->VBICtemp + here->VBICdtemp; TAMB = here->VBICtemp - CONSTCtoK; - - pnom[0] = model->VBICtnom; - pnom[1] = model->VBICextCollResist; - pnom[2] = model->VBICintCollResist; - pnom[3] = model->VBICepiSatVoltage; - pnom[4] = model->VBICepiDoping; - pnom[5] = model->VBIChighCurFac; - pnom[6] = model->VBICextBaseResist; - pnom[7] = model->VBICintBaseResist; - pnom[8] = model->VBICemitterResist; - pnom[9] = model->VBICsubstrateResist; - pnom[10] = model->VBICparBaseResist; - pnom[11] = model->VBICsatCur; - pnom[12] = model->VBICemissionCoeffF; - pnom[13] = model->VBICemissionCoeffR; - pnom[14] = model->VBICdeplCapLimitF; - pnom[15] = model->VBICextOverlapCapBE; - pnom[16] = model->VBICdepletionCapBE; - pnom[17] = model->VBICpotentialBE; - pnom[18] = model->VBICjunctionExpBE; - pnom[19] = model->VBICsmoothCapBE; - pnom[20] = model->VBICextOverlapCapBC; - pnom[21] = model->VBICdepletionCapBC; - pnom[22] = model->VBICepiCharge; - pnom[23] = model->VBICextCapBC; - pnom[24] = model->VBICpotentialBC; - pnom[25] = model->VBICjunctionExpBC; - pnom[26] = model->VBICsmoothCapBC; - pnom[27] = model->VBICextCapSC; - pnom[28] = model->VBICpotentialSC; - pnom[29] = model->VBICjunctionExpSC; - pnom[30] = model->VBICsmoothCapSC; - pnom[31] = model->VBICidealSatCurBE; - pnom[32] = model->VBICportionIBEI; - pnom[33] = model->VBICidealEmissCoeffBE; - pnom[34] = model->VBICnidealSatCurBE; - pnom[35] = model->VBICnidealEmissCoeffBE; - pnom[36] = model->VBICidealSatCurBC; - pnom[37] = model->VBICidealEmissCoeffBC; - pnom[38] = model->VBICnidealSatCurBC; - pnom[39] = model->VBICnidealEmissCoeffBC; - pnom[40] = model->VBICavalanchePar1BC; - pnom[41] = model->VBICavalanchePar2BC; - pnom[42] = model->VBICparasitSatCur; - pnom[43] = model->VBICportionICCP; - pnom[44] = model->VBICparasitFwdEmissCoeff; - pnom[45] = model->VBICidealParasitSatCurBE; - pnom[46] = model->VBICnidealParasitSatCurBE; - pnom[47] = model->VBICidealParasitSatCurBC; - pnom[48] = model->VBICidealParasitEmissCoeffBC; - pnom[49] = model->VBICnidealParasitSatCurBC; - pnom[50] = model->VBICnidealParasitEmissCoeffBC; - pnom[51] = model->VBICearlyVoltF; - pnom[52] = model->VBICearlyVoltR; - pnom[53] = model->VBICrollOffF; - pnom[54] = model->VBICrollOffR; - pnom[55] = model->VBICparRollOff; - pnom[56] = model->VBICtransitTimeF; - pnom[57] = model->VBICvarTransitTimeF; - pnom[58] = model->VBICtransitTimeBiasCoeffF; - pnom[59] = model->VBICtransitTimeFVBC; - pnom[60] = model->VBICtransitTimeHighCurrentF; - pnom[61] = model->VBICtransitTimeR; - pnom[62] = model->VBICdelayTimeF; - pnom[63] = model->VBICfNcoef; - pnom[64] = model->VBICfNexpA; - pnom[65] = model->VBICfNexpB; - pnom[66] = model->VBICtempExpRE; - pnom[67] = model->VBICtempExpRBI; - pnom[68] = model->VBICtempExpRCI; - pnom[69] = model->VBICtempExpRS; - pnom[70] = model->VBICtempExpVO; - pnom[71] = model->VBICactivEnergyEA; - pnom[72] = model->VBICactivEnergyEAIE; - pnom[73] = model->VBICactivEnergyEAIC; - pnom[74] = model->VBICactivEnergyEAIS; - pnom[75] = model->VBICactivEnergyEANE; - pnom[76] = model->VBICactivEnergyEANC; - pnom[77] = model->VBICactivEnergyEANS; - pnom[78] = model->VBICtempExpIS; - pnom[79] = model->VBICtempExpII; - pnom[80] = model->VBICtempExpIN; - pnom[81] = model->VBICtempExpNF; - pnom[82] = model->VBICtempExpAVC; - pnom[83] = model->VBICthermalResist; - pnom[84] = model->VBICthermalCapacitance; - pnom[85] = model->VBICpunchThroughVoltageBC; - pnom[86] = model->VBICdeplCapCoeff1; - pnom[87] = model->VBICfixedCapacitanceCS; - pnom[88] = model->VBICsgpQBselector; - pnom[89] = model->VBIChighCurrentBetaRolloff; - pnom[90] = model->VBICtempExpIKF; - pnom[91] = model->VBICtempExpRCX; - pnom[92] = model->VBICtempExpRBX; - pnom[93] = model->VBICtempExpRBP; - pnom[94] = model->VBICsepISRR; - pnom[95] = model->VBICtempExpXISR; - pnom[96] = model->VBICdear; - pnom[97] = model->VBICeap; - pnom[98] = model->VBICvbbe; - pnom[99] = model->VBICnbbe; - pnom[100] = model->VBICibbe; - pnom[101] = model->VBICtvbbe1; - pnom[102] = model->VBICtvbbe2; - pnom[103] = model->VBICtnbbe; - pnom[104] = model->VBICebbe; - pnom[105] = model->VBIClocTempDiff; - pnom[106] = model->VBICrevVersion; - pnom[107] = model->VBICrefVersion; - + + memcpy (&pnom, &model->VBICtnom, 108*8); + iret = vbic_4T_et_cf_t(p,pnom,&TAMB); - + here->VBICtextCollResist = p[1]; here->VBICtintCollResist = p[2]; here->VBICtepiSatVoltage = p[3]; diff --git a/visualc/sharedspice.vcxproj b/visualc/sharedspice.vcxproj index 78ef738c9..89bc0fbbe 100644 --- a/visualc/sharedspice.vcxproj +++ b/visualc/sharedspice.vcxproj @@ -433,6 +433,7 @@ + @@ -1045,6 +1046,7 @@ + diff --git a/visualc/vngspice-fftw.vcxproj b/visualc/vngspice-fftw.vcxproj index 51576a646..d44b3c013 100644 --- a/visualc/vngspice-fftw.vcxproj +++ b/visualc/vngspice-fftw.vcxproj @@ -881,6 +881,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 + @@ -1500,6 +1501,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 + diff --git a/visualc/vngspice.vcxproj b/visualc/vngspice.vcxproj index 3a951c090..f767965c8 100644 --- a/visualc/vngspice.vcxproj +++ b/visualc/vngspice.vcxproj @@ -889,6 +889,7 @@ + @@ -1507,6 +1508,7 @@ +