diff --git a/configure.ac b/configure.ac index 0ece75e57..1c5f7aafc 100644 --- a/configure.ac +++ b/configure.ac @@ -285,10 +285,6 @@ AC_ARG_ENABLE([expdevices], AC_ARG_ENABLE([ndev], [AS_HELP_STRING([--enable-ndev], [Enable NDEV interface, (experimental)])]) -# --enable-cluster: define CLUSTER in the code. This is for cluster support -AC_ARG_ENABLE([cluster], - [AS_HELP_STRING([--enable-cluster], [Enable cluster support, (experimental)])]) - # --enable-cmathtests: run the ancient tests in src/math/cmaths AC_ARG_ENABLE([cmathtests], [AS_HELP_STRING([--enable-cmathtests], [Enable ancient tests in src/math/cmaths])]) @@ -1244,14 +1240,6 @@ if test "x$enable_ndev" = xyes; then fi AM_CONDITIONAL([NDEV_WANTED], [test "x$enable_ndev" = xyes]) - -# Cluster option -if test "x$enable_cluster" = xyes; then - AC_MSG_RESULT([Cluster version is being compiled]) - AC_DEFINE([CLUSTER], [], [Spice cluster support]) - LIBS="$LIBS -lpthread" -fi - if test "x$enable_expdevices" = xyes; then AC_DEFINE([EXP_DEV], [], [Define if we want to enable experimental devices]) AC_MSG_RESULT([WARNING: Experimental devices enabled]) @@ -1440,7 +1428,6 @@ AC_CONFIG_FILES([Makefile src/xspice/mif/Makefile src/xspice/evt/Makefile src/xspice/enh/Makefile - src/xspice/ipc/Makefile src/xspice/idn/Makefile src/xspice/verilog/Makefile src/xspice/vhdl/Makefile diff --git a/examples/mos/ro_17_4.cir b/examples/mos/ro_17_4.cir index c4dccaa89..930ccb04a 100644 --- a/examples/mos/ro_17_4.cir +++ b/examples/mos/ro_17_4.cir @@ -42,33 +42,36 @@ mp17 2 18 1 1 p1 l=0.1u w=10u ad=5p pd=6u as=5p ps=6u mn17 2 18 0 0 n1 l=0.1u w=5u ad=5p pd=6u as=5p ps=6u c1 18 0 .1p -* .ic v(2)=1.0 v(3)=1.0 v(4)=1.0 -* .ic v(2)=2.0 v(3)=0.0 v(4)=2.0 -* .ic v(2)=2.0 v(3)=0.0 v(4)=2.0 v(5)=0.0 v(6)=2.0 -* .ic v(7)=0.0 v(8)=2.0 v(9)=0.0 v(10)=2.0 v(11)=0.0 v(12)=2.0 -* .ic v(13)=0.0 v(14)=2.0 v(15)=0.0 v(16)=2.0 v(17)=0.0 v(18)=2.0 -* .ic V(10)=5 v(2)=5 v(3)=5 v(4)=5 v(5)=5 v(6)=5 - -* .ic v(18)=1 - .tran .1ns 150ns uic -* .option xmu = 0.49 -* .print tran v(5) - .control * reduce current ringing option xmu = 0.49 -* set xmu=0.49 -set num_threads=8 set noinit -run +run ; temp is 27°C * current and output in a single plot plot v(18) 1000*(-I(vdd)) ylimit -1 6 +meas tran tdiff TRIG v(18) VAL=0.5 RISE=10 TARG v(18) VAL=0.5 RISE=20 +let freq = 10/tdiff +let delay = tdiff/17 +print freq delay +echo +echo + +set temp=100 +run ; temp is 100°C + +* current and output in a single plot +plot v(18) 1000*(-I(vdd)) ylimit -1 6 + +meas tran tdiff TRIG v(18) VAL=0.5 RISE=10 TARG v(18) VAL=0.5 RISE=20 +let freq = 10/tdiff +let delay = tdiff/17 +print freq delay .endc * Short channel models from CMOS Circuit Design, Layout, and Simulation, diff --git a/src/Makefile.am b/src/Makefile.am index aa2a49183..d1cedb9bf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -163,7 +163,6 @@ ngspice_LDADD += \ xspice/mif/libmifxsp.la \ xspice/evt/libevtxsp.la \ xspice/enh/libenhxsp.la \ - xspice/ipc/libipcxsp.la \ xspice/idn/libidnxsp.la endif ngspice_LDADD += $(XSPICEDLLIBS) @@ -459,7 +458,6 @@ if XSPICE_WANTED libspice_la_LIBADD += \ xspice/evt/libevtxsp.la \ xspice/enh/libenhxsp.la \ - xspice/ipc/libipcxsp.la \ xspice/idn/libidnxsp.la endif libspice_la_LIBADD += $(XSPICEDLLIBS) @@ -586,7 +584,6 @@ if XSPICE_WANTED libngspice_la_LIBADD += \ xspice/evt/libevtxsp.la \ xspice/enh/libenhxsp.la \ - xspice/ipc/libipcxsp.la \ xspice/idn/libidnxsp.la endif libngspice_la_LIBADD += $(XSPICEDLLIBS) diff --git a/src/frontend/device.c b/src/frontend/device.c index 0062bbeef..00cb3b881 100644 --- a/src/frontend/device.c +++ b/src/frontend/device.c @@ -1542,6 +1542,7 @@ com_alter_mod(wordlist *wl) if (modfile == NULL) { fprintf(cp_err, "Warning: Could not open file %s, altermod ignored\n", filename); + perror(" Cause: "); tfree(input); tfree(filename); return; diff --git a/src/frontend/inp.c b/src/frontend/inp.c index 56951b617..c689da971 100644 --- a/src/frontend/inp.c +++ b/src/frontend/inp.c @@ -244,13 +244,6 @@ inp_list(FILE *file, struct card *deck, struct card *extras, int type) bool useout = (file == cp_out); int i = 1; - /* gtri - wbk - 03/07/91 - Don't use 'more' type output if ipc enabled */ -#ifdef XSPICE - if (g_ipc.enabled) - useout = FALSE; -#endif - /* gtri - end - 03/07/91 */ - if (useout) { out_init(); file = cp_more; @@ -852,6 +845,7 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) #ifdef OSDI inputdir = dir_name; #endif + /* process each pre_xxx command */ cp_evloop(wl->wl_word); } @@ -1000,19 +994,21 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) tc->linenum, tc->line); } } - fprintf(fdo, "**************** uncommented deck **************\n\n"); - /* always print first line */ - fprintf(fdo, "%6s %6d %6d %s\n", deck->linesource, deck->linenum_orig, deck->linenum, deck->line); - /* here without out-commented lines */ - for (tc = deck->nextcard; tc; tc = tc->nextcard) { - if (*(tc->line) == '*') - continue; - fprintf(fdo, "%6s %6d %6d %s\n", tc->linesource, tc->linenum_orig, tc->linenum, tc->line); + if (!cp_getvar("debug-out-short", CP_BOOL, NULL, 0)) { + fprintf(fdo, "**************** uncommented deck **************\n\n"); + /* always print first line */ + fprintf(fdo, "%6s %6d %6d %s\n", deck->linesource, deck->linenum_orig, deck->linenum, deck->line); + /* here without out-commented lines */ + for (tc = deck->nextcard; tc; tc = tc->nextcard) { + if (*(tc->line) == '*') + continue; + fprintf(fdo, "%6s %6d %6d %s\n", tc->linesource, tc->linenum_orig, tc->linenum, tc->line); + } + fprintf(fdo, "\n****************** complete deck ***************\n\n"); + /* now completely */ + for (tc = deck; tc; tc = tc->nextcard) + fprintf(fdo, "%6s %6d %6d %s\n", tc->linesource, tc->linenum_orig, tc->linenum, tc->line); } - fprintf(fdo, "\n****************** complete deck ***************\n\n"); - /* now completely */ - for (tc = deck; tc; tc = tc->nextcard) - fprintf(fdo, "%6s %6d %6d %s\n", tc->linesource, tc->linenum_orig, tc->linenum, tc->line); fclose(fdo); } else @@ -1216,10 +1212,12 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) continue; fprintf(fdo, "%6d %6d %s\n", tc->linenum_orig, tc->linenum, tc->line); } - fprintf(fdo, "\n****************** complete deck ***************\n\n"); - /* now completely */ - for (tc = deck; tc; tc = tc->nextcard) - fprintf(fdo, "%6d %6d %s\n", tc->linenum_orig, tc->linenum, tc->line); + if (!cp_getvar("debug-out-short", CP_BOOL, NULL, 0)) { + fprintf(fdo, "\n****************** complete deck ***************\n\n"); + /* now completely */ + for (tc = deck; tc; tc = tc->nextcard) + fprintf(fdo, "%6d %6d %s\n", tc->linenum_orig, tc->linenum, tc->line); + } fclose(fdo); } else @@ -1474,10 +1472,6 @@ inp_dodeck( if (dd->error) { char *p, *q; -#ifdef XSPICE - /* add setting of ipc syntax error flag */ - g_ipc.syntax_error = IPC_TRUE; -#endif p = dd->error; fflush(stdout); do { diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 1f90d2732..c388d667e 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -583,6 +583,7 @@ static struct library *read_a_lib(const char *y, const char *dir_name) if (!newfp) { fprintf(cp_err, "Error: Could not open library file %s\n", y); + perror(" Cause: "); return NULL; } @@ -1256,32 +1257,35 @@ struct card *inp_readall(FILE *fp, const char *dir_name, const char* file_name, t->linenum, t->line); } } - fprintf(fd, - "\n\n**************** uncommented deck " - "**************\n\n"); - /* always print first line */ - fprintf(fd, "%6s %6d %6d %s\n", cc->linesource, cc->linenum_orig, cc->linenum, - cc->line); - /* here without out-commented lines */ - for (t = cc->nextcard; t; t = t->nextcard) { - if (*(t->line) == '*') - continue; - fprintf(fd, "%6s %6d %6d %s\n", - t->linesource, t->linenum_orig, t->linenum, t->line); - } - fprintf(fd, + if (!cp_getvar("debug-out-short", CP_BOOL, NULL, 0)) { + fprintf(fd, + "\n\n**************** uncommented deck " + "**************\n\n"); + /* always print first line */ + fprintf(fd, "%6s %6d %6d %s\n", cc->linesource, cc->linenum_orig, cc->linenum, + cc->line); + /* here without out-commented lines */ + for (t = cc->nextcard; t; t = t->nextcard) { + if (*(t->line) == '*') + continue; + fprintf(fd, "%6s %6d %6d %s\n", + t->linesource, t->linenum_orig, t->linenum, t->line); + } + fprintf(fd, "\n\n****************** complete deck " "***************\n\n"); - /* now completely */ - for (t = cc; t; t = t->nextcard) - fprintf(fd, "%6s %6d %6d %s\n", - t->linesource, t->linenum_orig,t->linenum, t->line); + /* now completely */ + for (t = cc; t; t = t->nextcard) + fprintf(fd, "%6s %6d %6d %s\n", + t->linesource, t->linenum_orig, t->linenum, t->line); + } fclose(fd); fprintf(stdout, - "max line length %d, max subst. per line %d, number " - "of lines %d\n", - (int) max_line_length, no_braces, dynmaxline); + "max line length %d, max subst. per line %d, number " + "of lines %d\n", + (int)max_line_length, no_braces, dynmaxline); + } else fprintf(stderr, @@ -1354,53 +1358,24 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name else { #ifdef XSPICE - /* gtri - modify - 12/12/90 - wbk - read from mailbox if ipc - * enabled */ - /* If IPC is not enabled, do equivalent of what SPICE did before - */ - if (!g_ipc.enabled) { - if (call_depth == 0 && line_count == 0) { - line_count++; - if (fgets(big_buff, 5000, fp)) - buffer = copy(big_buff); - } - else { - buffer = readline(fp); - if (!buffer) - break; - } + if (call_depth == 0 && line_count == 0) { + line_count++; + if (fgets(big_buff, 5000, fp)) + buffer = copy(big_buff); } else { - /* else, get the line from the ipc channel. */ - /* We assume that newlines are not sent by the client */ - /* so we add them here */ - char ipc_buffer[1025]; /* Had better be big enough */ - int ipc_len; - Ipc_Status_t ipc_status = - ipc_get_line(ipc_buffer, &ipc_len, IPC_WAIT); - if (ipc_status == IPC_STATUS_END_OF_DECK) { - buffer = NULL; + buffer = readline(fp); + if (!buffer) break; - } - else if (ipc_status == IPC_STATUS_OK) { - buffer = TMALLOC(char, strlen(ipc_buffer) + 3); - strcpy(buffer, ipc_buffer); - strcat(buffer, "\n"); - } - else { /* No good way to report this so just die */ - fprintf(stderr, "Error: IPC status not o.k.\n"); - controlled_exit(EXIT_FAILURE); - } } - /* gtri - end - 12/12/90 */ #else buffer = readline(fp); if (!buffer) { break; - } + } #endif } @@ -1564,6 +1539,7 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name else fprintf(cp_err, " While reading %s\n", y_resolved); } + perror(" Cause: "); tfree(buffer); /* allocated by readline() above */ controlled_exit(EXIT_FAILURE); } @@ -3473,7 +3449,7 @@ static void inp_stripcomments_deck(struct card *c, bool cf) found_control = TRUE; if (ciprefix(".endc", c->line)) found_control = FALSE; - inp_stripcomments_line(c->line, found_control | cf, FALSE); + inp_stripcomments_line(c->line, found_control || cf, FALSE); } } diff --git a/src/frontend/measure.c b/src/frontend/measure.c index b7b6680cc..4efd1d7bf 100644 --- a/src/frontend/measure.c +++ b/src/frontend/measure.c @@ -255,8 +255,10 @@ do_measure( if (cp_getvar("measoutfile", CP_STRING, out_file, sizeof(out_file))) { measout = fopen(out_file, "w"); - if (!measout) + if (!measout) { fprintf(stderr, " Warning: Could not open file %s\n", out_file); + perror(" Cause: "); + } } /* Evaluating the linked list of .meas cards, assembled from the input deck diff --git a/src/frontend/numparam/xpressn.c b/src/frontend/numparam/xpressn.c index ad0620983..ec1c55f8b 100644 --- a/src/frontend/numparam/xpressn.c +++ b/src/frontend/numparam/xpressn.c @@ -30,6 +30,7 @@ extern long dynsubst; /* see inpcom.c */ #define S_stop 4 static char* sort_idlist(char *list); +static char *string_expr(dico_t *, DSTRINGPTR, const char *, const char *); static double ternary_fcn(double conditional, double if_value, double else_value) @@ -83,23 +84,27 @@ limit(double nominal_val, double abs_variation) return (nominal_val + (drand() > 0 ? abs_variation : -1. * abs_variation)); } +/* The list of built-in functions. Patch 'mathfunction', here to get more ... + * Function "vec" and following take a string argument and must come last. + */ static const char *fmathS = /* all math functions */ "sqr sqrt sin cos exp ln arctan abs pow pwr max min int log log10 sinh cosh" " tanh ternary_fcn agauss sgn gauss unif aunif limit ceil floor" - " asin acos atan asinh acosh atanh tan nint"; + " asin acos atan asinh acosh atanh tan nint" + " vec var"; enum { XFU_SQR = 1, XFU_SQRT, XFU_SIN, XFU_COS, XFU_EXP, XFU_LN, XFU_ARCTAN, XFU_ABS, XFU_POW, XFU_PWR, XFU_MAX, XFU_MIN, XFU_INT, XFU_LOG, XFU_LOG10, XFU_SINH, XFU_COSH, XFU_TANH, XFU_TERNARY_FCN, XFU_AGAUSS, XFU_SGN, XFU_GAUSS, XFU_UNIF, XFU_AUNIF, XFU_LIMIT, XFU_CEIL, XFU_FLOOR, - XFU_ASIN, XFU_ACOS, XFU_ATAN, XFU_ASINH, XFU_ACOSH, XFU_ATANH, XFU_TAN, XFU_NINT + XFU_ASIN, XFU_ACOS, XFU_ATAN, XFU_ASINH, XFU_ACOSH, XFU_ATANH, XFU_TAN, XFU_NINT, + XFU_VEC, XFU_VAR // String arguments. }; static double mathfunction(int f, double z, double x) -/* the list of built-in functions. Patch 'fmath', here and near line 888 to get more ...*/ { double y; switch (f) @@ -946,6 +951,48 @@ formula(dico_t *dico, const char *s, const char *s_end, bool *perror) if (kptr >= s_end) { error = message(dico, "Closing \")\" not found.\n"); natom++; /* shut up other error message */ + } else if (fu >= XFU_VEC) { + struct dvec *d; + char *vec_name; + + /* Special case: function with string arg. + * Try to evaluate any string expression, else use directly. + */ + + if (string_expr(dico, &tstr, s, kptr) != kptr) + pscopy(&tstr, s, kptr); // No, or not fully consumed. + vec_name = ds_get_buf(&tstr); + + if (fu == XFU_VEC) { + struct plot *cplot, *prev; + + d = vec_get(vec_name); + + /* A simple name will be looked-up is the current plot. + * Try "const" if not found. + */ + + if (!d && !strchr(vec_name, '.')) { + cplot = get_plot("const"); + if (plot_cur != cplot) { + prev = plot_cur; + plot_cur = cplot; + d = vec_get(vec_name); + plot_cur = prev; + } + } + + if (d && d->v_length > 0 && isreal(d)) + u = d->v_realdata[0]; + else + u = 0; + } else if (fu == XFU_VAR) { + if (!cp_getvar(vec_name, CP_REAL, &u, sizeof u)) + u = 0; + } + state = S_atom; + s = kptr + 1; + fu = 0; } else { if (arg2 >= s) { v = formula(dico, s, arg2, &error); @@ -1088,7 +1135,7 @@ formula(dico_t *dico, const char *s, const char *s_end, bool *perror) } -/* Check for a string expression, return end pointer or NULL. +/* Check for a string expression, return end pointer or NULL. * A string expression is a sequence of quoted strings and string * variables, optionally enclosed by '{}' with no interventing space. * If successful return pointer to next char, otherwise NULL. diff --git a/src/frontend/outitf.c b/src/frontend/outitf.c index d47e61632..91cb49624 100644 --- a/src/frontend/outitf.c +++ b/src/frontend/outitf.c @@ -26,7 +26,6 @@ Modified: 2000 AlansFixes, 2013/2015 patch by Krzysztof Blaszkowski #include "variable.h" #include #include "ngspice/cktdefs.h" -#include "ngspice/inpdefs.h" #include "breakp2.h" #include "runcoms.h" #include "plotting/graf.h" @@ -119,20 +118,6 @@ OUTpBeginPlot(CKTcircuit *circuitPtr, JOB *analysisPtr, } -int -OUTwBeginPlot(CKTcircuit *circuitPtr, JOB *analysisPtr, - IFuid analName, - IFuid refName, int refType, - int numNames, IFuid *dataNames, int dataType, runDesc **plotPtr) -{ - - return (beginPlot(analysisPtr, circuitPtr, "circuit name", - analName, refName, refType, numNames, - dataNames, dataType, TRUE, - plotPtr)); -} - - static int beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analName, char *refName, int refType, int numNames, char **dataNames, int dataType, bool windowed, runDesc **runp) { @@ -149,10 +134,9 @@ beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analNam bool savenointernals = FALSE; char *an_name; int initmem; - /*to resume a run saj - *All it does is reassign the file pointer and return (requires *runp to be NULL if this is not needed) - */ + /*to resume a run, Reassign the file pointer and return + (requires *runp to be NULL if this is not needed)*/ if (dataType == 666 && numNames == 666) { run = *runp; run->writeOut = ft_getOutReq(&run->fp, &run->runPlot, &run->binary, @@ -280,6 +264,12 @@ beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analNam saves[i].used = 1; break; } + else if (ft_ngdebug && refName && eq(refName, "time") && eq(saves[i].name, "deltacheck")) { + addDataDesc(run, "deltacheck", IF_REAL, j, initmem); + savesused[i] = TRUE; + saves[i].used = 1; + break; + } } } } @@ -307,6 +297,7 @@ beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analNam /* generate a vector of real time information */ if (ft_ngdebug && refName && eq(refName, "time")) { addDataDesc(run, "speedcheck", IF_REAL, numNames, initmem); + addDataDesc(run, "deltacheck", IF_REAL, numNames, initmem); } } @@ -582,6 +573,9 @@ OUTpD_memory(runDesc *run, IFvalue *refValue, IFvalue *valuePtr) double tt = ((double)cl - (double)startclock) / CLOCKS_PER_SEC; plotAddRealValue(d, tt); } + else if (ft_ngdebug && d->type == IF_REAL && eq(d->name, "deltacheck")) { + plotAddRealValue(d, ft_curckt->ci_ckt->CKTdeltaOld[0]); + } else if (d->type == IF_REAL) plotAddRealValue(d, valuePtr->v.vec.rVec[d->outIndex]); else if (d->type == IF_COMPLEX) @@ -693,6 +687,9 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr) double tt = ((double)cl - (double)startclock) / CLOCKS_PER_SEC; fileAddRealValue(run->fp, run->binary, tt); } + else if (ft_ngdebug && run->data[i].type == IF_REAL && eq(run->data[i].name, "deltacheck")) { + fileAddRealValue(run->fp, run->binary, ft_curckt->ci_ckt->CKTdeltaOld[0]); + } else if (run->data[i].type == IF_REAL) fileAddRealValue(run->fp, run->binary, valuePtr->v.vec.rVec [run->data[i].outIndex]); @@ -789,38 +786,6 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr) } /* end of function OUTpData */ - -int OUTwReference(runDesc*plotPtr, IFvalue *valuePtr, void **refPtr) -{ - NG_IGNORE(refPtr); - NG_IGNORE(valuePtr); - NG_IGNORE(plotPtr); - - return OK; -} - - -int -OUTwData(runDesc *plotPtr, int dataIndex, IFvalue *valuePtr, void *refPtr) -{ - NG_IGNORE(refPtr); - NG_IGNORE(valuePtr); - NG_IGNORE(dataIndex); - NG_IGNORE(plotPtr); - - return OK; -} - - -int -OUTwEnd(runDesc *plotPtr) -{ - NG_IGNORE(plotPtr); - - return OK; -} - - int OUTendPlot(runDesc *plotPtr) { @@ -840,27 +805,6 @@ OUTendPlot(runDesc *plotPtr) } -int -OUTbeginDomain(runDesc *plotPtr, IFuid refName, int refType, IFvalue *outerRefValue) -{ - NG_IGNORE(outerRefValue); - NG_IGNORE(refType); - NG_IGNORE(refName); - NG_IGNORE(plotPtr); - - return (OK); -} - - -int -OUTendDomain(runDesc *plotPtr) -{ - NG_IGNORE(plotPtr); - - return (OK); -} - - int OUTattributes(runDesc *plotPtr, IFuid varName, int param, IFvalue *value) { @@ -957,8 +901,9 @@ fileInit(runDesc *run) } /* Trying to guess the type of a vector, using either their special names - or special parameter names for @ vecors. FIXME This guessing may fail - due to the many options, especially for the @ vectors. */ + or special parameter names for @ vectors. FIXME This guessing may fail + due to the many options, especially for the @ vectors. pltypename + may be run->type in batch mode or the plot name in control mode. */ static int guess_type(const char *name, char* pltypename) { @@ -970,6 +915,8 @@ guess_type(const char *name, char* pltypename) type = SV_TIME; else if ( cieq(name, "speedcheck")) type = SV_TIME; + else if ( cieq(name, "deltacheck")) + type = SV_TIME; else if (cieq(name, "frequency")) type = SV_FREQUENCY; else if (ciprefix("inoise", name)) @@ -1025,13 +972,15 @@ static void fileInit_pass2(runDesc *run) { int i, type; + bool keepbranch = cp_getvar("keep#branch", CP_BOOL, NULL, 0); for (i = 0; i < run->numData; i++) { char *name = run->data[i].name; - type = guess_type(name, NULL); + /* Use run->type to detect SP analysis */ + type = guess_type(name, run->type); if (type == SV_CURRENT && !keepbranch) { char *branch = strstr(name, "#branch"); @@ -1170,6 +1119,7 @@ plotInit(runDesc *run) else name = copy(dd->name); + /* Use pl->pl_typename to detect SP analysis */ v = dvec_alloc(name, guess_type(name, pl->pl_typename), run->isComplex diff --git a/src/frontend/outitf.h b/src/frontend/outitf.h index efb333119..cf4895d7e 100644 --- a/src/frontend/outitf.h +++ b/src/frontend/outitf.h @@ -50,17 +50,8 @@ int OUTpBeginPlot(CKTcircuit *circuitPtr, JOB *analysisPtr, IFuid analName, IFuid refName, int refType, int numNames, IFuid *dataNames, int dataType, runDesc **plotPtr); -int OUTwBeginPlot(CKTcircuit *circuitPtr, JOB *analysisPtr, - IFuid analName, - IFuid refName, int refType, - int numNames, IFuid *dataNames, int dataType, runDesc **plotPtr); int OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr); -int OUTwReference(runDesc *plotPtr, IFvalue *valuePtr, void **refPtr); -int OUTwData(runDesc *plotPtr, int dataIndex, IFvalue *valuePtr, void *refPtr); -int OUTwEnd(runDesc *plotPtr); int OUTendPlot(runDesc *plotPtr); -int OUTbeginDomain(runDesc *plotPtr, IFuid refName, int refType, IFvalue *outerRefValue); -int OUTendDomain(runDesc *plotPtr); int OUTattributes(runDesc *plotPtr, IFuid varName, int param, IFvalue *value); int OUTstopnow(void); void OUTerror(int flags, char *format, IFuid *names); diff --git a/src/frontend/resource.c b/src/frontend/resource.c index 47b4ae400..303cb65de 100644 --- a/src/frontend/resource.c +++ b/src/frontend/resource.c @@ -213,14 +213,6 @@ printres(char *name) called = TRUE; } -#ifdef XSPICE - /* gtri - add - 12/12/90 - wbk - record cpu time used for ipc */ - g_ipc.cpu_time = (double) last_msec; - g_ipc.cpu_time /= 1000.0; - g_ipc.cpu_time += (double) last_sec; - /* gtri - end - 12/12/90 */ -#endif - yy = TRUE; #else if (!name || eq(name, "totalcputime")) diff --git a/src/frontend/runcoms.c b/src/frontend/runcoms.c index 10077f0b8..9d98747df 100644 --- a/src/frontend/runcoms.c +++ b/src/frontend/runcoms.c @@ -323,14 +323,6 @@ static int dosim( if (if_sens_run(ft_curckt->ci_ckt, ww, ft_curckt->ci_symtab) == 1) { /* The circuit was interrupted somewhere. */ fprintf(cp_err, "%s simulation interrupted\n", what); -#ifdef XSPICE - /* gtri - add - 12/12/90 - wbk - record error and return errchk */ - g_ipc.run_error = IPC_TRUE; - if (g_ipc.enabled) { - ipc_send_errchk(); - } - /* gtri - end - 12/12/90 */ -#endif } else { ft_curckt->ci_inprogress = FALSE; @@ -342,14 +334,6 @@ static int dosim( if (err == 1) { /* The circuit was interrupted somewhere. */ fprintf(cp_err, "%s simulation interrupted\n", what); -#ifdef XSPICE - /* record error and return errchk */ - g_ipc.run_error = IPC_TRUE; - if (g_ipc.enabled) { - ipc_send_errchk(); - } - /* gtri - end - 12/12/90 */ -#endif err = 0; } else if (err == 2) { diff --git a/src/frontend/subckt.c b/src/frontend/subckt.c index 52eb230f5..a0fed2696 100644 --- a/src/frontend/subckt.c +++ b/src/frontend/subckt.c @@ -97,7 +97,7 @@ struct bxx_buffer; static void finishLine(struct bxx_buffer *dst, char *src, char *scname); static int settrans(char *formal, int flen, char *actual, const char *subname); static char *gettrans(const char *name, const char *name_end, bool *isglobal); -static int numnodes(const char *line); +static int numnodes(const char* line, struct subs* subs); static int numdevs(char *s); static wordlist *modtranslate(struct card *deck, char *subname, wordlist *new_modnames); static void devmodtranslate(struct card *deck, char *subname, wordlist * const orig_modnames); @@ -135,9 +135,6 @@ struct subs { * list of translated names (i.e. after subckt expansion) */ -/* flag indicating use of the experimental numparams library */ -static bool use_numparams = FALSE; - static char start[32], sbend[32], invoke[32], model[32]; static void @@ -224,48 +221,41 @@ inp_subcktexpand(struct card *deck) { if (!cp_getvar("modelline", CP_STRING, model, sizeof(model))) strcpy(model, ".model"); -/* use_numparams = cp_getvar("numparams", CP_BOOL, NULL, 0); */ - - use_numparams = TRUE; // tprint(deck); /* deck has .control sections already removed, but not comments */ - if (use_numparams) { - #ifdef TRACE - fprintf(stderr, "Numparams is processing this deck:\n"); - for (c = deck; c; c = c->nextcard) { - if (ciprefix("*", c->line)) - continue; - fprintf(stderr, "%3d:%s\n", c->linenum, c->line); - } -#endif - - nupa_signal(NUPADECKCOPY); - /* get the subckt names from the deck */ - for (c = deck; c; c = c->nextcard) { /* first Numparam pass */ - if (ciprefix(".subckt", c->line)) { - nupa_scan(c); - } - } - - /* now copy instances */ - for (c = deck; c; c = c->nextcard) { /* first Numparam pass */ - if (*(c->line) == '*') { - continue; - } - c->line = nupa_copy(c); - } - -#ifdef TRACE - fprintf(stderr, "Numparams transformed deck:\n"); - for (c = deck; c; c = c->nextcard) { - if (ciprefix("*", c->line)) - continue; - fprintf(stderr, "%3d:%s\n", c->linenum, c->line); - } -#endif - + fprintf(stderr, "Numparams is processing this deck:\n"); + for (c = deck; c; c = c->nextcard) { + if (ciprefix("*", c->line)) + continue; + fprintf(stderr, "%3d:%s\n", c->linenum, c->line); } +#endif + + nupa_signal(NUPADECKCOPY); + /* get the subckt names from the deck */ + for (c = deck; c; c = c->nextcard) { /* first Numparam pass */ + if (ciprefix(".subckt", c->line)) { + nupa_scan(c); + } + } + + /* now copy instances */ + for (c = deck; c; c = c->nextcard) { /* first Numparam pass */ + if (*(c->line) == '*') { + continue; + } + c->line = nupa_copy(c); + } + +#ifdef TRACE + fprintf(stderr, "Numparams transformed deck:\n"); + for (c = deck; c; c = c->nextcard) { + if (ciprefix("*", c->line)) + continue; + fprintf(stderr, "%3d:%s\n", c->linenum, c->line); + } +#endif /* Get all the model names so we can deal with BJTs, etc. * Stick all the model names into the doubly-linked wordlist modnames. @@ -374,36 +364,34 @@ inp_subcktexpand(struct card *deck) { if (ciprefix(invoke, c->line)) { fprintf(cp_err, "Error: unknown subckt: %s\n", c->line); fprintf(cp_err, " in line no. %d from file %s\n", c->linenum_orig, c->linesource); - if (use_numparams) - nupa_signal(NUPAEVALDONE); + + nupa_signal(NUPAEVALDONE); return NULL; } - if (use_numparams) { - /* the NUMPARAM final line translation pass */ - nupa_signal(NUPASUBDONE); - for (c = deck; c; c = c->nextcard) - /* 'param' .meas statements can have dependencies on measurement values */ - /* need to skip evaluating here and evaluate after other .meas statements */ - if (ciprefix(".meas", c->line) && strstr(c->line, "param")) { - ; - } else { - nupa_eval(c); - } + /* the NUMPARAM final line translation pass */ + nupa_signal(NUPASUBDONE); + for (c = deck; c; c = c->nextcard) + /* 'param' .meas statements can have dependencies on measurement values */ + /* need to skip evaluating here and evaluate after other .meas statements */ + if (ciprefix(".meas", c->line) && strstr(c->line, "param")) { + ; + } else { + nupa_eval(c); + } #ifdef TRACE - fprintf(stderr, "Numparams converted deck:\n"); - for (c = deck; c; c = c->nextcard) { - if (ciprefix("*", c->line)) - continue; - fprintf(stderr, "%3d:%s\n", c->linenum, c->line); - } + fprintf(stderr, "Numparams converted deck:\n"); + for (c = deck; c; c = c->nextcard) { + if (ciprefix("*", c->line)) + continue; + fprintf(stderr, "%3d:%s\n", c->linenum, c->line); + } #endif - /*nupa_list_params(stdout);*/ - nupa_copy_inst_dico(); - nupa_signal(NUPAEVALDONE); - } + /*nupa_list_params(stdout);*/ + nupa_copy_inst_dico(); + nupa_signal(NUPAEVALDONE); return (deck); /* return the spliced deck. */ } @@ -535,13 +523,8 @@ doit(struct card *deck, wordlist *modnames) { else deck = c; - if (use_numparams == FALSE) { - line_free_x(ends, FALSE); /* drop the .ends card */ - prev_of_ends->nextcard = NULL; - } else { - ends->line[0] = '*'; /* comment the .ends card */ - ends->nextcard = NULL; - } + ends->line[0] = '*'; /* comment the .ends card */ + ends->nextcard = NULL; } else { @@ -760,18 +743,8 @@ doit(struct card *deck, wordlist *modnames) { error = 1; /* Now splice the decks together. */ - - if (use_numparams == FALSE) { - line_free_x(c, FALSE); /* drop the invocation */ - if (prev_of_c) - prev_of_c->nextcard = su_deck; - else - deck = su_deck; - } else { - c->line[0] = '*'; /* comment the invocation */ - c->nextcard = su_deck; - } - + c->line[0] = '*'; /* comment the invocation */ + c->nextcard = su_deck; c = su_deck; while (c->nextcard) c = c->nextcard; @@ -1173,11 +1146,15 @@ translate_inst_name(struct bxx_buffer *buffer, const char *scname, const char *n static int translate(struct card *deck, char *formal, int flen, char *actual, char *scname, const char *subname, struct subs *subs, wordlist const *modnames) { + struct card *c; struct bxx_buffer buffer; char *next_name, *name, *t, *nametofree, *paren_ptr; int nnodes, i, dim; int rtn = 0; + + NG_IGNORE(modnames); + #ifdef XSPICE bool got_vnam = FALSE; #endif @@ -1387,7 +1364,7 @@ translate(struct card *deck, char *formal, int flen, char *actual, char *scname, * Ignore controlling nodes as they get special treatment for POLY. */ - nnodes = numnodes(c->line); + nnodes = numnodes(c->line, subs); while (--nnodes >= 0) { name = gettok_node(&s); if (name == NULL) { @@ -1477,7 +1454,7 @@ translate(struct card *deck, char *formal, int flen, char *actual, char *scname, tfree(name); bxx_putc(&buffer, ' '); - nnodes = numnodes(c->line); + nnodes = numnodes(c->line, subs); while (--nnodes >= 0) { name = gettok_node(&s); if (name == NULL) { @@ -1690,18 +1667,26 @@ gettrans(const char *name, const char *name_end, bool *isglobal) /* Control nodes for E and G sources are not counted as they vary in * the case of POLY. The count returned by get_number_terminals() includes * devices for K (mutual inductors) and W (current-controlled switch). - */ - + * x lines are special, when nested and containing parameters. + * Therefore the old code is kept.*/ static int -numnodes(const char *line) +numnodes(const char* line, struct subs* subs) { switch (*line) { - case 'e': - case 'g': - case 'w': - return 2; - case 'k': - return 0; + case 'e': + case 'g': + case 'w': + return 2; + case 'k': + return 0; + case 'x': + { + const char* xname_e = skip_back_ws(strchr(line, '\0'), line); + const char* xname = skip_back_non_ws(xname_e, line); + for (; subs; subs = subs->su_next) + if (eq_substr(xname, xname_e, subs->su_name)) + return subs->su_numargs; + } } return get_number_terminals((char *)line); } diff --git a/src/include/ngspice/Makefile.am b/src/include/ngspice/Makefile.am index 1783a9df1..fcda98836 100644 --- a/src/include/ngspice/Makefile.am +++ b/src/include/ngspice/Makefile.am @@ -11,7 +11,6 @@ noinst_HEADERS = \ ciderinp.h \ cidersupt.h \ cktdefs.h \ - cluster.h \ cmconstants.h \ cm.h \ cmproto.h \ diff --git a/src/include/ngspice/cktdefs.h b/src/include/ngspice/cktdefs.h index 6aa65744d..60a07db02 100644 --- a/src/include/ngspice/cktdefs.h +++ b/src/include/ngspice/cktdefs.h @@ -206,11 +206,11 @@ struct CKTcircuit { int CKTtranMaxIter; /* iteration limit for each timepoint for tran*/ /* (itl4) */ - int CKTbreakSize; /* ??? */ - int CKTbreak; /* ??? */ - double CKTsaveDelta; /* ??? */ - double CKTminBreak; /* ??? */ - double *CKTbreaks; /* List of breakpoints ??? */ + int CKTbreakSize; /* number of breakpoints in table *CKTbreaks */ + int CKTbreak; /* if 1, a breakpoint may be set (only used in isrcacct.c) */ + double CKTsaveDelta; /* previous delta, before breakpoints set a new delta */ + double CKTminBreak; /* minimum time difference between breakpoints */ + double *CKTbreaks; /* List of breakpoints as an array of doubles */ double CKTabstol; /* --- */ double CKTpivotAbsTol; /* --- */ double CKTpivotRelTol; /* --- */ diff --git a/src/include/ngspice/cluster.h b/src/include/ngspice/cluster.h deleted file mode 100644 index b6391c29b..000000000 --- a/src/include/ngspice/cluster.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef ngspice_CLUSTER_H -#define ngspice_CLUSTER_H -#include "ngspice/cktdefs.h" - -/* Cluster definitions */ -#define PORT 1234 -#define TIME_PORT 1235 -#define DOMAIN_NAME "cluster.multigig" -#define CLUSTER_WIDTH 4 -#define TIME_HOST "time.cluster.multigig" -/* does all the setups */ -extern int CLUsetup(CKTcircuit *ckt); - -/* reads input pipes and sets voltages*/ -/* call each time the present time is changed, ie just before NIinter*/ -extern int CLUinput(CKTcircuit *ckt); - -/* call after each accepted timestep, ie CKTdump */ -extern int CLUoutput(CKTcircuit *ckt); - - -/* the time step control */ -extern int CLUsync(double time,double *delta, int error); -#endif diff --git a/src/include/ngspice/ifsim.h b/src/include/ngspice/ifsim.h index cf019be2e..ca2f0787f 100644 --- a/src/include/ngspice/ifsim.h +++ b/src/include/ngspice/ifsim.h @@ -455,23 +455,8 @@ struct IFfrontEnd { /* start pointwise output plot */ int (*OUTpData) (runDesc *, IFvalue *, IFvalue *); /* data for pointwise plot */ - int (*OUTwBeginPlot) (CKTcircuit *, JOB *, - IFuid, - IFuid, int, - int, IFuid *, int, runDesc **); - /* start windowed output plot */ - int (*OUTwReference) (runDesc *, IFvalue *, void **); - /* independent vector for windowed plot */ - int (*OUTwData) (runDesc *, int, IFvalue *, void *); - /* data for windowed plot */ - int (*OUTwEnd) (runDesc *); - /* signal end of windows */ int (*OUTendPlot) (runDesc *); /* end of plot */ - int (*OUTbeginDomain) (runDesc *, IFuid, int, IFvalue *); - /* start nested domain */ - int (*OUTendDomain) (runDesc *); - /* end nested domain */ int (*OUTattributes) (runDesc *, IFuid, int, IFvalue *); /* specify output attributes of node */ }; diff --git a/src/include/ngspice/sharedspice.h b/src/include/ngspice/sharedspice.h index b932868ff..d1efd4305 100644 --- a/src/include/ngspice/sharedspice.h +++ b/src/include/ngspice/sharedspice.h @@ -497,6 +497,19 @@ int ngSpice_nospinit(void); IMPEXP int ngSpice_nospiceinit(void); +/* Locking and unlocking the realloc of output vectors during simulation. May be set +during reading output vectors in the primary thread, while the simulation in the +background thread is moving on. */ +IMPEXP +int ngSpice_LockRealloc(void); + +IMPEXP +int ngSpice_UnlockRealloc(void); + +/* Reset ngspice as far as possible. */ +IMPEXP +int ngSpice_Reset(void); + #ifdef __cplusplus } #endif diff --git a/src/main.c b/src/main.c index 986714e72..c547d5475 100644 --- a/src/main.c +++ b/src/main.c @@ -200,11 +200,8 @@ struct comm *cp_coms = spcp_coms; extern int OUTpBeginPlot(CKTcircuit *, JOB *, IFuid, IFuid, int, int, IFuid *, int, runDesc **); extern int OUTpData(runDesc *, IFvalue *, IFvalue *); -extern int OUTwBeginPlot(CKTcircuit *, JOB *, IFuid, IFuid, int, int, IFuid *, int, runDesc **); -extern int OUTwReference(runDesc *, IFvalue *, void **); -extern int OUTwData(runDesc *, int, IFvalue *, void *), OUTwEnd(runDesc *), OUTendPlot(runDesc *); -extern int OUTbeginDomain(runDesc *, IFuid, int, IFvalue *); -extern int OUTendDomain(runDesc *), OUTstopnow(void); +extern int OUTendPlot(runDesc *); +extern int OUTstopnow(void); extern void OUTerror(int, char *, IFuid *); #ifdef __GNUC__ @@ -224,13 +221,7 @@ IFfrontEnd nutmeginfo = { OUTerrorf, OUTpBeginPlot, OUTpData, - OUTwBeginPlot, - OUTwReference, - OUTwData, - OUTwEnd, OUTendPlot, - OUTbeginDomain, - OUTendDomain, OUTattributes }; @@ -1397,7 +1388,7 @@ int main(int argc, char **argv) tpf = smktemp("sp"); tempfile = fopen(tpf, "w+bTD"); if (tempfile == NULL) { - fprintf(stderr, "Could not open a temporary file " + fprintf(stderr, "Error: Could not open a temporary file " "to save and use optional arguments.\n"); sp_shutdown(EXIT_BAD); } diff --git a/src/sharedspice.c b/src/sharedspice.c index 5049fd12a..b7c660c87 100644 --- a/src/sharedspice.c +++ b/src/sharedspice.c @@ -258,13 +258,7 @@ IFfrontEnd nutmeginfo = { OUTerrorf, OUTpBeginPlot, OUTpData, - OUTwBeginPlot, - OUTwReference, - OUTwData, - OUTwEnd, OUTendPlot, - OUTbeginDomain, - OUTendDomain, OUTattributes }; diff --git a/src/spicelib/analysis/Makefile.am b/src/spicelib/analysis/Makefile.am index c6d98c35f..33d62591a 100644 --- a/src/spicelib/analysis/Makefile.am +++ b/src/spicelib/analysis/Makefile.am @@ -98,8 +98,7 @@ libckt_la_SOURCES = \ tfsetp.c \ tranaskq.c \ traninit.c \ - transetp.c \ - cluster.c + transetp.c if PSS_WANTED diff --git a/src/spicelib/analysis/acan.c b/src/spicelib/analysis/acan.c index e00fa41a0..97b25e163 100644 --- a/src/spicelib/analysis/acan.c +++ b/src/spicelib/analysis/acan.c @@ -62,16 +62,9 @@ ACan(CKTcircuit* ckt, int restart) #ifdef XSPICE - /* gtri - add - wbk - 12/19/90 - Add IPC stuff and anal_init and anal_type */ - - /* Tell the beginPlot routine what mode we're in */ - g_ipc.anal_type = IPC_ANAL_AC; - /* Tell the code models what mode we're in */ g_mif_info.circuit.anal_type = MIF_DC; g_mif_info.circuit.anal_init = MIF_TRUE; - - /* gtri - end - wbk */ #endif /* start at beginning */ @@ -152,40 +145,6 @@ ACan(CKTcircuit* ckt, int restart) else fprintf(stdout, "\n Linear circuit, option noopac given: no OP analysis\n"); -#ifdef XSPICE - /* gtri - add - wbk - 12/19/90 - Add IPC stuff */ - - /* Send the operating point results for Mspice compatibility */ - if (g_ipc.enabled) - { - /* Call CKTnames to get names of nodes/branches used by - BeginPlot */ - /* Probably should free nameList after this block since - called again... */ - error = CKTnames(ckt, &numNames, &nameList); - if (error) return(error); - - /* We have to do a beginPlot here since the data to return is - * different for the DCOP than it is for the AC analysis. - * Moreover the begin plot has not even been done yet at this - * point... - */ - SPfrontEnd->OUTpBeginPlot(ckt, ckt->CKTcurJob, - ckt->CKTcurJob->JOBname, - NULL, IF_REAL, - numNames, nameList, IF_REAL, - &acPlot); - txfree(nameList); - - ipc_send_dcop_prefix(); - CKTdump(ckt, 0.0, acPlot); - ipc_send_dcop_suffix(); - - SPfrontEnd->OUTendPlot(acPlot); - } - /* gtri - end - wbk */ -#endif - ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG; error = CKTload(ckt); if (error) return(error); @@ -376,21 +335,8 @@ ACan(CKTcircuit* ckt, int restart) } #endif -#ifdef XSPICE - /* gtri - modify - wbk - 12/19/90 - Send IPC stuff */ - - if (g_ipc.enabled) - ipc_send_data_prefix(freq); - error = CKTacDump(ckt, freq, acPlot); - if (g_ipc.enabled) - ipc_send_data_suffix(); - - /* gtri - modify - wbk - 12/19/90 - Send IPC stuff */ -#else - error = CKTacDump(ckt, freq, acPlot); -#endif if (error) { UPDATE_STATS(DOING_AC); return(error); diff --git a/src/spicelib/analysis/cktdojob.c b/src/spicelib/analysis/cktdojob.c index 9b12fb097..627626a2e 100644 --- a/src/spicelib/analysis/cktdojob.c +++ b/src/spicelib/analysis/cktdojob.c @@ -157,51 +157,15 @@ CKTdoJob(CKTcircuit* ckt, int reset, TSKtask* task) if (!error) error = CKTunsetup(ckt); -#ifdef XSPICE - /* gtri - add - 12/12/90 - wbk - set ipc syntax error flag */ - if (error) g_ipc.syntax_error = IPC_TRUE; - /* gtri - end - 12/12/90 */ -#endif - if (!error) error = CKTsetup(ckt); -#ifdef XSPICE - /* gtri - add - 12/12/90 - wbk - set ipc syntax error flag */ - if (error) g_ipc.syntax_error = IPC_TRUE; - /* gtri - end - 12/12/90 */ -#endif - if (!error) error = CKTtemp(ckt); -#ifdef XSPICE - /* gtri - add - 12/12/90 - wbk - set ipc syntax error flag */ - if (error) g_ipc.syntax_error = IPC_TRUE; - /* gtri - end - 12/12/90 */ -#endif - if (error) { - -#ifdef XSPICE - /* gtri - add - 12/12/90 - wbk - return if syntax errors from parsing */ - if (g_ipc.enabled) { - if (g_ipc.syntax_error) - ; - else { - /* else, send (GO) errchk status if we got this far */ - /* Caller is responsible for sending NOGO status if we returned earlier */ - ipc_send_errchk(); - } - } - /* gtri - end - 12/12/90 */ -#endif - - return error; - - - }/* if error */ + } } error2 = OK; diff --git a/src/spicelib/analysis/cktsetup.c b/src/spicelib/analysis/cktsetup.c index 8b5141f50..985739c64 100644 --- a/src/spicelib/analysis/cktsetup.c +++ b/src/spicelib/analysis/cktsetup.c @@ -23,7 +23,6 @@ Author: 1985 Thomas L. Quarles #ifdef USE_OMP #include #include "ngspice/cpextern.h" -int nthreads; #endif #define CKALLOC(var,size,type) \ @@ -36,7 +35,9 @@ CKTsetup(CKTcircuit *ckt) { int i; int error; - +#ifdef USE_OMP + int nthreads = 2; +#endif #ifdef XSPICE /* gtri - begin - Setup for adding rshunt option resistors */ CKTnode *node; diff --git a/src/spicelib/analysis/cktterr.c b/src/spicelib/analysis/cktterr.c index 9852b2acf..f2868e6ac 100644 --- a/src/spicelib/analysis/cktterr.c +++ b/src/spicelib/analysis/cktterr.c @@ -69,7 +69,9 @@ CKTterr(int qcap, CKTcircuit *ckt, double *timeStep) del = ckt->CKTtrtol * tol/MAX(ckt->CKTabstol,factor * fabs(diff[0])); if(ckt->CKTorder == 2) { del = sqrt(del); - } else if (ckt->CKTorder > 2) { + } else if (ckt->CKTorder == 3) { + del = cbrt(del); + } else if (ckt->CKTorder > 3) { del = exp(log(del)/ckt->CKTorder); } *timeStep = MIN(*timeStep,del); diff --git a/src/spicelib/analysis/cluster.c b/src/spicelib/analysis/cluster.c deleted file mode 100644 index c34f75181..000000000 --- a/src/spicelib/analysis/cluster.c +++ /dev/null @@ -1,426 +0,0 @@ -/* Spice hooks */ -#include "ngspice/ngspice.h" -#ifdef CLUSTER -#include "ngspice/inpdefs.h" -#include "ngspice/cluster.h" -#include "ngspice/cktdefs.h" -#include "ngspice/gendefs.h" - -/* Misc stuff */ -#include -#include - -/*Network stuff*/ -#include -#include -#include -#include -#include - - -struct input_pipe { - /*the names of the local and remote nodes*/ - char remote[32]; - char local[32]; - int fd; - FILE *stream; - /* the data recieved */ - double time; - double data; - /*resistance of this link*/ - double res; - /* The value controled */ - double *currentPtr; - /*The output it is linked to*/ - struct output_pipe *link; - struct input_pipe *next; -}; - -struct output_pipe { - int fd; - FILE *stream; - /*the names of the local and remote nodes*/ - char local[32]; - char remote[32]; - /* The index of the local node value in the ckt->CKTrhsOld array */ - int outIndex; - /*Last values sent*/ - double time,data; - struct input_pipe *link; - struct output_pipe *next; -}; - -static double lastTimeSent=0; - -static int time_sock=0; -static FILE *time_outfile=NULL; -static FILE *time_infile=NULL; - -static struct input_pipe* input_pipes=NULL; -static struct output_pipe* output_pipes=NULL; - -/* sets up deamon which waits for connections - *and sets up input pipes as it recieves them */ -static void *start_listener(void *); - -/* Setup the output pipes*/ -static int setup_output(CKTcircuit *ckt); -static int setup_input(CKTcircuit *ckt); -static int setup_time(); - -int CLUsetup(CKTcircuit *ckt){ - pthread_t tid; - struct input_pipe *curr; - int i, connections=0; - GENmodel *mod; - GENinstance *inst; - - /* count the number of connections expected */ - i = INPtypelook("Isource"); - for(mod = ckt->CKThead[i]; - mod != NULL; - mod = mod->GENnextModel) - for (inst = mod->GENinstances; - inst != NULL; - inst = inst->GENnextInstance) - if(strncmp("ipcx",inst->GENname,4) == 0) - connections++; - - /* allocate the input connections */ - for(i=0;inext = input_pipes; - else - curr->next = NULL; - input_pipes = curr; - } - - pthread_create(&tid,NULL,start_listener,(void *)&connections); - setup_output(ckt); - pthread_join(tid,NULL); - setup_input(ckt); - setup_time(); - return 0; -} - -#include "../devices/isrc/isrcdefs.h" -/*Connect to remote machine and find the data*/ -static int setup_output(CKTcircuit *ckt){ - int type; - GENmodel *mod; - GENinstance *inst; - char hostname[64]; - - lastTimeSent = 0; - type = INPtypelook("Isource"); - - for(mod = ckt->CKThead[type]; - mod != NULL; - mod = mod->GENnextModel) - - for (inst = mod->GENinstances; - inst != NULL; - inst = inst->GENnextInstance) - - if(strncmp("ipcx",inst->GENname,4) == 0){ - ISRCinstance *isrc = (ISRCinstance *)inst; - CKTnode *node; - struct output_pipe *curr; - struct sockaddr_in address; - struct hostent *host=NULL; - int sock,nodeNum,i; - - /*Create the struct*/ - curr = TMALLOC(struct output_pipe, 1); - if(output_pipes) - curr->next = output_pipes; - else - curr->next = NULL; - output_pipes = curr; - - /* The node names */ - strcpy(curr->local,CKTnodName(ckt,isrc->ISRCnegNode));/*weird*/ - strcpy(curr->remote,isrc->ISRCname); - - /* extract remote node number */ - nodeNum = /*Xcoord*/(curr->remote[4] - '0') * CLUSTER_WIDTH - + /*Ycoord*/(curr->remote[9] - '0'); - sprintf(hostname,"n%d."DOMAIN_NAME,nodeNum); - - /* network stuff */ - host = gethostbyname(hostname); - if(!host){ - printf("Host not found in setup_output\n"); - exit(0); - } - - if((sock = socket(PF_INET,SOCK_STREAM,0)) < 0){ - printf("Socket open in setup_output\n"); - exit(0); - } - - address.sin_family = AF_INET; - address.sin_port = htons(PORT); - memcpy(&address.sin_addr,host->h_addr_list[0], - sizeof(address.sin_addr)); - - printf("connecting to %s ...... ",hostname); - fflush(stdout); - - while(connect(sock,(struct sockaddr *)&address,sizeof(address))){ - usleep(500);/*wait for the sever to start*/ - } - - printf("connected\n"); - - curr->fd = sock; - - /* send stuff */ - /* buffer */ - i = (strlen(curr->remote) + strlen(curr->local) + 2)*sizeof(char); - setsockopt(sock,SOL_SOCKET,SO_SNDBUF,&i,sizeof(i)); - - curr->stream = fdopen(curr->fd,"w"); - - fwrite(curr->remote,sizeof(char),strlen(curr->remote),curr->stream); - fputc('\0',curr->stream); - fwrite(curr->local,sizeof(char),strlen(curr->local),curr->stream); - fputc('\0',curr->stream); - fflush(curr->stream); - - /* buffer, what is done per time point */ - i = sizeof(double)*2; - setsockopt(sock,SOL_SOCKET,SO_SNDBUF,&i,sizeof(i)); - - /* find the index in ckt->rhsOld which contains the local node */ - i = 0; - for(node = ckt->CKTnodes->next;node;node = node->next){ - i++; - if(strcmp(node->name,curr->local)==0){ - curr->outIndex = i; - goto next; - } - } - printf("Local node %s not found\n",curr->local); - exit(0); - next: - - } - return 0; -} - -/*Processes the connections recieved by start_listener*/ -static int setup_input(CKTcircuit *ckt){ - int type; - GENmodel *mod; - GENinstance *inst; - struct input_pipe *input; - type = INPtypelook("Isource"); - - for(input = input_pipes;input;input = input->next){ - int i; - - input->stream = fdopen(input->fd,"r"); - - /*Get the local and remote node names*/ - i=0; - do { - while(fread(&input->local[i],sizeof(char),1,input->stream) != 1); - }while(input->local[i++] != '\0'); - - i=0; - do { - while(fread(&input->remote[i],sizeof(char),1,input->stream) != 1); - }while(input->remote[i++] != '\0'); - - /* initilise */ - input->time = -1; - - /*Find the Isource to control*/ - for(mod = ckt->CKThead[type]; - mod != NULL; - mod = mod->GENnextModel) - - for (inst = mod->GENinstances; - inst != NULL; - inst = inst->GENnextInstance) - - if(strcmp(input->remote,&inst->GENname[11]) == 0){ - - ISRCinstance *isrc = (ISRCinstance *)inst; - input->res = isrc->ISRCdcValue; - isrc->ISRCdcValue = 0; - input->currentPtr = &isrc->ISRCdcValue; - goto next; - } - /* We get here if no Isource matches */ - printf("Current source %s not found\n",input->remote); - exit(0); - - next: - - /* Now find the corresponding output */ - { - struct output_pipe *output; - for(output = output_pipes;output;output = output->next) - if(strcmp(&input->local[11],output->local)==0){ - input->link = output; - output->link = input; - goto next2; - } - printf("Parent to %s not found\n",&input->local[11]); - exit(0); - next2: - } - } - return 0; -} - -/* This starts a server and waits for connections, number given by argument*/ -static void *start_listener(void *v){ - int *connections = (int *)v; - int count=0; - struct sockaddr_in address; - int sock, conn,i; - size_t addrLength = sizeof(struct sockaddr_in); - struct input_pipe *curr; - - if((sock = socket(PF_INET,SOCK_STREAM,0)) < 0){ - printf("socket in start_listener\n"); - exit(0); - } - - /* Allow reuse of the socket */ - i = 1; - setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(i)); - - /* port, inferface ..*/ - address.sin_family = AF_INET; - address.sin_port = htons(PORT); - memset(&address.sin_addr,0,sizeof(address.sin_addr)); - - if(bind(sock, (struct sockaddr *)&address,sizeof(address))){ - printf("bind in start_listener\n"); - exit(0); - } - if(listen(sock,5)){ - printf("listen in start_listener\n"); - exit(0); - } - - /* Loop till recieved all connections */ - curr = input_pipes; - while (count < *connections){ - if((conn = accept(sock, (struct sockaddr *)&address,&addrLength)) < 0){ - printf("accept in start_listener\n"); - exit(0); - } - - curr->fd = conn; - /* will fill rest of structure later in setup_input*/ - count ++; - curr = curr->next; - } - - close(sock); - - return NULL; -} - -/*Writes data to remote computer*/ -int CLUoutput(CKTcircuit *ckt){ - struct output_pipe *output; - lastTimeSent = ckt->CKTtime; - for(output = output_pipes; - output; - output = output->next){ - output->time = ckt->CKTtime; - output->data = ckt->CKTrhsOld[output->outIndex]; - fwrite(&output->time,sizeof(double),1,output->stream); - fwrite(&output->data, - sizeof(double),1,output->stream); - fflush(output->stream); - } - return 0; -} - -/*Maniputates the local circuit based on the links*/ -int CLUinput(CKTcircuit *ckt){ - struct input_pipe *input; - double tmp; - for(input= input_pipes;input;input = input->next){ - /*recieve data till we get a good time point*/ - while (input->time < lastTimeSent){ - while(fread(&input->time, sizeof(double), 1, input->stream) != 1){} - while(fread(&input->data, sizeof(double), 1, input->stream) != 1){} - } - tmp = (input->link->data - input->data) / input->res; - - /*dampen out large currents*/ - if(tmp > 0) - *input->currentPtr = 0.2 * (1 - exp(-tmp/0.2)); - else - *input->currentPtr = -0.2 * (1 - exp(tmp/0.2)); - - /*GND is the posNode, local node is the negNode*/ - } - return 0; -} - -static int setup_time(){ - struct sockaddr_in address; - struct hostent *host=NULL; - char *hostname = TIME_HOST; - int sock,i; - - /* network stuff */ - host = gethostbyname(hostname); - if(!host){ - printf("Host not found in setup_time\n"); - exit(0); - } - if((sock = socket(PF_INET,SOCK_STREAM,0)) < 0){ - printf("Socket open in setup_time\n"); - exit(0); - } - - i = sizeof(double)*2; - setsockopt(sock,SOL_SOCKET,SO_SNDBUF ,&i,sizeof(i)); - - address.sin_family = AF_INET; - address.sin_port = htons(TIME_PORT); - memcpy(&address.sin_addr,host->h_addr_list[0], - sizeof(address.sin_addr)); - - - while(connect(sock,(struct sockaddr *)&address,sizeof(address))){ - usleep(500);/*wait for the sever to start*/ - } - time_sock=sock; - time_outfile=fdopen(sock,"w"); - time_infile=fdopen(sock,"r"); - - return 0; -} - - -int CLUsync(double time,double *delta, int error){ - double tmp; - if(error) - tmp = *delta * (-1); - else - tmp = *delta; - fwrite(&time,sizeof(double),1,time_outfile); - fwrite(&tmp,sizeof(double),1,time_outfile); - fflush(time_outfile); - while(fread(&tmp,sizeof(double),1,time_infile) != 1); - if(tmp < 0){ - *delta = -tmp; - return 0; - } else { - *delta = tmp; - return 1; - } -} -#endif diff --git a/src/spicelib/analysis/dcop.c b/src/spicelib/analysis/dcop.c index fc94dae9d..4d8bfe8ca 100644 --- a/src/spicelib/analysis/dcop.c +++ b/src/spicelib/analysis/dcop.c @@ -35,18 +35,13 @@ DCop(CKTcircuit *ckt, int notused) NG_IGNORE(notused); #ifdef XSPICE -/* gtri - add - wbk - 12/19/90 - Add IPC stuff and initialize anal_init and anal_type */ - - /* Tell the beginPlot routine what mode we're in */ - g_ipc.anal_type = IPC_ANAL_DCOP; /* Tell the code models what mode we're in */ g_mif_info.circuit.anal_type = MIF_DC; g_mif_info.circuit.anal_init = MIF_TRUE; -/* gtri - end - wbk */ -#endif +#endif error = CKTnames(ckt,&numNames,&nameList); if(error) return(error); @@ -114,31 +109,17 @@ DCop(CKTcircuit *ckt, int notused) } #endif + converged = CKTload(ckt); -#ifdef XSPICE -/* gtri - modify - wbk - 12/19/90 - Send IPC data delimiters */ - if(g_ipc.enabled) - ipc_send_dcop_prefix(); - - CKTdump(ckt, 0.0, plot); - - if (ckt->CKTsoaCheck) - error = CKTsoaCheck(ckt); - - if(g_ipc.enabled) - ipc_send_dcop_suffix(); - -/* gtri - end - wbk */ -#else if(converged == 0) { - CKTdump(ckt, 0.0, plot); - if (ckt->CKTsoaCheck) - error = CKTsoaCheck(ckt); - } else { - fprintf(stderr,"error: circuit reload failed.\n"); - } -#endif + CKTdump(ckt, 0.0, plot); + if (ckt->CKTsoaCheck) + error = CKTsoaCheck(ckt); + } else { + fprintf(stderr,"error: circuit reload failed.\n"); + } + SPfrontEnd->OUTendPlot (plot); return(converged); } diff --git a/src/spicelib/analysis/dcpss.c b/src/spicelib/analysis/dcpss.c index 61350383c..d02b33712 100644 --- a/src/spicelib/analysis/dcpss.c +++ b/src/spicelib/analysis/dcpss.c @@ -24,11 +24,6 @@ /* gtri - end - wbk - Add headers */ #endif -#ifdef CLUSTER -#include "ngspice/cluster.h" -#endif - - #define INIT_STATS() \ do { \ startTime = SPfrontEnd->IFseconds(); \ @@ -89,18 +84,6 @@ DCpss(CKTcircuit *ckt, int ltra_num; CKTnode *node; -#ifdef XSPICE -/* gtri - add - wbk - 12/19/90 - Add IPC stuff */ - Ipc_Boolean_t ipc_firsttime = IPC_TRUE; - Ipc_Boolean_t ipc_secondtime = IPC_FALSE; - Ipc_Boolean_t ipc_delta_cut = IPC_FALSE; - double ipc_last_time = 0.0; - double ipc_last_delta = 0.0; -/* gtri - end - wbk - 12/19/90 - Add IPC stuff */ -#endif -#ifdef CLUSTER - int redostep; -#endif /* New variables */ int j, oscnNode; @@ -224,15 +207,12 @@ DCpss(CKTcircuit *ckt, #endif #ifdef XSPICE -/* gtri - add - wbk - 12/19/90 - Add IPC stuff and set anal_init and anal_type */ - /* Tell the beginPlot routine what mode we're in */ - g_ipc.anal_type = IPC_ANAL_TRAN; + /* set anal_init and anal_type */ /* Tell the code models what mode we're in */ g_mif_info.circuit.anal_type = MIF_DC; g_mif_info.circuit.anal_init = MIF_TRUE; -/* gtri - end - wbk */ #endif /* Time Domain plot start and prepared to be filled in later */ @@ -306,35 +286,18 @@ DCpss(CKTcircuit *ckt, #endif /* If no convergence reached - NO valid Operating Point */ - if(converged != 0) return(converged); + if(converged != 0) + return(converged); + #ifdef XSPICE -/* gtri - add - wbk - 12/19/90 - Add IPC stuff */ - - /* Send the operating point results for Mspice compatibility */ - if(g_ipc.enabled) { - ipc_send_dcop_prefix(); - CKTdump(ckt, 0.0, job->PSSplot_td); - ipc_send_dcop_suffix(); - } - -/* gtri - end - wbk */ - -/* gtri - add - wbk - 12/19/90 - set anal_init and anal_type */ - g_mif_info.circuit.anal_init = MIF_TRUE; /* Tell the code models what mode we're in */ g_mif_info.circuit.anal_type = MIF_TRAN; -/* gtri - end - wbk */ - -/* gtri - begin - wbk - Add Breakpoint stuff */ - /* Initialize the temporary breakpoint variables to infinity */ g_mif_info.breakpoint.current = HUGE_VAL; g_mif_info.breakpoint.last = HUGE_VAL; - -/* gtri - end - wbk - Add Breakpoint stuff */ #endif ckt->CKTstat->STATtimePts ++; @@ -365,9 +328,7 @@ DCpss(CKTcircuit *ckt, /* Statistics Initialization using a macro at the beginning of this code */ INIT_STATS(); -#ifdef CLUSTER - CLUsetup(ckt); -#endif + } else { /* saj As traninit resets CKTmode */ ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODETRAN | MODEINITPRED; @@ -444,56 +405,16 @@ DCpss(CKTcircuit *ckt, return(error); } #ifdef XSPICE -/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */ - if ((g_ipc.enabled) || wantevtdata) { + if (wantevtdata) { if (pss_state == PSS) { - /* Send event-driven results */ - EVTdump(ckt, IPC_ANAL_TRAN, 0.0); - - /* Then follow with analog results... */ - - /* Test to see if delta was cut by a breakpoint, */ - /* a non-convergence, or a too large truncation error */ - if(ipc_firsttime) - ipc_delta_cut = IPC_FALSE; - else if(ckt->CKTtime < (ipc_last_time + (0.999 * ipc_last_delta))) - ipc_delta_cut = IPC_TRUE; - else - ipc_delta_cut = IPC_FALSE; - - /* Record the data required to check for delta cuts */ - ipc_last_time = ckt->CKTtime; - ipc_last_delta = MIN(ckt->CKTdelta, ckt->CKTmaxStep); - - /* Send results data if time since last dump is greater */ - /* than 'mintime', or if first or second timepoints, */ - /* or if delta was cut */ - if( (ckt->CKTtime >= (g_ipc.mintime + g_ipc.last_time)) || - ipc_firsttime || ipc_secondtime || ipc_delta_cut ) { - - ipc_send_data_prefix(ckt->CKTtime); - CKTdump(ckt, ckt->CKTtime, job->PSSplot_td); - ipc_send_data_suffix(); - - if(ipc_firsttime) { - ipc_firsttime = IPC_FALSE; - ipc_secondtime = IPC_TRUE; - } else if(ipc_secondtime) { - ipc_secondtime = IPC_FALSE; - } - - g_ipc.last_time = ckt->CKTtime; - } + /* Send event-driven results */ + EVTdump(ckt, IPC_ANAL_TRAN, 0.0); } } else -/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */ -#endif -#ifdef CLUSTER - if (pss_state == PSS) - CLUoutput(ckt); + #endif if (pss_state == PSS) @@ -1278,14 +1199,6 @@ resume: } /* end if there are event instances */ /* gtri - end - wbk - Do event solution */ -#else - -#ifdef CLUSTER - if(!CLUsync(ckt->CKTtime,&ckt->CKTdelta,0)) { - fprintf (stderr, "Sync error!\n"); - exit(0); - } -#endif /* CLUSTER */ #endif @@ -1302,9 +1215,6 @@ resume: /* 600 */ for (;;) { -#ifdef CLUSTER - redostep = 1; -#endif #ifdef XSPICE /* gtri - add - wbk - 4/17/91 - Fix Berkeley bug */ /* This is needed here to allow CAPask to output currents */ @@ -1318,9 +1228,6 @@ resume: olddelta=ckt->CKTdelta; /* time abort? */ ckt->CKTtime += ckt->CKTdelta; -#ifdef CLUSTER - CLUinput(ckt); -#endif ckt->CKTdeltaOld[0]=ckt->CKTdelta; NIcomCof(ckt); #ifdef PREDICTOR @@ -1384,10 +1291,8 @@ resume: fprintf (stderr, "pss_state: %d, converged: %d\n", pss_state, converged) ; #endif if(converged != 0) { -#ifndef CLUSTER - ckt->CKTtime = ckt->CKTtime -ckt->CKTdelta; - ckt->CKTstat->STATrejected ++; -#endif + ckt->CKTtime = ckt->CKTtime - ckt->CKTdelta; + ckt->CKTstat->STATrejected++; ckt->CKTdelta = ckt->CKTdelta/8; #ifdef STEPDEBUG fprintf (stderr, "delta cut to %g for non-convergence\n", ckt->CKTdelta) ; @@ -1419,14 +1324,9 @@ resume: } else { if (firsttime) { firsttime = 0; -#ifndef CLUSTER goto nextTime; /* no check on * first time point */ -#else - redostep = 0; - goto chkStep; -#endif } newdelta = ckt->CKTdelta; error = CKTtrunc(ckt,&newdelta); @@ -1467,18 +1367,13 @@ resume: fflush(stdout); #endif -#ifndef CLUSTER + /* go to 650 - trapezoidal */ goto nextTime; -#else - redostep = 0; - goto chkStep; -#endif + } else { /* newdelta <= .9 * ckt->CKTdelta */ -#ifndef CLUSTER ckt->CKTtime = ckt->CKTtime -ckt->CKTdelta; ckt->CKTstat->STATrejected ++; -#endif ckt->CKTdelta = newdelta; #ifdef STEPDEBUG fprintf (stderr, "delta set to truncation error result:point rejected\n") ; @@ -1505,15 +1400,6 @@ resume: EVTbackup(ckt, ckt->CKTtime + ckt->CKTdelta); /* gtri - end - wbk - Do event backup */ -#endif -#ifdef CLUSTER - chkStep: - if(CLUsync(ckt->CKTtime,&ckt->CKTdelta,redostep)){ - goto nextTime; - } else { - ckt->CKTtime -= olddelta; - ckt->CKTstat->STATrejected ++; - } #endif } /* NOTREACHED */ diff --git a/src/spicelib/analysis/dctran.c b/src/spicelib/analysis/dctran.c index e83143318..4c55678d5 100644 --- a/src/spicelib/analysis/dctran.c +++ b/src/spicelib/analysis/dctran.c @@ -5,8 +5,14 @@ Modified: 2000 AlansFixes Modified: 2023 XSPICE breakpoint fix for shared ngspice by Vyacheslav Shevchuk **********/ -/* subroutine to do DC TRANSIENT analysis - --- ONLY, unlike spice2 routine with the same name! */ +/* subroutine to do DC TRANSIENT analysis */ + + +/* line goto label: + 373 nextTime + 515 resume + 786 past_breakpoint + 985 chkStep */ #include "ngspice/ngspice.h" #include "ngspice/cktdefs.h" @@ -21,19 +27,12 @@ extern struct dbcomm *dbs; #include "ngspice/ftedebug.h" #ifdef XSPICE -/* gtri - add - wbk - Add headers */ #include "ngspice/miftypes.h" - #include "ngspice/evt.h" #include "ngspice/enh.h" #include "ngspice/mif.h" #include "ngspice/evtproto.h" #include "ngspice/ipctiein.h" -/* gtri - end - wbk - Add headers */ -#endif - -#ifdef CLUSTER -#include "ngspice/cluster.h" #endif #ifdef SHARED_MODULE @@ -100,37 +99,29 @@ DCtran(CKTcircuit *ckt, int ltra_num; CKTnode *node; #ifdef XSPICE -/* gtri - add - wbk - 12/19/90 - Add IPC stuff */ - Ipc_Boolean_t ipc_firsttime = IPC_TRUE; - Ipc_Boolean_t ipc_secondtime = IPC_FALSE; - Ipc_Boolean_t ipc_delta_cut = IPC_FALSE; - double ipc_last_time = 0.0; - double ipc_last_delta = 0.0; -/* gtri - end - wbk - 12/19/90 - Add IPC stuff */ - - // Fix for sharedsync olddelta: When DCTran processes - // either analog or XSPICE breakpoint, then it subtracts delta from - // ckt->CKTtime. It sends 0 as olddelta after analog breakpoint - // processing. Still, for XSPICE breakpoints it subtracts delta (see code - // 'else if(g_mif_info.breakpoint.current < ckt->CKTtime)' branch) and - // then sends non zero olddelta to sharedsync at the end of the function - // (see chkStep: label). Thus olddelta is subtracted twice. Then - // ckt->CKTtime becomes less than last_accepted_time. - // xspice_breakpoints_processed 0: - // XSPICE models didn't have breakpoints in [last_accepted_time, CKTtime]. - // xspice_breakpoints_processed 1: - // convergence criteria are satisfied but XSPICE breakpoint(s) is in the - // time interval [last_accepted_time, CKTtime]. + /* xspice_breakpoints_processed 0: + XSPICE models didn't have breakpoints in [last_accepted_time, CKTtime]. + xspice_breakpoints_processed 1: + convergence criteria are satisfied but XSPICE breakpoint(s) is in the + time interval [last_accepted_time, CKTtime]. */ int xspice_breakpoints_processed = 0; #ifdef SHARED_MODULE double olddelta_for_shared_sync = 0.0; -#endif // SHARED_MODULE #endif -#if defined CLUSTER || defined SHARED_MODULE +#endif +#if defined SHARED_MODULE int redostep; #endif if(restart || ckt->CKTtime == 0) { + /* dctran() is entered here upon starting transient simulation + with time 0 and restart 1. + ckt->CKTstep, CKTfinalTime, CKTinitTime, CKTmaxStep have been + set already in fcn TRANinit() of traninit.c according to + TSTEP TSTOP TSTART TMAX given on the .tran line. TMAX is set to TSTEP, + if 'set nostepsizelimit' is not given in .spiceinit.*/ + + /* Set the first delta (step) time, typically depending on TSTEP */ delta=MIN(ckt->CKTfinalTime/100,ckt->CKTstep)/10; #ifdef STEPDEBUG @@ -153,6 +144,8 @@ DCtran(CKTcircuit *ckt, ckt->CKTtimePoints = TMALLOC(double, ckt->CKTtimeListSize); /* end LTRA code addition */ + /* Reset the breakpoint list. + Add breakpoints at 0 time and TSTOP (final) time */ if(ckt->CKTbreaks) FREE(ckt->CKTbreaks); ckt->CKTbreaks = TMALLOC(double, 2); if(ckt->CKTbreaks == NULL) return(E_NOMEM); @@ -165,25 +158,23 @@ DCtran(CKTcircuit *ckt, #endif #ifdef XSPICE -/* gtri - begin - wbk - 12/19/90 - Modify setting of CKTminBreak */ - /* Set to 10 times delmin for ATESSE 1 compatibity */ - if(ckt->CKTminBreak==0) ckt->CKTminBreak = 10.0 * ckt->CKTdelmin; -/* gtri - end - wbk - 12/19/90 - Modify setting of CKTminBreak */ + /* Modify setting of CKTminBreak + Set to 10 times delmin (minimum delta step time). */ + if(ckt->CKTminBreak == 0) + ckt->CKTminBreak = 10.0 * ckt->CKTdelmin; + #else - if(ckt->CKTminBreak==0) ckt->CKTminBreak=ckt->CKTmaxStep*5e-5; + if(ckt->CKTminBreak == 0) + ckt->CKTminBreak = ckt->CKTmaxStep * 5e-5; #endif #ifdef XSPICE -/* gtri - add - wbk - 12/19/90 - Add IPC stuff and set anal_init and anal_type */ - /* Tell the beginPlot routine what mode we're in */ - g_ipc.anal_type = IPC_ANAL_TRAN; - + /* set anal_init and anal_type */ /* Tell the code models what mode we're in */ g_mif_info.circuit.anal_type = MIF_DC; - g_mif_info.circuit.anal_init = MIF_TRUE; -/* gtri - end - wbk */ #endif + /* Scan ckt->CKTnodes and create list of node names */ error = CKTnames(ckt,&numNames,&nameList); if(error) return(error); SPfrontEnd->IFnewUid (ckt, &timeUid, NULL, "time", UID_OTHER, NULL); @@ -195,7 +186,7 @@ DCtran(CKTcircuit *ckt, tfree(nameList); if(error) return(error); - /* initialize CKTsoaCheck `warn' counters */ + /* initialize CKTsoaCheck 'warn' counters */ if (ckt->CKTsoaCheck) error = CKTsoaInit(); @@ -224,13 +215,12 @@ DCtran(CKTcircuit *ckt, } #ifdef XSPICE -/* gtri - begin - wbk - set a breakpoint at end of supply ramping time */ - /* must do this after CKTtime set to 0 above */ + /* set a breakpoint at end of supply ramping time. + Must do this after CKTtime is set to 0 above */ if(ckt->enh->ramp.ramptime > 0.0) CKTsetBreak(ckt, ckt->enh->ramp.ramptime); -/* gtri - end - wbk - set a breakpoint at end of supply ramping time */ -/* gtri - begin - wbk - Call EVTop if event-driven instances exist */ + /* Call EVTop if event-driven instances exist */ if(ckt->evt->counts.num_insts != 0) { /* use new DCOP algorithm */ converged = EVTop(ckt, @@ -241,20 +231,19 @@ DCtran(CKTcircuit *ckt, EVTdump(ckt, IPC_ANAL_DCOP, 0.0); EVTop_save(ckt, MIF_FALSE, 0.0); - -/* gtri - end - wbk - Call EVTop if event-driven instances exist */ } else #endif + /* Get operating point for analogue circuit */ converged = CKTop(ckt, (ckt->CKTmode & MODEUIC) | MODETRANOP | MODEINITJCT, (ckt->CKTmode & MODEUIC) | MODETRANOP | MODEINITFLOAT, ckt->CKTdcMaxIter); if(converged != 0) { - fprintf(stdout,"\nTransient solution failed -\n"); + fprintf(stderr,"\nError: Finding the operating point for transient simulation failed \n"); CKTncDump(ckt); - fprintf(stdout,"\n"); - fflush(stdout); + fprintf(stderr,"\n"); + fflush(stderr); } else if (ckt->CKTmode & MODEUIC && !ft_ngdebug) { fprintf(stdout,"Operating point simulation skipped by 'uic',\n"); fprintf(stdout," now using transient initial conditions.\n"); @@ -273,45 +262,30 @@ DCtran(CKTcircuit *ckt, fflush(stdout); } + /* return upon failure to converge during op */ if (converged != 0) { SPfrontEnd->OUTendPlot(job->TRANplot); return(converged); } #ifdef XSPICE -/* gtri - add - wbk - 12/19/90 - Add IPC stuff */ - - /* Send the operating point results for Mspice compatibility */ - if(g_ipc.enabled) { - ipc_send_dcop_prefix(); - CKTdump(ckt, 0.0, job->TRANplot); - ipc_send_dcop_suffix(); - } - -/* gtri - end - wbk */ - -/* gtri - add - wbk - 12/19/90 - set anal_init and anal_type */ - + /* set anal_init and anal_type */ g_mif_info.circuit.anal_init = MIF_TRUE; /* Tell the code models what mode we're in */ g_mif_info.circuit.anal_type = MIF_TRAN; -/* gtri - end - wbk */ - -/* gtri - begin - wbk - Add Breakpoint stuff */ - + /* Breakpoint stuff */ /* Initialize the temporary breakpoint variables to infinity */ g_mif_info.breakpoint.current = 1.0e30; g_mif_info.breakpoint.last = 1.0e30; - -/* gtri - end - wbk - Add Breakpoint stuff */ #endif ckt->CKTstat->STATtimePts ++; ckt->CKTorder = 1; + /* Initialze CKTdeltaOld with maximum value */ for(i=0;i<7;i++) { ckt->CKTdeltaOld[i]=ckt->CKTmaxStep; } - ckt->CKTdelta = delta; + ckt->CKTdelta = delta; /* delta set in line 130 */ #ifdef STEPDEBUG (void)printf("delta initialized to %g\n",ckt->CKTdelta); #endif @@ -337,9 +311,9 @@ DCtran(CKTcircuit *ckt, ckt->CKTorder = save2; } #endif - - ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODETRAN | MODEINITTRAN; /* modeinittran set here */ + ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODETRAN | MODEINITTRAN; + /* Reset the gear variable coefficient matrix. */ ckt->CKTag[0]=ckt->CKTag[1]=0; if (ckt->CKTstate1 && ckt->CKTstate0) { memcpy(ckt->CKTstate1, ckt->CKTstate0, @@ -355,17 +329,17 @@ DCtran(CKTcircuit *ckt, #endif INIT_STATS(); -#ifdef CLUSTER - CLUsetup(ckt); -#endif + + /* End of (restart || ckt->CKTtime == 0) */ } else { - /* saj As traninit resets CKTmode */ + /* traninit resets CKTmode */ ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODETRAN | MODEINITPRED; - /* saj */ + INIT_STATS(); - if(ckt->CKTminBreak==0) ckt->CKTminBreak=ckt->CKTmaxStep*5e-5; + if(ckt->CKTminBreak == 0) + ckt->CKTminBreak = ckt->CKTmaxStep * 5e-5; firsttime=0; - /* To get rawfile working saj*/ + /* To get rawfile working */ error = SPfrontEnd->OUTpBeginPlot (NULL, NULL, NULL, NULL, 0, @@ -375,11 +349,9 @@ DCtran(CKTcircuit *ckt, fprintf(stderr, "Couldn't relink rawfile\n"); return error; } - /* end saj*/ - goto resume; + goto resume; /* line 515 */ } -/* 650 */ nextTime: /* begin LTRA code addition */ @@ -401,7 +373,8 @@ DCtran(CKTcircuit *ckt, error = CKTaccept(ckt); /* check if current breakpoint is outdated; if so, clear */ - if (ckt->CKTtime > ckt->CKTbreaks[0]) CKTclrBreak(ckt); + if (ckt->CKTtime > ckt->CKTbreaks[0]) + CKTclrBreak(ckt); if (ckt->CKTsoaCheck) error = CKTsoaCheck(ckt); @@ -429,71 +402,30 @@ DCtran(CKTcircuit *ckt, UPDATE_STATS(DOING_TRAN); return(error); } + #ifdef XSPICE -/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */ - - if ((g_ipc.enabled) || wantevtdata) { - + /* Send evt data stuff in shared library */ + if (wantevtdata) { /* Send event-driven results */ EVTdump(ckt, IPC_ANAL_TRAN, 0.0); - /* Then follow with analog results... */ - - /* Test to see if delta was cut by a breakpoint, */ - /* a non-convergence, or a too large truncation error */ - if(ipc_firsttime) - ipc_delta_cut = IPC_FALSE; - else if(ckt->CKTtime < (ipc_last_time + (0.999 * ipc_last_delta))) - ipc_delta_cut = IPC_TRUE; - else - ipc_delta_cut = IPC_FALSE; - - /* Record the data required to check for delta cuts */ - ipc_last_time = ckt->CKTtime; - ipc_last_delta = MIN(ckt->CKTdelta, ckt->CKTmaxStep); - - /* Send results data if time since last dump is greater */ - /* than 'mintime', or if first or second timepoints, */ - /* or if delta was cut */ - if( (ckt->CKTtime >= (g_ipc.mintime + g_ipc.last_time)) || - ipc_firsttime || ipc_secondtime || ipc_delta_cut ) { - - if (wantevtdata) - CKTdump(ckt, ckt->CKTtime, job->TRANplot); - else { - ipc_send_data_prefix(ckt->CKTtime); - CKTdump(ckt, ckt->CKTtime, job->TRANplot); - ipc_send_data_suffix(); - } - - if(ipc_firsttime) { - ipc_firsttime = IPC_FALSE; - ipc_secondtime = IPC_TRUE; - } else if(ipc_secondtime) { - ipc_secondtime = IPC_FALSE; - } - - g_ipc.last_time = ckt->CKTtime; - } - } else -/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */ + } #endif -#ifdef CLUSTER - CLUoutput(ckt); -#endif - if((ckt->CKTmode&MODEUIC && ckt->CKTtime > 0 && ckt->CKTtime >= ckt->CKTinitTime) - || (!(ckt->CKTmode&MODEUIC) && ckt->CKTtime >= ckt->CKTinitTime)) - CKTdump(ckt, ckt->CKTtime, job->TRANplot); + + /* Output the data of the current accepted time point */ + if ((ckt->CKTmode & MODEUIC && ckt->CKTtime > 0 && ckt->CKTtime >= ckt->CKTinitTime) + || (!(ckt->CKTmode & MODEUIC) && ckt->CKTtime >= ckt->CKTinitTime)) { + CKTdump(ckt, ckt->CKTtime, job->TRANplot); + } #ifdef XSPICE -/* gtri - begin - wbk - Update event queues/data for accepted timepoint */ - /* Note: this must be done AFTER sending results to SI so it can't */ - /* go next to CKTaccept() above */ + /* Update event queues/data for accepted timepoint */ + /* Note: this must be done AFTER sending results to SI so it can't + go next to CKTaccept() above */ if(ckt->evt->counts.num_insts > 0) EVTaccept(ckt, ckt->CKTtime); -/* gtri - end - wbk - Update event queues/data for accepted timepoint */ #endif ckt->CKTstat->STAToldIter = ckt->CKTstat->STATnumIter; - /* check for the end of the tran simulation, either by< stop time given, + /* Check for the end of the tran simulation, either by stop time given, or final time has been reached. */ if (have_autostop) /* time consuming autostop check only, when variable 'autostop' has been set @@ -516,7 +448,7 @@ DCtran(CKTcircuit *ckt, if (flag_autostop) fprintf(stdout, "\nNote: Autostop after %e s, all measurement conditions are fulfilled.\n", ckt->CKTtime); - /* Final return from tran*/ + /* Final return from tran upon success */ return(OK); } if(SPfrontEnd->IFpauseTest()) { @@ -543,25 +475,21 @@ resume: else SetAnalyse( "tran", (int)((ckt->CKTtime * 1000.) / ckt->CKTfinalTime + 0.5)); #endif - ckt->CKTdelta = - MIN(ckt->CKTdelta,ckt->CKTmaxStep); + + ckt->CKTdelta = MIN(ckt->CKTdelta,ckt->CKTmaxStep); + #ifdef XSPICE -/* gtri - begin - wbk - Cut integration order if first timepoint after breakpoint */ - /* if(ckt->CKTtime == g_mif_info.breakpoint.last) */ + /* Cut integration order if first timepoint after breakpoint */ if ( AlmostEqualUlps( ckt->CKTtime, g_mif_info.breakpoint.last, 100 ) ) ckt->CKTorder = 1; -/* gtri - end - wbk - Cut integration order if first timepoint after breakpoint */ - #endif - /* are we at a breakpoint, or indistinguishably close? */ - /* if ((ckt->CKTtime == ckt->CKTbreaks[0]) || (ckt->CKTbreaks[0] - */ + /* Are we at a breakpoint, or indistinguishably close? */ if ( AlmostEqualUlps( ckt->CKTtime, ckt->CKTbreaks[0], 100 ) || ckt->CKTbreaks[0] - ckt->CKTtime <= ckt->CKTdelmin) { - /* first timepoint after a breakpoint - cut integration order */ - /* and limit timestep to .1 times minimum of time to next breakpoint, - * and previous timestep - */ + /* First timepoint after a breakpoint: cut integration order + and limit timestep to .1 times minimum of time to next breakpoint, + and previous timestep. */ ckt->CKTorder = 1; #ifdef STEPDEBUG if( (ckt->CKTdelta > .1*ckt->CKTsaveDelta) || @@ -597,6 +525,7 @@ resume: } #ifndef XSPICE + /* Force the breakpoint if appropriate */ else if(ckt->CKTtime + ckt->CKTdelta >= ckt->CKTbreaks[0]) { ckt->CKTsaveDelta = ckt->CKTdelta; ckt->CKTdelta = ckt->CKTbreaks[0] - ckt->CKTtime; @@ -606,15 +535,23 @@ resume: #endif ckt->CKTbreak = 1; /* why? the current pt. is not a bkpt. */ } + /* Try to equalise the last two time steps before the breakpoint, + if the second step would be smaller than CKTdelta otherwise.*/ + else if (ckt->CKTtime + 1.9 * ckt->CKTdelta > ckt->CKTbreaks[0]) { + ckt->CKTsaveDelta = ckt->CKTdelta; + ckt->CKTdelta = (ckt->CKTbreaks[0] - ckt->CKTtime) / 2.; +#ifdef STEPDEBUG + fprintf(stdout, "Delta equalising step at time %e with delta %e\n", ckt->CKTtime, ckt->CKTdelta); +#endif + } #endif /* !XSPICE */ #ifdef XSPICE -/* gtri - begin - wbk - Add Breakpoint stuff */ - + /* More Breakpoint stuff */ if(ckt->CKTtime + ckt->CKTdelta >= g_mif_info.breakpoint.current) { - /* If next time > temporary breakpoint, force it to the breakpoint */ - /* And mark that timestep was set by temporary breakpoint */ + /* If next time > temporary breakpoint, force it to the breakpoint, + and mark that timestep was set by temporary breakpoint */ ckt->CKTsaveDelta = ckt->CKTdelta; ckt->CKTdelta = g_mif_info.breakpoint.current - ckt->CKTtime; g_mif_info.breakpoint.last = ckt->CKTtime + ckt->CKTdelta; @@ -623,12 +560,8 @@ resume: g_mif_info.breakpoint.last = 1.0e30; } -/* gtri - end - wbk - Add Breakpoint stuff */ - -/* gtri - begin - wbk - Modify Breakpoint stuff */ /* Throw out any permanent breakpoint with time <= current time or in the - * very near future, unless it the final stop break. - */ + very near future, unless it is the final stop break. */ #ifdef STEPDEBUG printf(" brk_pt: %g ckt_time: %g ckt_min_break: %g\n", ckt->CKTbreaks[0], ckt->CKTtime, ckt->CKTminBreak); @@ -651,8 +584,15 @@ resume: ckt->CKTsaveDelta = ckt->CKTdelta; ckt->CKTdelta = ckt->CKTbreaks[0] - ckt->CKTtime; } - -/* gtri - end - wbk - Modify Breakpoint stuff */ + /* Try to equalise the last two time steps before the breakpoint, + if the second step would be smaller than CKTdelta otherwise.*/ + else if (ckt->CKTtime + 1.9 * ckt->CKTdelta > ckt->CKTbreaks[0]) { + ckt->CKTsaveDelta = ckt->CKTdelta; + ckt->CKTdelta = (ckt->CKTbreaks[0] - ckt->CKTtime) / 2.; +#ifdef STEPDEBUG + fprintf(stdout, "Delta equalising step at time %e with delta %e\n", ckt->CKTtime, ckt->CKTdelta); +#endif + } #ifdef SHARED_MODULE /* Either directly go to next time step, or modify ckt->CKTdelta depending on @@ -661,17 +601,16 @@ resume: ckt->CKTdelmin, 0, &ckt->CKTstat->STATrejected, 0); #endif -/* gtri - begin - wbk - Do event solution */ - + /* Do event solution */ if(ckt->evt->counts.num_insts > 0) { - /* if time = 0 and op_alternate was specified as false during */ - /* dcop analysis, call any changed instances to let them */ - /* post their outputs with their associated delays */ + /* If time = 0 and op_alternate was specified as false during + dcop analysis, call any changed instances to let them + post their outputs with their associated delays */ if((ckt->CKTtime == 0.0) && (! ckt->evt->options.op_alternate)) EVTiter(ckt); - /* while there are events on the queue with event time <= next */ + /* While there are events on the queue with event time <= next */ /* projected analog time, process them */ while((g_mif_info.circuit.evt_step = EVTnext_time(ckt)) <= (ckt->CKTtime + ckt->CKTdelta)) { @@ -683,14 +622,14 @@ resume: EVTdequeue(ckt, g_mif_info.circuit.evt_step); EVTiter(ckt); - /* If any instances have forced an earlier */ - /* next analog time, cut the delta */ + /* If any instances have forced an earlier + next analog time, cut the delta */ if(ckt->CKTbreaks[0] < g_mif_info.breakpoint.current) if(ckt->CKTbreaks[0] > ckt->CKTtime + ckt->CKTminBreak) g_mif_info.breakpoint.current = ckt->CKTbreaks[0]; if(g_mif_info.breakpoint.current < ckt->CKTtime + ckt->CKTdelta) { - /* Breakpoint must be > last accepted timepoint */ - /* and >= current event time */ + /* Breakpoint must be > last accepted timepoint + and >= current event time */ if(g_mif_info.breakpoint.current > ckt->CKTtime + ckt->CKTminBreak && g_mif_info.breakpoint.current >= g_mif_info.circuit.evt_step) { ckt->CKTsaveDelta = ckt->CKTdelta; @@ -702,16 +641,8 @@ resume: } /* end while next event time <= next analog time */ } /* end if there are event instances */ -/* gtri - end - wbk - Do event solution */ #else /* no XSPICE */ -#ifdef CLUSTER - if(!CLUsync(ckt->CKTtime,&ckt->CKTdelta,0)) { - printf("Sync error!\n"); - exit(0); - } -#endif /* CLUSTER */ - #ifdef SHARED_MODULE /* Either directly go to next time step, or modify ckt->CKTdelta depending on synchronization requirements. sharedsync() returns 0. @@ -733,26 +664,19 @@ resume: /* 600 */ for (;;) { -#if defined CLUSTER || defined SHARED_MODULE +#if defined SHARED_MODULE redostep = 1; #endif #ifdef XSPICE -/* gtri - add - wbk - 4/17/91 - Fix Berkeley bug */ -/* This is needed here to allow CAPask to output currents */ -/* during Transient analysis. A grep for CKTcurrentAnalysis */ -/* indicates that it should not hurt anything else ... */ - +/* This is needed here to allow CAPask to output currents + during Transient analysis. */ ckt->CKTcurrentAnalysis = DOING_TRAN; -/* gtri - end - wbk - 4/17/91 - Fix Berkeley bug */ xspice_breakpoints_processed = 0; #endif olddelta=ckt->CKTdelta; /* time abort? */ ckt->CKTtime += ckt->CKTdelta; -#ifdef CLUSTER - CLUinput(ckt); -#endif ckt->CKTdeltaOld[0]=ckt->CKTdelta; NIcomCof(ckt); #ifdef PREDICTOR @@ -761,33 +685,25 @@ resume: save_mode = ckt->CKTmode; save_order = ckt->CKTorder; #ifdef XSPICE -/* gtri - begin - wbk - Add Breakpoint stuff */ /* Initialize temporary breakpoint to infinity */ g_mif_info.breakpoint.current = 1.0e30; -/* gtri - end - wbk - Add Breakpoint stuff */ - - -/* gtri - begin - wbk - add convergence problem reporting flags */ + /* Add convergence problem reporting flags */ /* delta is forced to equal delmin on last attempt near line 650 */ if(ckt->CKTdelta <= ckt->CKTdelmin) ckt->enh->conv_debug.last_NIiter_call = MIF_TRUE; else ckt->enh->conv_debug.last_NIiter_call = MIF_FALSE; -/* gtri - begin - wbk - add convergence problem reporting flags */ +/* Call all hybrids */ -/* gtri - begin - wbk - Call all hybrids */ - -/* gtri - begin - wbk - Set evt_step */ - + /* Set evt_step */ if(ckt->evt->counts.num_insts > 0) { g_mif_info.circuit.evt_step = ckt->CKTtime; } -/* gtri - end - wbk - Set evt_step */ #endif - + /* Central solver step */ converged = NIiter(ckt,ckt->CKTtranMaxIter); ckt->CKTstat->STATtimePts ++; @@ -803,14 +719,14 @@ resume: return(converged); } + /* If no convergence in Central solver step */ if(converged != 0) { -#ifndef CLUSTER + #ifndef SHARED_MODULE ckt->CKTtime = ckt->CKTtime -ckt->CKTdelta; ckt->CKTstat->STATrejected ++; #else redostep = 1; -#endif #endif ckt->CKTdelta = ckt->CKTdelta/8; #ifdef STEPDEBUG @@ -823,10 +739,12 @@ resume: ckt->CKTorder = 1; #ifdef XSPICE -/* gtri - begin - wbk - Add Breakpoint stuff */ - + /* Add Breakpoint stuff */ } else if(g_mif_info.breakpoint.current < ckt->CKTtime) { - /* Force backup if temporary breakpoint is < current time */ + /* Force backup if temporary breakpoint is < current time: + - save old delta + - retract time by old delta + - new delta by difference between by retracted time and breakpoint */ past_breakpoint: ckt->CKTsaveDelta = ckt->CKTdelta; @@ -839,11 +757,13 @@ resume: ckt->CKTmode = (ckt->CKTmode&MODEUIC)|MODETRAN | MODEINITTRAN; } ckt->CKTorder = 1; - -/* gtri - end - wbk - Add Breakpoint stuff */ #endif } else { + /* If converged: + - go to next time step if this was the first time. + - If not the first time step, don not accept, but check the truncation errors, + and reduce delta accordingly, thenm redo the step, to bound the error. */ if (firsttime) { #ifdef WANT_SENSE2 if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & TRANSEN)){ @@ -860,16 +780,17 @@ resume: } #endif firsttime = 0; -#if !defined CLUSTER && !defined SHARED_MODULE - goto nextTime; /* no check on - * first time point - */ +#if !defined SHARED_MODULE + /* no check on first time point */ + goto nextTime; /* line 373 */ #else redostep = 0; - goto chkStep; + goto chkStep; /* line 987 */ #endif } newdelta = ckt->CKTdelta; + /* Scan through all devices, estimate the truncation error, + and reduce the time step, if necessary.*/ error = CKTtrunc(ckt,&newdelta); if(error) { UPDATE_STATS(DOING_TRAN); @@ -891,13 +812,12 @@ resume: EVTcall_hybrids(ckt); if (g_mif_info.breakpoint.current < ckt->CKTtime) { /* A hybrid requested a breakpoint in the past. */ - - goto past_breakpoint; + goto past_breakpoint; /* line 786 */ } } #endif - - if ((ckt->CKTorder == 1) && (ckt->CKTmaxOrder > 1)) { /* don't rise the order for backward Euler */ + /* don't raise the order for backward Euler */ + if ((ckt->CKTorder == 1) && (ckt->CKTmaxOrder > 1)) { newdelta = ckt->CKTdelta; ckt->CKTorder = 2; error = CKTtrunc(ckt, &newdelta); @@ -947,30 +867,33 @@ resume: } #endif -#if !defined CLUSTER && !defined SHARED_MODULE - /* go to 650 - trapezoidal */ - goto nextTime; +#if !defined SHARED_MODULE + /* trapezoidal */ + goto nextTime; /* line 373 */ #else redostep = 0; - goto chkStep; + goto chkStep; /* line 987 */ #endif } else { -#ifndef CLUSTER + /* not (newdelta > .9 * ckt->CKTdelta): reject the step + - redo the time + - apply the new (reduced) delta */ #ifndef SHARED_MODULE ckt->CKTtime = ckt->CKTtime -ckt->CKTdelta; ckt->CKTstat->STATrejected ++; #else redostep = 1; -#endif #endif ckt->CKTdelta = newdelta; #ifdef STEPDEBUG (void)printf( - "delta set to truncation error result:point rejected\n"); + "delta set to truncation error result: point rejected\n"); #endif } } - + /* Set the new delta to delmin (minimum delta allowed). However: + If the new delta has been less than the minimum delta + for the second time, bail out with 'Timestep too small'. */ if (ckt->CKTdelta <= ckt->CKTdelmin) { if (olddelta > ckt->CKTdelmin) { ckt->CKTdelta = ckt->CKTdelmin; @@ -983,23 +906,23 @@ resume: SPfrontEnd->OUTendPlot(job->TRANplot); job->TRANplot = NULL; UPDATE_STATS(0); + /* return upon convergence failure */ return(E_TIMESTEP); } } #ifdef XSPICE -/* gtri - begin - wbk - Do event backup */ - + /* Do event backup */ if(ckt->evt->counts.num_insts > 0) { #ifdef SHARED_MODULE double discard_start_time = ckt->CKTtime + ckt->CKTdelta; - // ngspice in executable mode subtracts olddelta from the time - // before new delta calculation, but it keeps delta in CKTtime and - // postpones subtraction in library mode. Delayed subtraction leads - // to incorrect points dropping because ckt->CKTdelta is almost always - // less than olddelta if there are convergence issues, and EVTbackup - // may drop valid events that need to be processed within - // [last_accepted_time, last_accepted_time + ckt->CKTdelta] range - // after delta adjustment. + /* ngspice in executable mode subtracts olddelta from the time + before new delta calculation, but it keeps delta in CKTtime and + postpones subtraction in library mode. Delayed subtraction leads + to incorrect points dropping because ckt->CKTdelta is almost always + less than olddelta if there are convergence issues, and EVTbackup + may drop valid events that need to be processed within + [last_accepted_time, last_accepted_time + ckt->CKTdelta] range + after delta adjustment. */ if (redostep && xspice_breakpoints_processed == 0) discard_start_time -= olddelta; EVTbackup(ckt, discard_start_time); @@ -1008,16 +931,6 @@ resume: #endif } -/* gtri - end - wbk - Do event backup */ -#endif -#ifdef CLUSTER - chkStep: - if(CLUsync(ckt->CKTtime,&ckt->CKTdelta,redostep)){ - goto nextTime; - } else { - ckt->CKTtime -= olddelta; - ckt->CKTstat->STATrejected ++; - } #endif #ifdef SHARED_MODULE @@ -1045,11 +958,11 @@ chkStep: olddelta_for_shared_sync = 0.0; if(sharedsync(&ckt->CKTtime, &ckt->CKTdelta, olddelta_for_shared_sync, ckt->CKTfinalTime, ckt->CKTdelmin, redostep, &ckt->CKTstat->STATrejected, 1) == 0) - goto nextTime; + goto nextTime; /* line 373 */ #else if(sharedsync(&ckt->CKTtime, &ckt->CKTdelta, olddelta, ckt->CKTfinalTime, ckt->CKTdelmin, redostep, &ckt->CKTstat->STATrejected, 1) == 0) - goto nextTime; + goto nextTime; /* line 373 */ #endif // XSPICE #endif // SHARED_MODULE diff --git a/src/spicelib/analysis/dctrcurv.c b/src/spicelib/analysis/dctrcurv.c index f2a46d3b4..dd312a637 100644 --- a/src/spicelib/analysis/dctrcurv.c +++ b/src/spicelib/analysis/dctrcurv.c @@ -165,17 +165,12 @@ DCtrCurv(CKTcircuit *ckt, int restart) #endif #ifdef XSPICE -/* gtri - add - wbk - 12/19/90 - Add IPC stuff and anal_init and anal_type */ - - /* Tell the beginPlot routine what mode we're in */ - g_ipc.anal_type = IPC_ANAL_DCTRCURVE; /* Tell the code models what mode we're in */ g_mif_info.circuit.anal_type = MIF_DC; g_mif_info.circuit.anal_init = MIF_TRUE; -/* gtri - end - wbk */ #endif error = CKTnames(ckt, &numNames, &nameList); @@ -383,18 +378,10 @@ DCtrCurv(CKTcircuit *ckt, int restart) ckt->CKTtime = ckt->CKTtemp - CONSTCtoK; #ifdef XSPICE -/* gtri - add - wbk - 12/19/90 - Add IPC stuff */ - /* If first time through, call CKTdump to output Operating Point info */ - /* for Mspice compatibility */ - - if (((g_ipc.enabled) || wantevtdata) && firstTime) { - ipc_send_dcop_prefix(); + if (wantevtdata && firstTime) { CKTdump(ckt, 0.0, plot); - ipc_send_dcop_suffix(); } - -/* gtri - end - wbk */ #endif #ifdef WANT_SENSE2 @@ -435,25 +422,11 @@ DCtrCurv(CKTcircuit *ckt, int restart) } #endif -#ifdef XSPICE -/* gtri - modify - wbk - 12/19/90 - Send IPC delimiters */ - - if (g_ipc.enabled) - ipc_send_data_prefix(ckt->CKTtime); -#endif - CKTdump(ckt,ckt->CKTtime,plot); if (ckt->CKTsoaCheck) error = CKTsoaCheck(ckt); -#ifdef XSPICE - if (g_ipc.enabled) - ipc_send_data_suffix(); - -/* gtri - end - wbk */ -#endif - if (firstTime) { firstTime = 0; if (ckt->CKTstate1 && ckt->CKTstate0) { diff --git a/src/spicelib/analysis/noisean.c b/src/spicelib/analysis/noisean.c index 5115f854f..3eeca41f2 100644 --- a/src/spicelib/analysis/noisean.c +++ b/src/spicelib/analysis/noisean.c @@ -65,16 +65,9 @@ NOISEan(CKTcircuit* ckt, int restart) runDesc* plot = NULL; #ifdef XSPICE - /* gtri - add - wbk - 12/19/90 - Add IPC stuff and anal_init and anal_type */ - - /* Tell the beginPlot routine what mode we're in */ - g_ipc.anal_type = IPC_ANAL_NOI; - /* Tell the code models what mode we're in */ g_mif_info.circuit.anal_type = MIF_DC; g_mif_info.circuit.anal_init = MIF_TRUE; - - /* gtri - end - wbk */ #endif #ifdef KLU @@ -189,19 +182,18 @@ NOISEan(CKTcircuit* ckt, int restart) EVTop_save(ckt, MIF_TRUE, 0.0); } else - { // start of no XSPICE event-driven instances #endif - + { // start of no XSPICE event-driven instances #ifdef KLU - if (ckt->CKTmatrix->CKTkluMODE) - { - /* Conversion from Complex Matrix to Real Matrix */ - for (i = 0 ; i < DEVmaxnum ; i++) - if (DEVices [i] && DEVices [i]->DEVbindCSCComplexToReal && ckt->CKThead [i]) - DEVices [i]->DEVbindCSCComplexToReal (ckt->CKThead [i], ckt) ; + if (ckt->CKTmatrix->CKTkluMODE) + { + /* Conversion from Complex Matrix to Real Matrix */ + for (i = 0 ; i < DEVmaxnum ; i++) + if (DEVices [i] && DEVices [i]->DEVbindCSCComplexToReal && ckt->CKThead [i]) + DEVices [i]->DEVbindCSCComplexToReal (ckt->CKThead [i], ckt) ; - ckt->CKTmatrix->SMPkluMatrix->KLUmatrixIsComplex = KLUmatrixReal ; - } + ckt->CKTmatrix->SMPkluMatrix->KLUmatrixIsComplex = KLUmatrixReal ; + } #endif /* If no event-driven instances, do what SPICE normally does */ @@ -220,43 +212,8 @@ NOISEan(CKTcircuit* ckt, int restart) else { fprintf(stdout, "\n Linear circuit, option noopac given: no OP analysis\n"); } - -#ifdef XSPICE } // end of no XSPICE event-driven instances - /* gtri - add - wbk - 12/19/90 - Add IPC stuff */ - - /* Send the operating point results for Mspice compatibility */ - if (g_ipc.enabled) - { - /* Call CKTnames to get names of nodes/branches used by - BeginPlot */ - /* Probably should free nameList after this block since - called again... */ - error = CKTnames(ckt, &numNames, &nameList); - if (error) return(error); - - /* We have to do a beginPlot here since the data to return is - * different for the DCOP than it is for the AC analysis. - * Moreover the begin plot has not even been done yet at this - * point... - */ - SPfrontEnd->OUTpBeginPlot(ckt, ckt->CKTcurJob, - ckt->CKTcurJob->JOBname, - NULL, IF_REAL, - numNames, nameList, IF_REAL, - &noiPlot); - txfree(nameList); - - ipc_send_dcop_prefix(); - CKTdump(ckt, 0.0, noiPlot); - ipc_send_dcop_suffix(); - - SPfrontEnd->OUTendPlot(noiPlot); - } - /* gtri - end - wbk */ -#endif - /* Patch to noisean.c by Richard D. McRoberts. */ ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG; error = CKTload(ckt); diff --git a/src/spicelib/analysis/optran.c b/src/spicelib/analysis/optran.c index 8483560f3..0ba875d97 100644 --- a/src/spicelib/analysis/optran.c +++ b/src/spicelib/analysis/optran.c @@ -67,6 +67,8 @@ static bool nooptran = TRUE; we firstly fill the static vars opstepsize, opfinaltime, and opramptime. Later from inp.c we call com_optran again and set the data in ft_curckt->ci_defTask. + + com_optran is called from cp_init() as 'optran 1 1 1 100n 10u 0'. */ void com_optran(wordlist* wl) { wordlist* wltmp = wl; @@ -177,8 +179,10 @@ void com_optran(wordlist* wl) { goto bugquit; } /* optran deselected by setting opstepsize to 0 */ - if (opstepsize == 0) + if (opstepsize == 0) { nooptran = TRUE; + fprintf(stdout, "Note: Optran is deselected"); + } dataset = TRUE; if (errno == 0) @@ -311,8 +315,8 @@ OPtran(CKTcircuit *ckt, int oldconverged) int redostep; #endif - /* if optran command has not been given (in .spiceinit or in .control section), - we don' use optran */ + /* if optran command with step size 0 has been set in in .spiceinit or in .control section, + we don't use optran */ if (nooptran) return oldconverged; /* diff --git a/src/spicelib/analysis/span.c b/src/spicelib/analysis/span.c index 46c7756fe..b70eab72d 100644 --- a/src/spicelib/analysis/span.c +++ b/src/spicelib/analysis/span.c @@ -386,18 +386,9 @@ SPan(CKTcircuit* ckt, int restart) } #ifdef XSPICE - /* gtri - add - wbk - 12/19/90 - Add IPC stuff and anal_init and anal_type */ - - /* Tell the beginPlot routine what mode we're in */ - - // For now, let's keep this as IPC_ANAL_AC (TBD) - g_ipc.anal_type = IPC_ANAL_AC; - /* Tell the code models what mode we're in */ g_mif_info.circuit.anal_type = MIF_DC; g_mif_info.circuit.anal_init = MIF_TRUE; - - /* gtri - end - wbk */ #endif /* start at beginning */ @@ -475,40 +466,6 @@ SPan(CKTcircuit* ckt, int restart) else fprintf(stdout, "\n Linear circuit, option noopac given: no OP analysis\n"); -#ifdef XSPICE - /* gtri - add - wbk - 12/19/90 - Add IPC stuff */ - - /* Send the operating point results for Mspice compatibility */ - if (g_ipc.enabled) - { - /* Call CKTnames to get names of nodes/branches used by - BeginPlot */ - /* Probably should free nameList after this block since - called again... */ - error = CKTnames(ckt, &numNames, &nameList); - if (error) return(error); - - /* We have to do a beginPlot here since the data to return is - * different for the DCOP than it is for the AC analysis. - * Moreover the begin plot has not even been done yet at this - * point... - */ - SPfrontEnd->OUTpBeginPlot(ckt, ckt->CKTcurJob, - ckt->CKTcurJob->JOBname, - NULL, IF_REAL, - numNames, nameList, IF_REAL, - &spPlot); - txfree(nameList); - - ipc_send_dcop_prefix(); - CKTdump(ckt, 0.0, spPlot); - ipc_send_dcop_suffix(); - - SPfrontEnd->OUTendPlot(spPlot); - } - /* gtri - end - wbk */ -#endif - ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG; error = CKTload(ckt); if (error) return(error); @@ -937,22 +894,8 @@ SPan(CKTcircuit* ckt, int restart) data->lstFreq = freq; } - -#ifdef XSPICE - /* gtri - modify - wbk - 12/19/90 - Send IPC stuff */ - - if (g_ipc.enabled) - ipc_send_data_prefix(freq); - error = CKTspDump(ckt, freq, spPlot, job->SPdoNoise); - if (g_ipc.enabled) - ipc_send_data_suffix(); - - /* gtri - modify - wbk - 12/19/90 - Send IPC stuff */ -#else - error = CKTspDump(ckt, freq, spPlot, job->SPdoNoise); -#endif if (error) { UPDATE_STATS(DOING_AC); tfree(internalNoiseAN); diff --git a/src/spicelib/devices/dio/dio.c b/src/spicelib/devices/dio/dio.c index 3c4ff131c..8814c5a1a 100644 --- a/src/spicelib/devices/dio/dio.c +++ b/src/spicelib/devices/dio/dio.c @@ -55,6 +55,7 @@ IFparm DIOmPTable[] = { /* model parameters */ IOPU( "tnom",DIO_MOD_TNOM,IF_REAL, "Parameter measurement temperature"), IOPUR("tref",DIO_MOD_TNOM,IF_REAL, "Parameter measurement temperature"), IOP( "rs", DIO_MOD_RS, IF_REAL, "Ohmic resistance"), + IOP( "rsw", DIO_MOD_RSW, IF_REAL, "Ohmic resistance sidewall"), IOP( "trs", DIO_MOD_TRS, IF_REAL, "Ohmic resistance 1st order temp. coeff."), IOPR( "trs1", DIO_MOD_TRS, IF_REAL, "Ohmic resistance 1st order temp. coeff."), IOP( "trs2", DIO_MOD_TRS2, IF_REAL, "Ohmic resistance 2nd order temp. coeff."), @@ -80,6 +81,7 @@ IFparm DIOmPTable[] = { /* model parameters */ IOP( "ikf", DIO_MOD_IKF, IF_REAL, "Forward Knee current"), IOPR( "ik", DIO_MOD_IKF, IF_REAL, "Forward Knee current"), IOP( "ikr", DIO_MOD_IKR, IF_REAL, "Reverse Knee current"), + IOP( "ikp", DIO_MOD_IKP, IF_REAL, "Forward Sw Knee current"), IOP( "nbv", DIO_MOD_NBV, IF_REAL, "Breakdown Emission Coefficient"), IOPR( "nz", DIO_MOD_NBV, IF_REAL, "Breakdown Emission Coefficient"), IOP("area", DIO_MOD_AREA, IF_REAL, "Area factor"), diff --git a/src/spicelib/devices/dio/dioacld.c b/src/spicelib/devices/dio/dioacld.c index d7e68c41b..62ad65efd 100644 --- a/src/spicelib/devices/dio/dioacld.c +++ b/src/spicelib/devices/dio/dioacld.c @@ -17,7 +17,7 @@ int DIOacLoad(GENmodel *inModel, CKTcircuit *ckt) { DIOmodel *model = (DIOmodel*)inModel; - double gspr; + double gspr, gsprsw; double geq; double xceq; DIOinstance *here; @@ -42,6 +42,23 @@ DIOacLoad(GENmodel *inModel, CKTcircuit *ckt) *(here->DIOposPrimePosPtr ) -= gspr; *(here->DIOposPrimeNegPtr ) -= geq; *(here->DIOposPrimeNegPtr +1 ) -= xceq; + if (model->DIOresistSWGiven) { + gsprsw=here->DIOtConductanceSW; + geq= *(ckt->CKTstate0 + here->DIOconductSW); + xceq= *(ckt->CKTstate0 + here->DIOcapCurrentSW) * ckt->CKTomega; + *(here->DIOposPosPtr) += gsprsw; + *(here->DIOnegNegPtr) += geq; + *(here->DIOnegNegPtr + 1) += xceq; + *(here->DIOposSwPrimePosSwPrimePtr) += (geq + gsprsw); + *(here->DIOposSwPrimePosSwPrimePtr + 1) += xceq; + *(here->DIOposPosSwPrimePtr) -= gsprsw; + *(here->DIOnegPosSwPrimePtr) -= geq; + *(here->DIOnegPosSwPrimePtr + 1) -= xceq; + *(here->DIOposSwPrimePosPtr) -= gsprsw; + *(here->DIOposSwPrimeNegPtr) -= geq; + *(here->DIOposSwPrimeNegPtr + 1) -= xceq; + } + int selfheat = ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given)); if (selfheat) { double dIth_dVrs = here->DIOdIth_dVrs; @@ -60,6 +77,19 @@ DIOacLoad(GENmodel *inModel, CKTcircuit *ckt) double xgcTt= *(ckt->CKTstate0 + here->DIOcqth) * ckt->CKTomega; (*(here->DIOtempTempPtr + 1) += xgcTt); + + if (model->DIOresistSWGiven) { + double dIth_dVrssw = here->DIOdIth_dVrs; + double dIth_dVdioSw = here->DIOdIth_dVdio; + double dIrssw_dT = here->DIOdIrs_dT; + double dIdioSw_dT = *(ckt->CKTstate0 + here->DIOdIdio_dT); + (*(here->DIOtempPosPtr) += -dIth_dVrssw); + (*(here->DIOtempPosSwPrimePtr) += -dIth_dVdioSw + dIth_dVrssw); + (*(here->DIOtempNegPtr) += dIth_dVdioSw); + (*(here->DIOposTempPtr) += dIrssw_dT); + (*(here->DIOposSwPrimeTempPtr) += dIdioSw_dT - dIrssw_dT); + (*(here->DIOnegTempPtr) += -dIdioSw_dT); + } } } } diff --git a/src/spicelib/devices/dio/diobindCSC.c b/src/spicelib/devices/dio/diobindCSC.c index c33557307..a5df3db3d 100644 --- a/src/spicelib/devices/dio/diobindCSC.c +++ b/src/spicelib/devices/dio/diobindCSC.c @@ -32,6 +32,12 @@ DIObindCSC (GENmodel *inModel, CKTcircuit *ckt) CREATE_KLU_BINDING_TABLE(DIOposPosPtr, DIOposPosBinding, DIOposNode, DIOposNode); CREATE_KLU_BINDING_TABLE(DIOnegNegPtr, DIOnegNegBinding, DIOnegNode, DIOnegNode); CREATE_KLU_BINDING_TABLE(DIOposPrimePosPrimePtr, DIOposPrimePosPrimeBinding, DIOposPrimeNode, DIOposPrimeNode); + /* separate sidewall */ + CREATE_KLU_BINDING_TABLE(DIOposPosSwPrimePtr,DIOposPosSwPrimeBinding,DIOposNode,DIOposSwPrimeNode); + CREATE_KLU_BINDING_TABLE(DIOnegPosSwPrimePtr,DIOnegPosSwPrimeBinding,DIOnegNode,DIOposSwPrimeNode); + CREATE_KLU_BINDING_TABLE(DIOposSwPrimePosPtr,DIOposSwPrimePosBinding,DIOposSwPrimeNode,DIOposNode); + CREATE_KLU_BINDING_TABLE(DIOposSwPrimeNegPtr,DIOposSwPrimeNegBinding,DIOposSwPrimeNode,DIOnegNode); + CREATE_KLU_BINDING_TABLE(DIOposSwPrimePosSwPrimePtr,DIOposSwPrimePosSwPrimeBinding,DIOposSwPrimeNode,DIOposSwPrimeNode); if ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given)) { CREATE_KLU_BINDING_TABLE(DIOtempPosPtr, DIOtempPosBinding, DIOtempNode, DIOposNode); CREATE_KLU_BINDING_TABLE(DIOtempPosPrimePtr, DIOtempPosPrimeBinding, DIOtempNode, DIOposPrimeNode); @@ -40,6 +46,9 @@ DIObindCSC (GENmodel *inModel, CKTcircuit *ckt) CREATE_KLU_BINDING_TABLE(DIOposTempPtr, DIOposTempBinding, DIOposNode, DIOtempNode); CREATE_KLU_BINDING_TABLE(DIOposPrimeTempPtr, DIOposPrimeTempBinding, DIOposPrimeNode, DIOtempNode); CREATE_KLU_BINDING_TABLE(DIOnegTempPtr, DIOnegTempBinding, DIOnegNode, DIOtempNode); + /* separate sidewall */ + CREATE_KLU_BINDING_TABLE(DIOtempPosSwPrimePtr, DIOtempPosSwPrimeBinding, DIOtempNode, DIOposSwPrimeNode); + CREATE_KLU_BINDING_TABLE(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode); } } } @@ -68,6 +77,12 @@ DIObindCSCComplex (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposPosPtr, DIOposPosBinding, DIOposNode, DIOposNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOnegNegPtr, DIOnegNegBinding, DIOnegNode, DIOnegNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposPrimePosPrimePtr, DIOposPrimePosPrimeBinding, DIOposPrimeNode, DIOposPrimeNode); + /* separate sidewall */ + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposPosSwPrimePtr,DIOposPosSwPrimeBinding,DIOposNode,DIOposSwPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOnegPosSwPrimePtr,DIOnegPosSwPrimeBinding,DIOnegNode,DIOposSwPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimePosPtr,DIOposSwPrimePosBinding,DIOposSwPrimeNode,DIOposNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimeNegPtr,DIOposSwPrimeNegBinding,DIOposSwPrimeNode,DIOnegNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimePosSwPrimePtr,DIOposSwPrimePosSwPrimeBinding,DIOposSwPrimeNode,DIOposSwPrimeNode); if ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given)) { CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOtempPosPtr, DIOtempPosBinding, DIOtempNode, DIOposNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOtempPosPrimePtr, DIOtempPosPrimeBinding, DIOtempNode, DIOposPrimeNode); @@ -76,6 +91,9 @@ DIObindCSCComplex (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposTempPtr, DIOposTempBinding, DIOposNode, DIOtempNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposPrimeTempPtr, DIOposPrimeTempBinding, DIOposPrimeNode, DIOtempNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOnegTempPtr, DIOnegTempBinding, DIOnegNode, DIOtempNode); + /* separate sidewall */ + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOtempPosSwPrimePtr, DIOtempPosSwPrimeBinding, DIOtempNode, DIOposSwPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode); } } } @@ -104,6 +122,12 @@ DIObindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposPosPtr, DIOposPosBinding, DIOposNode, DIOposNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOnegNegPtr, DIOnegNegBinding, DIOnegNode, DIOnegNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposPrimePosPrimePtr, DIOposPrimePosPrimeBinding, DIOposPrimeNode, DIOposPrimeNode); + /* separate sidewall */ + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposPosSwPrimePtr,DIOposPosSwPrimeBinding,DIOposNode,DIOposSwPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOnegPosSwPrimePtr,DIOnegPosSwPrimeBinding,DIOnegNode,DIOposSwPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimePosPtr,DIOposSwPrimePosBinding,DIOposSwPrimeNode,DIOposNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimeNegPtr,DIOposSwPrimeNegBinding,DIOposSwPrimeNode,DIOnegNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimePosSwPrimePtr,DIOposSwPrimePosSwPrimeBinding,DIOposSwPrimeNode,DIOposSwPrimeNode); if ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given)) { CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOtempPosPtr, DIOtempPosBinding, DIOtempNode, DIOposNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOtempPosPrimePtr, DIOtempPosPrimeBinding, DIOtempNode, DIOposPrimeNode); @@ -112,6 +136,9 @@ DIObindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposTempPtr, DIOposTempBinding, DIOposNode, DIOtempNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposPrimeTempPtr, DIOposPrimeTempBinding, DIOposPrimeNode, DIOtempNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOnegTempPtr, DIOnegTempBinding, DIOnegNode, DIOtempNode); + /* separate sidewall */ + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOtempPosSwPrimePtr, DIOtempPosSwPrimeBinding, DIOtempNode, DIOposSwPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode); } } } diff --git a/src/spicelib/devices/dio/dioconv.c b/src/spicelib/devices/dio/dioconv.c index ed1b0cea6..7e749576e 100644 --- a/src/spicelib/devices/dio/dioconv.c +++ b/src/spicelib/devices/dio/dioconv.c @@ -19,7 +19,7 @@ DIOconvTest(GENmodel *inModel, CKTcircuit *ckt) { DIOmodel *model = (DIOmodel*)inModel; DIOinstance *here; - double delvd,vd,cdhat,cd; + double delvd,vd,cdhat,cd,vdsw,cdhatsw=0.0,cdsw=0.0; double tol; double delTemp, deldelTemp; /* loop through all the diode models */ @@ -46,11 +46,23 @@ DIOconvTest(GENmodel *inModel, CKTcircuit *ckt) deldelTemp = delTemp - *(ckt->CKTstate0 + here->DIOdeltemp); cdhat= *(ckt->CKTstate0 + here->DIOcurrent) + - *(ckt->CKTstate0 + here->DIOconduct) * delvd + - *(ckt->CKTstate0 + here->DIOdIdio_dT) * deldelTemp; + *(ckt->CKTstate0 + here->DIOconduct) * delvd + + *(ckt->CKTstate0 + here->DIOdIdio_dT) * deldelTemp; cd= *(ckt->CKTstate0 + here->DIOcurrent); + if (model->DIOresistSWGiven) { + vdsw = *(ckt->CKTrhsOld+here->DIOposSwPrimeNode)- + *(ckt->CKTrhsOld + here->DIOnegNode); + + delvd=vdsw- *(ckt->CKTstate0 + here->DIOvoltageSW); + + cdhatsw= *(ckt->CKTstate0 + here->DIOcurrentSW) + + *(ckt->CKTstate0 + here->DIOconductSW) * delvd + + *(ckt->CKTstate0 + here->DIOdIdioSW_dT) * deldelTemp; + + cdsw= *(ckt->CKTstate0 + here->DIOcurrentSW); + } /* * check convergence */ @@ -61,6 +73,15 @@ DIOconvTest(GENmodel *inModel, CKTcircuit *ckt) ckt->CKTtroubleElt = (GENinstance *) here; return(OK); /* don't need to check any more device */ } + if (model->DIOresistSWGiven) { + tol=ckt->CKTreltol* + MAX(fabs(cdhatsw),fabs(cdsw))+ckt->CKTabstol; + if (fabs(cdhatsw-cdsw) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + return(OK); /* no reason to continue - we've failed... */ + } + } } } return(OK); diff --git a/src/spicelib/devices/dio/diodefs.h b/src/spicelib/devices/dio/diodefs.h index 80f49a59d..836475538 100644 --- a/src/spicelib/devices/dio/diodefs.h +++ b/src/spicelib/devices/dio/diodefs.h @@ -20,6 +20,9 @@ enum { DIORSNOIZ = 0, DIOIDNOIZ, DIOFLNOIZ, + DIORSSWNOIZ, + DIOIDSWNOIZ, + DIOFLSWNOIZ, DIOTOTNOIZ, /* finally, the number of noise sources */ DIONSRCS @@ -40,6 +43,7 @@ typedef struct sDIOinstance { const int DIOnegNode; /* number of negative node of diode */ const int DIOtempNode; /* number of the temperature node of the diode */ int DIOposPrimeNode; /* number of positive prime node of diode */ + int DIOposSwPrimeNode; /* number of positive prime node of diode sidewall */ double *DIOposPosPrimePtr; /* pointer to sparse matrix at * (positive,positive prime) */ @@ -55,6 +59,17 @@ typedef struct sDIOinstance { * (negative,negative) */ double *DIOposPrimePosPrimePtr; /* pointer to sparse matrix at * (positive prime,positive prime) */ + /* separate sidewall */ + double *DIOposPosSwPrimePtr; /* pointer to sparse matrix at + * (positive,positive prime sidewall) */ + double *DIOnegPosSwPrimePtr; /* pointer to sparse matrix at + * (negative,positive prime sidewall) */ + double *DIOposSwPrimePosPtr; /* pointer to sparse matrix at + * (positive prime sidewall,positive) */ + double *DIOposSwPrimeNegPtr; /* pointer to sparse matrix at + * (positive prime sidewall,negative) */ + double *DIOposSwPrimePosSwPrimePtr; /* pointer to sparse matrix at + * (positive prime sidewall,positive prime sidewall) */ /* self heating */ double *DIOtempPosPtr; @@ -64,8 +79,12 @@ typedef struct sDIOinstance { double *DIOposTempPtr; double *DIOposPrimeTempPtr; double *DIOnegTempPtr; + /* separate sidewall */ + double *DIOtempPosSwPrimePtr; + double *DIOposSwPrimeTempPtr; double DIOcap; /* stores the diode capacitance */ + double DIOcapSW; /* stores the diode Sw capacitance */ double *DIOsens; /* stores the perturbed values of geq and ceq in ac sensitivity analyis */ @@ -114,6 +133,8 @@ typedef struct sDIOinstance { double DIOtGradingCoeff; /* temperature adjusted grading coefficient (MJ) */ double DIOtConductance; /* temperature adjusted series conductance */ double DIOtConductance_dT; /* temperature adjusted series conductance temperature derivative */ + double DIOtConductanceSW; /* temperature adjusted sw series conductance */ + double DIOtConductanceSW_dT; /* temperature adjusted sw series conductance temperature derivative */ double DIOtDepCap; /* temperature adjusted transition point in */ /* the curve matching (Fc * Vj ) */ @@ -129,6 +150,7 @@ typedef struct sDIOinstance { double DIOtTunSatSWCur_dT; /* sidewall tunneling saturation current temperature derivative */ double DIOtVcrit; /* temperature adjusted V crit */ + double DIOtVcritSW; /* temperature adjusted V crit sidewall*/ double DIOtF1; /* temperature adjusted f1 */ double DIOtBrkdwnV; /* temperature adjusted breakdown voltage */ @@ -139,17 +161,21 @@ typedef struct sDIOinstance { double DIOforwardKneeCurrent; /* Forward Knee current */ double DIOreverseKneeCurrent; /* Reverse Knee current */ + double DIOforwardSWKneeCurrent; /* Forward Sw Knee current */ double DIOjunctionCap; /* geometry adjusted junction capacitance */ double DIOjunctionSWCap; /* geometry adjusted junction sidewall capacitance */ double DIOtRecSatCur; /* temperature adjusted recombination saturation current */ double DIOtRecSatCur_dT; /* temperature adjusted recombination saturation current */ double DIOdIth_dVrs; + double DIOdIth_dVrssw; double DIOdIth_dVdio; double DIOdIth_dT; double DIOgcTt; double DIOdIrs_dT; + double DIOdIrssw_dT; double DIOdIdio_dT; + double DIOdIdioSW_dT; double DIOcmetal; /* parasitic metal overlap capacitance */ double DIOcpoly; /* parasitic polysilicon overlap capacitance */ @@ -194,6 +220,12 @@ typedef struct sDIOinstance { BindElement *DIOposPosBinding ; BindElement *DIOnegNegBinding ; BindElement *DIOposPrimePosPrimeBinding ; + /* separate sidewall */ + BindElement *DIOposPosSwPrimeBinding ; + BindElement *DIOnegPosSwPrimeBinding ; + BindElement *DIOposSwPrimePosBinding ; + BindElement *DIOposSwPrimeNegBinding ; + BindElement *DIOposSwPrimePosSwPrimeBinding ; /* self heating */ BindElement *DIOtempPosBinding; BindElement *DIOtempPosPrimeBinding; @@ -216,18 +248,24 @@ typedef struct sDIOinstance { #define DIOvoltage DIOstate #define DIOcurrent DIOstate+1 #define DIOconduct DIOstate+2 -#define DIOcapCharge DIOstate+3 -#define DIOcapCurrent DIOstate+4 +#define DIOvoltageSW DIOstate+3 +#define DIOcurrentSW DIOstate+4 +#define DIOconductSW DIOstate+5 +#define DIOcapCharge DIOstate+6 +#define DIOcapCurrent DIOstate+7 +#define DIOcapChargeSW DIOstate+8 +#define DIOcapCurrentSW DIOstate+9 -#define DIOqth DIOstate+5 /* thermal capacitor charge */ -#define DIOcqth DIOstate+6 /* thermal capacitor current */ +#define DIOqth DIOstate+10 /* thermal capacitor charge */ +#define DIOcqth DIOstate+11 /* thermal capacitor current */ -#define DIOdeltemp DIOstate+7 /* thermal voltage over rth0 */ -#define DIOdIdio_dT DIOstate+8 +#define DIOdeltemp DIOstate+12 /* thermal voltage over rth0 */ +#define DIOdIdio_dT DIOstate+13 +#define DIOdIdioSW_dT DIOstate+14 -#define DIOnumStates 9 +#define DIOnumStates 15 -#define DIOsensxp DIOstate+9 /* charge sensitivities and their derivatives. +#define DIOsensxp DIOstate+12 /* charge sensitivities and their derivatives. * +10 for the derivatives - pointer to the * beginning of the array */ @@ -252,6 +290,7 @@ typedef struct sDIOmodel { /* model structure for a diode */ unsigned DIOresistGiven : 1; unsigned DIOresistTemp1Given : 1; unsigned DIOresistTemp2Given : 1; + unsigned DIOresistSWGiven : 1; unsigned DIOemissionCoeffGiven : 1; unsigned DIOswEmissionCoeffGiven : 1; unsigned DIObrkdEmissionCoeffGiven : 1; @@ -268,6 +307,7 @@ typedef struct sDIOmodel { /* model structure for a diode */ unsigned DIOgradingSWCoeffGiven : 1; unsigned DIOforwardKneeCurrentGiven : 1; unsigned DIOreverseKneeCurrentGiven : 1; + unsigned DIOforwardSWKneeCurrentGiven : 1; unsigned DIOtlevGiven : 1; unsigned DIOtlevcGiven : 1; @@ -324,6 +364,8 @@ typedef struct sDIOmodel { /* model structure for a diode */ double DIOresistTemp1; /* series resistance 1st order temp. coeff. */ double DIOresistTemp2; /* series resistance 2nd order temp. coeff. */ double DIOconductance; /* conductance corresponding to ohmic R */ + double DIOresistSW; /* ohmic series resistance sidewall */ + double DIOconductanceSW; /* conductance corresponding to ohmic R */ double DIOemissionCoeff; /* emission coefficient (N) */ double DIOswEmissionCoeff; /* Sidewall emission coefficient (NS) */ double DIObrkdEmissionCoeff; /* Breakdown emission coefficient (NBV) */ @@ -340,6 +382,7 @@ typedef struct sDIOmodel { /* model structure for a diode */ double DIOgradingSWCoeff; /* Sidewall grading coefficient (mjsw) */ double DIOforwardKneeCurrent; /* Forward Knee current (IKF) */ double DIOreverseKneeCurrent; /* Reverse Knee current (IKR) */ + double DIOforwardSWKneeCurrent; /* Forward Sw Knee current (IKP) */ int DIOtlev; /* Diode temperature equation selector */ int DIOtlevc; /* Diode temperature equation selector */ @@ -428,6 +471,7 @@ enum { DIO_MOD_LEVEL = 100, DIO_MOD_IS, DIO_MOD_RS, + DIO_MOD_RSW, DIO_MOD_N, DIO_MOD_TT, DIO_MOD_CJO, @@ -451,6 +495,7 @@ enum { DIO_MOD_MJSW, DIO_MOD_IKF, DIO_MOD_IKR, + DIO_MOD_IKP, DIO_MOD_FCS, DIO_MOD_TTT1, DIO_MOD_TTT2, diff --git a/src/spicelib/devices/dio/dioload.c b/src/spicelib/devices/dio/dioload.c index e8f1dd755..d7243d5b1 100644 --- a/src/spicelib/devices/dio/dioload.c +++ b/src/spicelib/devices/dio/dioload.c @@ -24,10 +24,10 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) DIOinstance *here; double arg; double argsw; - double capd; + double capd, capdsw=0.0; double cd, cdb, cdsw, cdb_dT, cdsw_dT; double cdeq; - double cdhat; + double cdhat, cdhatsw=0.0; double ceq; double csat; /* area-scaled saturation current */ double csatsw; /* perimeter-scaled saturation current */ @@ -37,34 +37,33 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) double czeroSW; double czof2SW; double sargSW; - double sqrt_ikr; - double sqrt_ikf; - double ikf_area_m; - double ikr_area_m; + double sqrt_ikx; - double delvd; /* change in diode voltage temporary */ + double delvd, delvdsw=0.0; /* change in diode voltage temporary */ double evd; double evrev; double gd, gdb, gdsw, gen_fac, gen_fac_vd; double t1, evd_rec, cdb_rec, gdb_rec, cdb_rec_dT; double geq; double gspr; /* area-scaled conductance */ + double gsprsw; /* perim-scaled conductance */ double sarg; #ifndef NOBYPASS double tol; /* temporary for tolerence calculations */ #endif - double vd; /* current diode voltage */ + double vd, vdsw=0.0; /* current diode voltage */ double vdtemp; double vt; /* K t / Q */ - double vte, vtesw, vtetun, vtebrk; - int Check_dio=0, Check_th; + double vte, vtesw, vtetun, vtebrk, vterec; + int Check_dio=0, Check_dio_sw=0, Check_th; int error; int SenCond=0; /* sensitivity condition */ double diffcharge, deplcharge, deplchargeSW, diffcap, deplcap, deplcapSW; double deldelTemp, delTemp, Temp; - double ceqqth=0.0, Ith=0.0, gcTt=0.0, vrs=0.0; + double ceqqth=0.0, Ith=0.0, gcTt=0.0, vrs=0.0, vrssw=0.0; double dIdio_dT, dIth_dVdio=0.0, dIrs_dT=0.0, dIth_dVrs=0.0, dIth_dT=0.0; + double dIdioSw_dT=0.0, dIth_dVdioSw=0.0, dIth_dVrssw=0.0, dIrssw_dT=0.0; double argsw_dT, csat_dT, csatsw_dT; /* loop through all the diode models */ @@ -101,8 +100,11 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) delTemp = 0.0; vt = CONSTKoverQ * here->DIOtemp; vte = model->DIOemissionCoeff * vt; + vtesw = model->DIOswEmissionCoeff * vt; vtebrk = model->DIObrkdEmissionCoeff * vt; + vterec = model->DIOrecEmissionCoeff*vt; gspr = here->DIOtConductance; + gsprsw = here->DIOtConductanceSW; /* * initialization */ @@ -116,9 +118,11 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) if((ckt->CKTsenInfo->SENmode == TRANSEN)&& (ckt->CKTmode & MODEINITTRAN)) { vd = *(ckt->CKTstate1 + here->DIOvoltage); + if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate1 + here->DIOvoltageSW); delTemp = *(ckt->CKTstate1 + here->DIOdeltemp); } else{ vd = *(ckt->CKTstate0 + here->DIOvoltage); + if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate0 + here->DIOvoltageSW); delTemp = *(ckt->CKTstate0 + here->DIOdeltemp); } @@ -128,24 +132,28 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) goto next1; } - Check_dio=1; + Check_dio=1; Check_dio_sw=1; if(ckt->CKTmode & MODEINITSMSIG) { vd= *(ckt->CKTstate0 + here->DIOvoltage); + if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate0 + here->DIOvoltageSW); delTemp = *(ckt->CKTstate0 + here->DIOdeltemp); } else if (ckt->CKTmode & MODEINITTRAN) { vd= *(ckt->CKTstate1 + here->DIOvoltage); + if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate1 + here->DIOvoltageSW); delTemp = *(ckt->CKTstate1 + here->DIOdeltemp); } else if ( (ckt->CKTmode & MODEINITJCT) && (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC) ) { vd=here->DIOinitCond; + if (model->DIOresistSWGiven) vdsw = here->DIOinitCond; } else if ( (ckt->CKTmode & MODEINITJCT) && here->DIOoff) { - vd=0; + vd=vdsw=0; delTemp = 0.0; } else if ( ckt->CKTmode & MODEINITJCT) { vd=here->DIOtVcrit; + vdsw=here->DIOtVcritSW; delTemp = 0.0; } else if ( ckt->CKTmode & MODEINITFIX && here->DIOoff) { - vd=0; + vd=vdsw=0; delTemp = 0.0; } else { #ifndef PREDICTOR @@ -164,10 +172,17 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) *(ckt->CKTstate1 + here->DIOdIdio_dT); *(ckt->CKTstate0+here->DIOqth) = *(ckt->CKTstate1+here->DIOqth); + if (model->DIOresistSWGiven) { + vdsw = DEVpred(ckt,here->DIOvoltageSW); + *(ckt->CKTstate0 + here->DIOdIdioSW_dT) = + *(ckt->CKTstate1 + here->DIOdIdioSW_dT); + } } else { #endif /* PREDICTOR */ vd = *(ckt->CKTrhsOld+here->DIOposPrimeNode)- *(ckt->CKTrhsOld + here->DIOnegNode); + if (model->DIOresistSWGiven) vdsw = *(ckt->CKTrhsOld+here->DIOposSwPrimeNode)- + *(ckt->CKTrhsOld + here->DIOnegNode); if (selfheat) delTemp = *(ckt->CKTrhsOld + here->DIOtempNode); else @@ -185,6 +200,11 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) cdhat= *(ckt->CKTstate0 + here->DIOcurrent) + *(ckt->CKTstate0 + here->DIOconduct) * delvd + *(ckt->CKTstate0 + here->DIOdIdio_dT) * deldelTemp; + if (model->DIOresistSWGiven) { + delvdsw=vdsw - *(ckt->CKTstate0 + here->DIOvoltageSW); + cdhatsw = *(ckt->CKTstate0 + here->DIOconductSW) * delvdsw + + *(ckt->CKTstate0 + here->DIOdIdioSW_dT) * deldelTemp; + } /* * bypass if solution has not changed */ @@ -192,7 +212,7 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) if ((!(ckt->CKTmode & MODEINITPRED)) && (ckt->CKTbypass)) { tol=ckt->CKTvoltTol + ckt->CKTreltol* MAX(fabs(vd),fabs(*(ckt->CKTstate0 +here->DIOvoltage))); - if (fabs(delvd) < tol){ + if (fabs(delvd) < tol) { tol=ckt->CKTreltol* MAX(fabs(cdhat), fabs(*(ckt->CKTstate0 + here->DIOcurrent)))+ ckt->CKTabstol; @@ -202,12 +222,25 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) (fabs(deldelTemp) < (ckt->CKTreltol * MAX(fabs(delTemp), fabs(*(ckt->CKTstate0+here->DIOdeltemp)))+ ckt->CKTvoltTol*1e4))) { - vd= *(ckt->CKTstate0 + here->DIOvoltage); - cd= *(ckt->CKTstate0 + here->DIOcurrent); - gd= *(ckt->CKTstate0 + here->DIOconduct); - delTemp = *(ckt->CKTstate0 + here->DIOdeltemp); - dIdio_dT= *(ckt->CKTstate0 + here->DIOdIdio_dT); - goto load; + if ((!model->DIOresistSWGiven) || (fabs(delvdsw) < ckt->CKTvoltTol + ckt->CKTreltol * + MAX(fabs(vdsw),fabs(*(ckt->CKTstate0+here->DIOvoltageSW))))) { + if ((!model->DIOresistSWGiven) || (fabs(cdhatsw- *(ckt->CKTstate0 + here->DIOcurrentSW)) + < ckt->CKTreltol* MAX(fabs(cdhatsw), + fabs(*(ckt->CKTstate0 + here->DIOcurrentSW)))+ckt->CKTabstol)) { + vd= *(ckt->CKTstate0 + here->DIOvoltage); + cd= *(ckt->CKTstate0 + here->DIOcurrent); + gd= *(ckt->CKTstate0 + here->DIOconduct); + delTemp = *(ckt->CKTstate0 + here->DIOdeltemp); + dIdio_dT= *(ckt->CKTstate0 + here->DIOdIdio_dT); + if (model->DIOresistSWGiven) { + vdsw= *(ckt->CKTstate0 + here->DIOvoltageSW); + cdsw= *(ckt->CKTstate0 + here->DIOcurrentSW); + gdsw= *(ckt->CKTstate0 + here->DIOconductSW); + dIdioSw_dT= *(ckt->CKTstate0 + here->DIOdIdioSW_dT); + } + goto load; + } + } } } } @@ -228,6 +261,20 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt) vd = DEVpnjlim(vd,*(ckt->CKTstate0 + here->DIOvoltage), vte,here->DIOtVcrit,&Check_dio); } + if (model->DIOresistSWGiven) { + if ( (model->DIObreakdownVoltageGiven) && + (vdsw < MIN(0,-here->DIOtBrkdwnV+10*vtebrk))) { + vdtemp = -(vdsw+here->DIOtBrkdwnV); + vdtemp = DEVpnjlim(vdtemp, + -(*(ckt->CKTstate0 + here->DIOvoltageSW) + + here->DIOtBrkdwnV),vtebrk, + here->DIOtVcritSW,&Check_dio_sw); + vdsw = -(vdtemp+here->DIOtBrkdwnV); + } else { + vdsw = DEVpnjlim(vdsw,*(ckt->CKTstate0 + here->DIOvoltageSW), + vtesw,here->DIOtVcritSW,&Check_dio_sw); + } + } if (selfheat) delTemp = DEVlimitlog(delTemp, *(ckt->CKTstate0 + here->DIOdeltemp), 100, &Check_th); @@ -253,47 +300,45 @@ next1: csatsw = here->DIOtSatSWCur; csatsw_dT = here->DIOtSatSWCur_dT; gspr = here->DIOtConductance; + gsprsw = here->DIOtConductanceSW; - if (model->DIOsatSWCurGiven) { /* sidewall current */ + if (model->DIOsatSWCurGiven) { /* sidewall current */ + double vds; + if (model->DIOresistSWGiven) + vds = vdsw; /* sidewall voltage used */ + else + vds = vd; /* common voltage used */ - if (model->DIOswEmissionCoeffGiven) { /* current with own characteristic */ + if (model->DIOswEmissionCoeffGiven) { /* with own characteristic */ - vtesw = model->DIOswEmissionCoeff * vt; + if (vds >= -3*vtesw) { /* forward */ - if (vd >= -3*vtesw) { /* forward */ - - evd = exp(vd/vtesw); + evd = exp(vds/vtesw); cdsw = csatsw*(evd-1); gdsw = csatsw*evd/vtesw; - cdsw_dT = csatsw_dT * (evd - 1) - csatsw * vd * evd / (vtesw * Temp); + cdsw_dT = csatsw_dT * (evd - 1) - csatsw * vds * evd / (vtesw * Temp); - } else if((!(model->DIObreakdownVoltageGiven)) || - vd >= -here->DIOtBrkdwnV) { /* reverse */ + } else if ((!(model->DIObreakdownVoltageGiven)) || + vds >= -here->DIOtBrkdwnV) { /* reverse */ - argsw = 3*vtesw/(vd*CONSTe); + argsw = 3*vtesw/(vds*CONSTe); argsw = argsw * argsw * argsw; argsw_dT = 3 * argsw / Temp; cdsw = -csatsw*(1+argsw); - gdsw = csatsw*3*argsw/vd; + gdsw = csatsw*3*argsw/vds; cdsw_dT = -csatsw_dT - (csatsw_dT*argsw + csatsw*argsw_dT); - } else { /* breakdown */ + } else if (!model->DIOresistSWGiven){ /* breakdown, but not for separate sidewall diode */ double evrev_dT; - evrev = exp(-(here->DIOtBrkdwnV+vd)/vtebrk); - evrev_dT = (here->DIOtBrkdwnV+vd)*evrev/(vtebrk*Temp); + evrev = exp(-(here->DIOtBrkdwnV+vds)/vtebrk); + evrev_dT = (here->DIOtBrkdwnV+vds)*evrev/(vtebrk*Temp); cdsw = -csatsw*evrev; gdsw = csatsw*evrev/vtebrk; cdsw_dT = -(csatsw_dT*evrev + csatsw*evrev_dT); } - } else { /* merge saturation currents and use same characteristic as bottom diode */ - - csat = csat + csatsw; - csat_dT = csat_dT + csatsw_dT; - cdsw_dT = 0.0; - } } @@ -302,15 +347,19 @@ next1: * temperature dependent diode saturation current and derivative */ - if (vd >= -3*vte) { /* bottom current forward */ - + if (vd >= -3*vte) { /* bottom and sidewall current forward with common voltage */ + /* and with common characteristic */ evd = exp(vd/vte); cdb = csat*(evd-1); gdb = csat*evd/vte; cdb_dT = csat_dT * (evd - 1) - csat * vd * evd / (vte * Temp); + if ((model->DIOsatSWCurGiven)&&(!model->DIOswEmissionCoeffGiven)) { + cdsw = csatsw*(evd-1); + gdsw = csatsw*evd/vte; + cdsw_dT = csatsw_dT * (evd - 1) - csatsw * vd * evd / (vte * Temp); + } if (model->DIOrecSatCurGiven) { /* recombination current */ - double vterec = model->DIOrecEmissionCoeff*vt; - evd_rec = exp(vd/(vterec)); + evd_rec = exp(vd/vterec); cdb_rec = here->DIOtRecSatCur*(evd_rec-1); gdb_rec = here->DIOtRecSatCur*evd_rec/vterec; cdb_rec_dT = here->DIOtRecSatCur_dT * (evd_rec - 1) @@ -326,7 +375,7 @@ next1: cdb_dT = cdb_dT + cdb_rec_dT*gen_fac; } - } else if((!(model->DIObreakdownVoltageGiven)) || + } else if ((!(model->DIObreakdownVoltageGiven)) || vd >= -here->DIOtBrkdwnV) { /* reverse */ double darg_dT; @@ -334,18 +383,49 @@ next1: arg = 3*vte/(vd*CONSTe); arg = arg * arg * arg; darg_dT = 3 * arg / Temp; - cdb = -csat*(1+arg); + if (model->DIOrecSatCurGiven) { + evd_rec = exp((-3*vte)/vterec); + cdb_rec = here->DIOtRecSatCur*(evd_rec-1); + t1 = pow((1-(-3*vte)/here->DIOtJctPot), 2) + 0.005; + gen_fac = pow(t1, here->DIOtGradingCoeff/2); + cdb = -csat*(1+arg) + gen_fac*cdb_rec; + } else { + cdb = -csat*(1+arg); + } gdb = csat*3*arg/vd; cdb_dT = -csat_dT - (csat_dT*arg + csat*darg_dT); + if ((model->DIOsatSWCurGiven)&&(!model->DIOswEmissionCoeffGiven)) { + cdsw = -csatsw*(1+arg); + gdsw = csatsw*3*arg/vd; + cdsw_dT = -csatsw_dT - (csatsw_dT*arg + csatsw*darg_dT); + } } else { /* breakdown */ + double evrev_dT; evrev = exp(-(here->DIOtBrkdwnV+vd)/vtebrk); evrev_dT = (here->DIOtBrkdwnV+vd)*evrev/(vtebrk*Temp); - cdb = -csat*evrev; + if (model->DIOrecSatCurGiven) { + evd_rec = exp((-3*vte)/vterec); + cdb_rec = here->DIOtRecSatCur*(evd_rec-1); + t1 = pow((1-(-3*vte)/here->DIOtJctPot), 2) + 0.005; + gen_fac = pow(t1, here->DIOtGradingCoeff/2); + cdb = -csat*evrev + gen_fac*cdb_rec; + } else { + cdb = -csat*evrev; + } gdb = csat*evrev/vtebrk; cdb_dT = -(csat_dT*evrev + csat*evrev_dT); + if ((model->DIOsatSWCurGiven) + &&(!model->DIOswEmissionCoeffGiven) + &&(!model->DIOresistSWGiven)) { /* no breakdown for separate sidewall diode */ + evrev = exp(-(here->DIOtBrkdwnV+vdsw)/vtebrk); + evrev_dT = (here->DIOtBrkdwnV+vdsw)*evrev/(vtebrk*Temp); + cdsw = -csatsw*evrev; + gdsw = csatsw*evrev/vtebrk; + cdsw_dT = -(csatsw_dT*evrev + csatsw*evrev_dT); + } } @@ -373,36 +453,46 @@ next1: } - cd = cdb + cdsw; - gd = gdb + gdsw; - dIdio_dT = cdb_dT + cdsw_dT; - if (vd >= -3*vte) { /* limit forward */ - if( (model->DIOforwardKneeCurrentGiven) && (cd > 1.0e-18) ) { - ikf_area_m = here->DIOforwardKneeCurrent; - sqrt_ikf = sqrt(cd/ikf_area_m); - gd = ((1+sqrt_ikf)*gd - cd*gd/(2*sqrt_ikf*ikf_area_m))/(1+2*sqrt_ikf + cd/ikf_area_m) + ckt->CKTgmin; - cd = cd/(1+sqrt_ikf) + ckt->CKTgmin*vd; - } else { - gd = gd + ckt->CKTgmin; - cd = cd + ckt->CKTgmin*vd; + if ( (model->DIOforwardKneeCurrentGiven) && (cdb > 1.0e-18) ) { + double ikf_area_m = here->DIOforwardKneeCurrent; + sqrt_ikx = sqrt(cdb/ikf_area_m); + gdb = ((1+sqrt_ikx)*gdb - cdb*gdb/(2*sqrt_ikx*ikf_area_m))/(1+2*sqrt_ikx + cdb/ikf_area_m); + cdb = cdb/(1+sqrt_ikx); } } else { /* limit reverse */ - if( (model->DIOreverseKneeCurrentGiven) && (cd < -1.0e-18) ) { - ikr_area_m = here->DIOreverseKneeCurrent; - sqrt_ikr = sqrt(cd/(-ikr_area_m)); - gd = ((1+sqrt_ikr)*gd + cd*gd/(2*sqrt_ikr*ikr_area_m))/(1+2*sqrt_ikr - cd/ikr_area_m) + ckt->CKTgmin; - cd = cd/(1+sqrt_ikr) + ckt->CKTgmin*vd; - } else { - gd = gd + ckt->CKTgmin; - cd = cd + ckt->CKTgmin*vd; + if ( (model->DIOreverseKneeCurrentGiven) && (cdb < -1.0e-18) ) { + double ikr_area_m = here->DIOreverseKneeCurrent; + sqrt_ikx = sqrt(cdb/(-ikr_area_m)); + gdb = ((1+sqrt_ikx)*gdb + cdb*gdb/(2*sqrt_ikx*ikr_area_m))/(1+2*sqrt_ikx - cdb/ikr_area_m); + cdb = cdb/(1+sqrt_ikx); } } + if ( (model->DIOforwardSWKneeCurrentGiven) && (cdsw > 1.0e-18) ) { + double ikp_peri_m = here->DIOforwardSWKneeCurrent; + sqrt_ikx = sqrt(cdsw/ikp_peri_m); + gdsw = ((1+sqrt_ikx)*gdsw - cdsw*gdsw/(2*sqrt_ikx*ikp_peri_m))/(1+2*sqrt_ikx + cdsw/ikp_peri_m); + cdsw = cdsw/(1+sqrt_ikx); + } + + if (!model->DIOresistSWGiven) { + cd = cdb + cdsw + ckt->CKTgmin*vd; + gd = gdb + gdsw + ckt->CKTgmin; + dIdio_dT = cdb_dT + cdsw_dT; + } else { + cd = cdb + ckt->CKTgmin*vd; + gd = gdb + ckt->CKTgmin; + cdsw = cdsw + ckt->CKTgmin*vdsw; + gdsw = gdsw + ckt->CKTgmin; + dIdio_dT = cdb_dT; + dIdioSw_dT = cdsw_dT; + } + if ((ckt->CKTmode & (MODEDCTRANCURVE | MODETRAN | MODEAC | MODEINITSMSIG)) || ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) { /* @@ -421,28 +511,40 @@ next1: deplcap = czof2*(here->DIOtF3+here->DIOtGradingCoeff*vd/here->DIOtJctPot); } czeroSW=here->DIOtJctSWCap; - if (vd < here->DIOtDepSWCap){ - argSW=1-vd/here->DIOtJctSWPot; + double vdx; + if (model->DIOresistSWGiven) + vdx = vdsw; + else + vdx = vd; + if (vdx < here->DIOtDepSWCap){ + argSW=1-vdx/here->DIOtJctSWPot; sargSW=exp(-model->DIOgradingSWCoeff*log(argSW)); deplchargeSW = here->DIOtJctSWPot*czeroSW*(1-argSW*sargSW)/(1-model->DIOgradingSWCoeff); deplcapSW = czeroSW*sargSW; } else { czof2SW=czeroSW/here->DIOtF2SW; - deplchargeSW = czeroSW*here->DIOtF1+czof2SW*(here->DIOtF3SW*(vd-here->DIOtDepSWCap)+ - (model->DIOgradingSWCoeff/(here->DIOtJctSWPot+here->DIOtJctSWPot))*(vd*vd-here->DIOtDepSWCap*here->DIOtDepSWCap)); - deplcapSW = czof2SW*(here->DIOtF3SW+model->DIOgradingSWCoeff*vd/here->DIOtJctSWPot); + deplchargeSW = czeroSW*here->DIOtF1+czof2SW*(here->DIOtF3SW*(vdx-here->DIOtDepSWCap)+ + (model->DIOgradingSWCoeff/(here->DIOtJctSWPot+here->DIOtJctSWPot))*(vdx*vdx-here->DIOtDepSWCap*here->DIOtDepSWCap)); + deplcapSW = czof2SW*(here->DIOtF3SW+model->DIOgradingSWCoeff*vdx/here->DIOtJctSWPot); } diffcharge = here->DIOtTransitTime*cd; - *(ckt->CKTstate0 + here->DIOcapCharge) = - diffcharge + deplcharge + deplchargeSW + (here->DIOcmetal + here->DIOcpoly)*vd; - diffcap = here->DIOtTransitTime*gd; - - capd = diffcap + deplcap + deplcapSW + here->DIOcmetal + here->DIOcpoly; - - here->DIOcap = capd; - + if (!model->DIOresistSWGiven) { + *(ckt->CKTstate0 + here->DIOcapCharge) = + diffcharge + deplcharge + deplchargeSW + (here->DIOcmetal + here->DIOcpoly)*vd; + capd = diffcap + deplcap + deplcapSW + here->DIOcmetal + here->DIOcpoly; + here->DIOcap = capd; + } else { + *(ckt->CKTstate0 + here->DIOcapCharge) = + diffcharge + deplcharge + (here->DIOcmetal + here->DIOcpoly)*vd; + capd = diffcap + deplcap + here->DIOcmetal + here->DIOcpoly; + here->DIOcap = capd; + *(ckt->CKTstate0 + here->DIOcapChargeSW) = + deplcapSW; + capdsw = deplcapSW; + here->DIOcapSW = capdsw; + } /* * store small-signal parameters */ @@ -450,11 +552,18 @@ next1: (!(ckt->CKTmode & MODEUIC)) ) { if (ckt->CKTmode & MODEINITSMSIG){ *(ckt->CKTstate0 + here->DIOcapCurrent) = capd; - + if (model->DIOresistSWGiven) { + *(ckt->CKTstate0 + here->DIOcapCurrentSW) = capdsw; + } if(SenCond){ *(ckt->CKTstate0 + here->DIOcurrent) = cd; *(ckt->CKTstate0 + here->DIOconduct) = gd; *(ckt->CKTstate0 + here->DIOdIdio_dT) = dIdio_dT; + if (model->DIOresistSWGiven) { + *(ckt->CKTstate0 + here->DIOcurrentSW) = cdsw; + *(ckt->CKTstate0 + here->DIOconductSW) = gdsw; + *(ckt->CKTstate0 + here->DIOdIdioSW_dT) = dIdioSw_dT; + } #ifdef SENSDEBUG printf("storing small signal parameters\n"); printf("cd = %.7e,vd = %.7e\n",cd,vd); @@ -469,6 +578,8 @@ next1: */ if(SenCond && (ckt->CKTsenInfo->SENmode == TRANSEN)){ *(ckt->CKTstate0 + here->DIOcurrent) = cd; + if (model->DIOresistSWGiven) + *(ckt->CKTstate0 + here->DIOcurrentSW) = cdsw; #ifdef SENSDEBUG printf("storing parameters for transient sensitivity\n" ); @@ -481,21 +592,29 @@ next1: if (ckt->CKTmode & MODEINITTRAN) { *(ckt->CKTstate1 + here->DIOcapCharge) = *(ckt->CKTstate0 + here->DIOcapCharge); + if (model->DIOresistSWGiven) + *(ckt->CKTstate1 + here->DIOcapChargeSW) = + *(ckt->CKTstate0 + here->DIOcapChargeSW); } error = NIintegrate(ckt,&geq,&ceq,capd,here->DIOcapCharge); if(error) return(error); gd=gd+geq; cd=cd+*(ckt->CKTstate0 + here->DIOcapCurrent); + if (model->DIOresistSWGiven) { + error = NIintegrate(ckt,&geq,&ceq,capdsw,here->DIOcapChargeSW); + if(error) return(error); + gdsw=gdsw+geq; + cdsw=cdsw+*(ckt->CKTstate0 + here->DIOcapCurrentSW); + } if (ckt->CKTmode & MODEINITTRAN) { *(ckt->CKTstate1 + here->DIOcapCurrent) = *(ckt->CKTstate0 + here->DIOcapCurrent); + if (model->DIOresistSWGiven) + *(ckt->CKTstate1 + here->DIOcapCurrentSW) = + *(ckt->CKTstate0 + here->DIOcapCurrentSW); } if (selfheat) { - if (ckt->CKTmode & MODEINITTRAN) { - *(ckt->CKTstate1 + here->DIOqth) = - *(ckt->CKTstate0 + here->DIOqth); - } error = NIintegrate(ckt, &gcTt, &ceqqth, model->DIOcth0, here->DIOqth); if (error) return(error); if (ckt->CKTmode & MODEINITTRAN) { @@ -512,9 +631,16 @@ next1: * check convergence */ if ( (!(ckt->CKTmode & MODEINITFIX)) || (!(here->DIOoff)) ) { - if ((Check_th == 1) || (Check_dio == 1)) { - ckt->CKTnoncon++; - ckt->CKTtroubleElt = (GENinstance *) here; + if (!model->DIOresistSWGiven) { + if ((Check_th == 1) || (Check_dio == 1)) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } + } else { + if ((Check_th == 1) || (Check_dio == 1) || (Check_dio_sw == 1)) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } } } next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd; @@ -522,7 +648,12 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd; *(ckt->CKTstate0 + here->DIOconduct) = gd; *(ckt->CKTstate0 + here->DIOdeltemp) = delTemp; *(ckt->CKTstate0 + here->DIOdIdio_dT) = dIdio_dT; - + if (model->DIOresistSWGiven) { + *(ckt->CKTstate0 + here->DIOvoltageSW) = vdsw; + *(ckt->CKTstate0 + here->DIOcurrentSW) = cdsw; + *(ckt->CKTstate0 + here->DIOconductSW) = gdsw; + *(ckt->CKTstate0 + here->DIOdIdioSW_dT) = dIdioSw_dT; + } if(SenCond) continue; #ifndef NOBYPASS @@ -531,20 +662,37 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd; if (selfheat) { double dIrs_dVrs, dIrs_dgspr, dIth_dIrs; vrs = *(ckt->CKTrhsOld + here->DIOposNode) - *(ckt->CKTrhsOld + here->DIOposPrimeNode); - Ith = vd*cd + vrs*vrs*gspr; /* Diode dissipated power */ dIrs_dVrs = gspr; dIrs_dgspr = vrs; dIrs_dT = dIrs_dgspr * here->DIOtConductance_dT; + Ith = vd*cd + vrs*vrs*gspr; /* Diode dissipated power */ dIth_dVrs = vrs*gspr; dIth_dIrs = vrs; dIth_dVrs = dIth_dVrs + dIth_dIrs*dIrs_dVrs; dIth_dT = dIth_dIrs*dIrs_dT + dIdio_dT*vd; dIth_dVdio = cd + vd*gd; here->DIOdIth_dVrs = dIth_dVrs; - here->DIOdIth_dVdio = dIth_dVdio; - here->DIOdIth_dT = dIth_dT; here->DIOgcTt = gcTt; here->DIOdIrs_dT = dIrs_dT; + here->DIOdIth_dVdio = dIth_dVdio; + here->DIOdIth_dT = dIth_dT; + if (model->DIOresistSWGiven) { + double dIrssw_dVrssw, dIrssw_dgsprsw, dIth_dIrssw; + vrssw = *(ckt->CKTrhsOld + here->DIOposNode) - *(ckt->CKTrhsOld + here->DIOposSwPrimeNode); + dIrssw_dVrssw = gsprsw; + dIrssw_dgsprsw = vrssw; + dIrssw_dT = dIrssw_dgsprsw * here->DIOtConductanceSW_dT; + Ith = Ith + vdsw*cdsw + vrssw*vrssw*gsprsw; /* Diode dissipated power */ + dIth_dVrssw = vrssw*gsprsw; + dIth_dIrssw = vrssw; + dIth_dVrssw = dIth_dVrssw + dIth_dIrssw*dIrssw_dVrssw; + dIth_dT = dIth_dT + dIth_dIrssw*dIrssw_dT + dIdioSw_dT*vdsw; + dIth_dVdioSw = cdsw + vdsw*gdsw; + here->DIOdIth_dVrssw = dIth_dVrssw; + here->DIOdIth_dVdio = dIth_dVdioSw; + here->DIOdIth_dT = dIth_dT; + here->DIOdIrssw_dT = dIrssw_dT; + } } /* * load current vector @@ -558,6 +706,17 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd; *(ckt->CKTrhs + here->DIOnegNode) += -dIdio_dT*delTemp; *(ckt->CKTrhs + here->DIOtempNode) += Ith - dIth_dVdio*vd - dIth_dVrs*vrs - dIth_dT*delTemp - ceqqth; } + if (model->DIOresistSWGiven) { + cdeq=cdsw-gdsw*vdsw; + *(ckt->CKTrhs + here->DIOnegNode) += cdeq; + *(ckt->CKTrhs + here->DIOposSwPrimeNode) -= cdeq; + if (selfheat) { + *(ckt->CKTrhs + here->DIOposNode) += dIrssw_dT*delTemp; + *(ckt->CKTrhs + here->DIOposSwPrimeNode) += dIdioSw_dT*delTemp - dIrssw_dT*delTemp; + *(ckt->CKTrhs + here->DIOnegNode) += -dIdioSw_dT*delTemp; + *(ckt->CKTrhs + here->DIOtempNode) += -dIth_dVdioSw*vdsw - dIth_dVrssw*vrssw; + } + } /* * load matrix */ @@ -577,6 +736,24 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd; (*(here->DIOposPrimeTempPtr) += dIdio_dT - dIrs_dT); (*(here->DIOnegTempPtr) += -dIdio_dT); } + if (model->DIOresistSWGiven) { + *(here->DIOposPosPtr) += gsprsw; + *(here->DIOnegNegPtr) += gdsw; + *(here->DIOposSwPrimePosSwPrimePtr) += (gdsw + gsprsw); + *(here->DIOposPosSwPrimePtr) -= gsprsw; + *(here->DIOnegPosSwPrimePtr) -= gdsw; + *(here->DIOposSwPrimePosPtr) -= gsprsw; + *(here->DIOposSwPrimeNegPtr) -= gdsw; + + if (selfheat) { + (*(here->DIOtempPosPtr) += -dIth_dVrssw); + (*(here->DIOtempPosSwPrimePtr) += -dIth_dVdioSw + dIth_dVrssw); + (*(here->DIOtempNegPtr) += dIth_dVdioSw); + (*(here->DIOposTempPtr) += dIrssw_dT); + (*(here->DIOposSwPrimeTempPtr) += dIdioSw_dT - dIrssw_dT); + (*(here->DIOnegTempPtr) += -dIdioSw_dT); + } + } } } return(OK); diff --git a/src/spicelib/devices/dio/diomask.c b/src/spicelib/devices/dio/diomask.c index dcbdfffc0..1f4e11ce5 100644 --- a/src/spicelib/devices/dio/diomask.c +++ b/src/spicelib/devices/dio/diomask.c @@ -42,6 +42,9 @@ DIOmAsk (CKTcircuit *ckt, GENmodel *inModel, int which, IFvalue *value) case DIO_MOD_RS: value->rValue = model->DIOresist; return(OK); + case DIO_MOD_RSW: + value->rValue = model->DIOresistSW; + return(OK); case DIO_MOD_TRS: value->rValue = model->DIOresistTemp1; return(OK); @@ -93,6 +96,9 @@ DIOmAsk (CKTcircuit *ckt, GENmodel *inModel, int which, IFvalue *value) case DIO_MOD_IKR: value->rValue = model->DIOreverseKneeCurrent; return(OK); + case DIO_MOD_IKP: + value->rValue = model->DIOforwardSWKneeCurrent; + return(OK); case DIO_MOD_NBV: value->rValue = model->DIObrkdEmissionCoeff; return(OK); diff --git a/src/spicelib/devices/dio/diompar.c b/src/spicelib/devices/dio/diompar.c index e68052eb0..498421160 100644 --- a/src/spicelib/devices/dio/diompar.c +++ b/src/spicelib/devices/dio/diompar.c @@ -40,6 +40,10 @@ DIOmParam(int param, IFvalue *value, GENmodel *inModel) model->DIOresist = value->rValue; model->DIOresistGiven = TRUE; break; + case DIO_MOD_RSW: + model->DIOresistSW = value->rValue; + model->DIOresistSWGiven = TRUE; + break; case DIO_MOD_TRS: model->DIOresistTemp1 = value->rValue; model->DIOresistTemp1Given = TRUE; @@ -108,6 +112,10 @@ DIOmParam(int param, IFvalue *value, GENmodel *inModel) model->DIOreverseKneeCurrent = value->rValue; model->DIOreverseKneeCurrentGiven = TRUE; break; + case DIO_MOD_IKP: + model->DIOforwardSWKneeCurrent = value->rValue; + model->DIOforwardSWKneeCurrentGiven = TRUE; + break; case DIO_MOD_NBV: model->DIObrkdEmissionCoeff = value->rValue; model->DIObrkdEmissionCoeffGiven = TRUE; diff --git a/src/spicelib/devices/dio/dionoise.c b/src/spicelib/devices/dio/dionoise.c index fc30d4132..de2ba3793 100644 --- a/src/spicelib/devices/dio/dionoise.c +++ b/src/spicelib/devices/dio/dionoise.c @@ -41,10 +41,13 @@ DIOnoise(int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, static char *DIOnNames[DIONSRCS] = { /* Note that we have to keep the order - consistent with thestrchr definitions in DIOdefs.h */ + consistent with the strchr definitions in DIOdefs.h */ "_rs", /* noise due to rs */ "_id", /* noise due to id */ "_1overf", /* flicker (1/f) noise */ + "_rsw", /* noise due to rsw */ + "_idsw", /* noise due to id sw */ + "_1overfsw", /* flicker (1/f) noise sw */ "" /* total diode noise */ }; @@ -108,10 +111,36 @@ DIOnoise(int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, noizDens[DIOTOTNOIZ] = noizDens[DIORSNOIZ] + noizDens[DIOIDNOIZ] + noizDens[DIOFLNOIZ]; + + if (model->DIOresistSWGiven) { + /* sidewall diode */ + NevalSrcInstanceTemp(&noizDens[DIORSSWNOIZ],&lnNdens[DIORSSWNOIZ], + ckt, THERMNOISE, inst->DIOposSwPrimeNode, inst->DIOposNode, + inst->DIOtConductanceSW, dtemp); + + NevalSrc(&noizDens[DIOIDSWNOIZ],&lnNdens[DIOIDSWNOIZ], + ckt, SHOTNOISE, inst->DIOposSwPrimeNode, inst->DIOnegNode, + *(ckt->CKTstate0 + inst->DIOcurrentSW)); + + NevalSrc(&noizDens[DIOFLSWNOIZ], NULL, ckt, + N_GAIN, inst->DIOposSwPrimeNode, inst->DIOnegNode, + (double) 0.0); + noizDens[DIOFLSWNOIZ] *= model->DIOfNcoef * + exp(model->DIOfNexp * + log(MAX(fabs(*(ckt->CKTstate0 + inst->DIOcurrentSW) / inst->DIOm), N_MINLOG))) / + data->freq * inst->DIOm; + lnNdens[DIOFLSWNOIZ] = + log(MAX(noizDens[DIOFLSWNOIZ], N_MINLOG)); + + noizDens[DIOTOTNOIZ] += noizDens[DIORSSWNOIZ] + + noizDens[DIOIDSWNOIZ] + + noizDens[DIOFLSWNOIZ]; + } + lnNdens[DIOTOTNOIZ] = log(MAX(noizDens[DIOTOTNOIZ], N_MINLOG)); - *OnDens += noizDens[DIOTOTNOIZ]; + *OnDens += noizDens[DIOTOTNOIZ]; if (data->delFreq == 0.0) { diff --git a/src/spicelib/devices/dio/diopzld.c b/src/spicelib/devices/dio/diopzld.c index 8ec036031..44e13b84b 100644 --- a/src/spicelib/devices/dio/diopzld.c +++ b/src/spicelib/devices/dio/diopzld.c @@ -18,7 +18,7 @@ int DIOpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s) { DIOmodel *model = (DIOmodel*)inModel; - double gspr; + double gspr, gsprsw; double geq; double xceq; DIOinstance *here; @@ -43,6 +43,22 @@ DIOpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s) *(here->DIOposPrimePosPtr ) -= gspr; *(here->DIOposPrimeNegPtr ) -= geq + xceq * s->real; *(here->DIOposPrimeNegPtr +1 ) -= xceq * s->imag; + if (model->DIOresistSWGiven) { + gsprsw=here->DIOtConductanceSW; + geq= *(ckt->CKTstate0 + here->DIOconductSW); + xceq= *(ckt->CKTstate0 + here->DIOcapCurrentSW) * ckt->CKTomega; + *(here->DIOposPosPtr) += gsprsw; + *(here->DIOnegNegPtr) += geq + xceq * s->real; + *(here->DIOnegNegPtr + 1) += xceq * s->imag; + *(here->DIOposSwPrimePosSwPrimePtr) += geq + gsprsw + xceq * s->real; + *(here->DIOposSwPrimePosSwPrimePtr + 1) += xceq * s->imag; + *(here->DIOposPosSwPrimePtr) -= gsprsw; + *(here->DIOnegPosSwPrimePtr) -= geq; + *(here->DIOnegPosSwPrimePtr + 1) -= xceq; + *(here->DIOposSwPrimePosPtr) -= gsprsw; + *(here->DIOposSwPrimeNegPtr) -= geq + xceq * s->real; + *(here->DIOposSwPrimeNegPtr + 1) -= xceq * s->imag; + } } } return(OK); diff --git a/src/spicelib/devices/dio/diosetup.c b/src/spicelib/devices/dio/diosetup.c index 98ced6e01..df9555be8 100644 --- a/src/spicelib/devices/dio/diosetup.c +++ b/src/spicelib/devices/dio/diosetup.c @@ -35,6 +35,10 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) if(!model->DIOlevelGiven) { model->DIOlevel = 1; + } else if (model->DIOlevel == 2) { + SPfrontEnd->IFerrorf(ERR_FATAL, + "%s: Diode model level 2 is not supported.", model->DIOmodName); + return(E_BADPARM); } if(!model->DIOemissionCoeffGiven) { model->DIOemissionCoeff = 1; @@ -117,6 +121,13 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) model->DIOmodName); } } + if(model->DIOforwardSWKneeCurrentGiven) { + if (model->DIOforwardSWKneeCurrent < ckt->CKTepsmin) { + model->DIOforwardSWKneeCurrentGiven = FALSE; + fprintf(stderr, "Warning: %s: IKP too small - model effect disabled!\n", + model->DIOmodName); + } + } if(!model->DIObrkdEmissionCoeffGiven) { model->DIObrkdEmissionCoeff = model->DIOemissionCoeff; } @@ -238,6 +249,24 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) } else { model->DIOconductance = 1/model->DIOresist; } + if((!model->DIOresistSWGiven) || (model->DIOresistSW==0)) { + if (newcompat.ps || newcompat.lt) { + double rsdiode = 0.; + /* to improve convergence (sometimes) */ + if (cp_getvar("diode_rser", CP_REAL, &rsdiode, 0) && rsdiode > 0) { + model->DIOconductanceSW = 1./rsdiode; + model->DIOresistSW = rsdiode; + if (ft_ngdebug) + fprintf(stderr, "Diode sidewall series resistance in model %s set to %e Ohm\n", model->gen.GENmodName, rsdiode); + } + else + model->DIOconductanceSW = 0.0; + } + else + model->DIOconductanceSW = 0.0; + } else { + model->DIOconductanceSW = 1/model->DIOresistSW; + } if (!model->DIOrth0Given) { model->DIOrth0 = 0; @@ -329,6 +358,7 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) } here->DIOforwardKneeCurrent = model->DIOforwardKneeCurrent * here->DIOarea * here->DIOm; here->DIOreverseKneeCurrent = model->DIOreverseKneeCurrent * here->DIOarea * here->DIOm; + here->DIOforwardSWKneeCurrent = model->DIOforwardSWKneeCurrent * here->DIOpj * here->DIOm; here->DIOjunctionCap = model->DIOjunctionCap * here->DIOarea * here->DIOm; here->DIOjunctionSWCap = model->DIOjunctionSWCap * here->DIOpj * here->DIOm; @@ -344,19 +374,41 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) } else if(here->DIOposPrimeNode == 0) { - CKTnode *tmpNode; - IFuid tmpName; + CKTnode *tmpNode; + IFuid tmpName; error = CKTmkVolt(ckt,&tmp,here->DIOname,"internal"); if(error) return(error); here->DIOposPrimeNode = tmp->number; if (ckt->CKTcopyNodesets) { - if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) { - if (tmpNode->nsGiven) { - tmp->nodeset=tmpNode->nodeset; - tmp->nsGiven=tmpNode->nsGiven; - } - } + if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) { + if (tmpNode->nsGiven) { + tmp->nodeset=tmpNode->nodeset; + tmp->nsGiven=tmpNode->nsGiven; + } + } + } + } + + if(!model->DIOresistSWGiven) { + + here->DIOposSwPrimeNode = here->DIOposPrimeNode; + + } else if(here->DIOposSwPrimeNode == 0) { + + CKTnode *tmpNode; + IFuid tmpName; + + error = CKTmkVolt(ckt,&tmp,here->DIOname,"internal_sw"); + if(error) return(error); + here->DIOposSwPrimeNode = tmp->number; + if (ckt->CKTcopyNodesets) { + if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) { + if (tmpNode->nsGiven) { + tmp->nodeset=tmpNode->nodeset; + tmp->nsGiven=tmpNode->nsGiven; + } + } } } @@ -375,6 +427,14 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ TSTALLOC(DIOposPosPtr,DIOposNode,DIOposNode); TSTALLOC(DIOnegNegPtr,DIOnegNode,DIOnegNode); TSTALLOC(DIOposPrimePosPrimePtr,DIOposPrimeNode,DIOposPrimeNode); + if(model->DIOresistSWGiven) { + /* separate sidewall */ + TSTALLOC(DIOposPosSwPrimePtr,DIOposNode,DIOposSwPrimeNode); + TSTALLOC(DIOnegPosSwPrimePtr,DIOnegNode,DIOposSwPrimeNode); + TSTALLOC(DIOposSwPrimePosPtr,DIOposSwPrimeNode,DIOposNode); + TSTALLOC(DIOposSwPrimeNegPtr,DIOposSwPrimeNode,DIOnegNode); + TSTALLOC(DIOposSwPrimePosSwPrimePtr,DIOposSwPrimeNode,DIOposSwPrimeNode); + } if (selfheat) { TSTALLOC(DIOtempPosPtr, DIOtempNode, DIOposNode); @@ -384,6 +444,11 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ TSTALLOC(DIOposTempPtr, DIOposNode, DIOtempNode); TSTALLOC(DIOposPrimeTempPtr, DIOposPrimeNode, DIOtempNode); TSTALLOC(DIOnegTempPtr, DIOnegNode, DIOtempNode); + if(model->DIOresistSWGiven) { + /* separate sidewall */ + TSTALLOC(DIOtempPosSwPrimePtr, DIOtempNode, DIOposSwPrimeNode); + TSTALLOC(DIOposSwPrimeTempPtr, DIOposSwPrimeNode, DIOtempNode); + } } } @@ -410,6 +475,15 @@ DIOunsetup( && here->DIOposPrimeNode != here->DIOposNode) CKTdltNNum(ckt, here->DIOposPrimeNode); here->DIOposPrimeNode = 0; + + if(model->DIOresistSWGiven) { + /* separate sidewall */ + if (here->DIOposSwPrimeNode > 0 + && here->DIOposSwPrimeNode != here->DIOposNode) + CKTdltNNum(ckt, here->DIOposSwPrimeNode); + here->DIOposSwPrimeNode = 0; + } + } } return OK; diff --git a/src/spicelib/devices/dio/diotemp.c b/src/spicelib/devices/dio/diotemp.c index 30a47405b..d39b03de4 100644 --- a/src/spicelib/devices/dio/diotemp.c +++ b/src/spicelib/devices/dio/diotemp.c @@ -29,6 +29,7 @@ void DIOtempUpdate(DIOmodel *inModel, DIOinstance *here, double Temp, CKTcircuit double dt; double factor; double tBreakdownVoltage; + double totalSatCur; double egfet1,arg1,fact1,pbfact1,pbo,gmaold,pboSW,gmaSWold; double fact2,pbfact,arg,egfet,gmanew,gmaSWnew; @@ -196,9 +197,14 @@ void DIOtempUpdate(DIOmodel *inModel, DIOinstance *here, double Temp, CKTcircuit here->DIOtDepSWCap=model->DIOdepletionSWcapCoeff* here->DIOtJctSWPot; /* and Vcrit */ - double totalSatCur = here->DIOtSatCur + here->DIOtSatSWCur; - here->DIOtVcrit = vte * log(vte/(CONSTroot2*totalSatCur)); - + totalSatCur = here->DIOtSatCur + here->DIOtSatSWCur; + if(model->DIOresistSWGiven) { + here->DIOtVcrit = vte * log(vte/(CONSTroot2*here->DIOtSatCur)); + here->DIOtVcritSW = vts * log(vts/(CONSTroot2*here->DIOtSatSWCur)); + } else { + here->DIOtVcrit = vte * log(vte/(CONSTroot2*totalSatCur)); + here->DIOtVcritSW = vts * log(vts/(CONSTroot2*here->DIOtSatSWCur)); + } /* and now to compute the breakdown voltage, again, using * temperature adjusted basic parameters */ if (model->DIObreakdownVoltageGiven){ @@ -253,6 +259,14 @@ void DIOtempUpdate(DIOmodel *inModel, DIOinstance *here, double Temp, CKTcircuit here->DIOtConductance_dT = -model->DIOconductance * here->DIOarea * here->DIOm * (model->DIOresistTemp1 + model->DIOresistTemp2 * dt) / (factor*factor); } + here->DIOtConductanceSW = model->DIOconductanceSW * here->DIOpj * here->DIOm; + if(model->DIOresistSWGiven && model->DIOresistSW!=0.0) { + factor = 1.0 + (model->DIOresistTemp1) * dt + + (model->DIOresistTemp2 * dt * dt); + here->DIOtConductanceSW = model->DIOconductanceSW * here->DIOpj * here->DIOm / factor; + here->DIOtConductanceSW_dT = -model->DIOconductanceSW * here->DIOpj * here->DIOm * + (model->DIOresistTemp1 + model->DIOresistTemp2 * dt) / (factor*factor); + } here->DIOtF2=exp((1+here->DIOtGradingCoeff)*xfc); here->DIOtF3=1-model->DIOdepletionCapCoeff* diff --git a/src/spicelib/devices/dio/diotrunc.c b/src/spicelib/devices/dio/diotrunc.c index 5c64086f9..b940528be 100644 --- a/src/spicelib/devices/dio/diotrunc.c +++ b/src/spicelib/devices/dio/diotrunc.c @@ -21,6 +21,7 @@ DIOtrunc(GENmodel *inModel, CKTcircuit *ckt, double *timeStep) for( ; model != NULL; model = DIOnextModel(model)) { for(here=DIOinstances(model);here!=NULL;here = DIOnextInstance(here)){ CKTterr(here->DIOcapCharge,ckt,timeStep); + if (model->DIOresistSWGiven) CKTterr(here->DIOcapChargeSW,ckt,timeStep); } } return(OK); diff --git a/src/spicelib/devices/vdmos/vdmosacld.c b/src/spicelib/devices/vdmos/vdmosacld.c index 5e5315611..fd90caa66 100644 --- a/src/spicelib/devices/vdmos/vdmosacld.c +++ b/src/spicelib/devices/vdmos/vdmosacld.c @@ -48,7 +48,8 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt) GmT = model->VDMOStype * here->VDMOSgmT; cgT = model->VDMOStype * here->VDMOScgT; cdT = model->VDMOStype * here->VDMOScdT; - cTt = model->VDMOScthj; + // Everything is computed for m parallel instances... so scale cthj accordingly + cTt = here->VDMOSm * model->VDMOScthj; gTtg = here->VDMOSgtempg; gTtdp = here->VDMOSgtempd; gTtt = here->VDMOSgtempT; @@ -57,7 +58,8 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt) GmT = -model->VDMOStype * here->VDMOSgmT; cgT = -model->VDMOStype * here->VDMOScgT; cdT = -model->VDMOStype * here->VDMOScdT; - cTt = -model->VDMOScthj; + // Everything is computed for m parallel instances... so scale cthj accordingly + cTt = - here->VDMOSm * model->VDMOScthj; gTtg = -here->VDMOSgtempg; gTtdp = -here->VDMOSgtempd; gTtt = -here->VDMOSgtempT; @@ -131,21 +133,23 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt) *(here->VDIORPdPtr +1) -= xceq; if (selfheat) { - *(here->VDMOSDPtempPtr) += GmT; + // Everything is computed for m parallel instances... so scale gthjc and gthja accordingly + double gthjc = here->VDMOSm / model->VDMOSrthjc; + double gthca = here->VDMOSm / model->VDMOSrthca; + *(here->VDMOSDPtempPtr) += GmT; *(here->VDMOSSPtempPtr) += -GmT; - - *(here->VDMOSTemptempPtr) += gTtt + 1/model->VDMOSrthjc; - *(here->VDMOSTempgpPtr) += gTtg; - *(here->VDMOSTempdpPtr) += gTtdp; - *(here->VDMOSTempspPtr) += gTtsp; - *(here->VDMOSTemptcasePtr) += -1/model->VDMOSrthjc; - *(here->VDMOSTcasetempPtr) += -1/model->VDMOSrthjc; - *(here->VDMOSTcasetcasePtr) += 1/model->VDMOSrthjc + 1/model->VDMOSrthca; - *(here->VDMOSTptpPtr) += 1/model->VDMOSrthca; - *(here->VDMOSTptcasePtr) += -1/model->VDMOSrthca; - *(here->VDMOSTcasetpPtr) += -1/model->VDMOSrthca; - *(here->VDMOSCktTtpPtr) += 1.0; - *(here->VDMOSTpcktTPtr) += 1.0; + *(here->VDMOSTemptempPtr) += gTtt + gthjc; + *(here->VDMOSTempgpPtr) += gTtg; + *(here->VDMOSTempdpPtr) += gTtdp; + *(here->VDMOSTempspPtr) += gTtsp; + *(here->VDMOSTemptcasePtr) += -gthjc; + *(here->VDMOSTcasetempPtr) += -gthjc; + *(here->VDMOSTcasetcasePtr) += gthjc + gthca; + *(here->VDMOSTptpPtr) += gthca; + *(here->VDMOSTptcasePtr) += -gthca; + *(here->VDMOSTcasetpPtr) += -gthca; + *(here->VDMOSDevTtpPtr) += 1.0; + *(here->VDMOSTpdevTPtr) += 1.0; *(here->VDMOSTemptempPtr + 1) += xcTt; *(here->VDMOSDPtempPtr + 1) += xcdT; diff --git a/src/spicelib/devices/vdmos/vdmosbindCSC.c b/src/spicelib/devices/vdmos/vdmosbindCSC.c index 1d85b47df..bd24b856d 100644 --- a/src/spicelib/devices/vdmos/vdmosbindCSC.c +++ b/src/spicelib/devices/vdmos/vdmosbindCSC.c @@ -67,18 +67,18 @@ VDMOSbindCSC (GENmodel *inModel, CKTcircuit *ckt) CREATE_KLU_BINDING_TABLE(VDMOSTempdPtr, VDMOSTempdBinding, VDMOStempNode, VDMOSdNode); CREATE_KLU_BINDING_TABLE(VDIOPosPrimetempPtr, VDIOPosPrimetempBinding, VDIOposPrimeNode, VDMOStempNode); CREATE_KLU_BINDING_TABLE(VDMOSDtempPtr, VDMOSDtempBinding, VDMOSdNode, VDMOStempNode); - CREATE_KLU_BINDING_TABLE(VDMOStempSPtr, VDMOStempSBinding, VDMOStempNode, VDMOSsNode); - CREATE_KLU_BINDING_TABLE(VDMOSSTempPtr, VDMOSSTempBinding, VDMOSsNode, VDMOStempNode); + CREATE_KLU_BINDING_TABLE(VDMOSTempsPtr, VDMOStempSBinding, VDMOStempNode, VDMOSsNode); + CREATE_KLU_BINDING_TABLE(VDMOSStempPtr, VDMOSSTempBinding, VDMOSsNode, VDMOStempNode); CREATE_KLU_BINDING_TABLE(VDMOSTcasetcasePtr, VDMOSTcasetcaseBinding, VDMOStcaseNode, VDMOStcaseNode); /* Rthjc between tj and tcase*/ CREATE_KLU_BINDING_TABLE(VDMOSTcasetempPtr, VDMOSTcasetempBinding, VDMOStcaseNode, VDMOStempNode); CREATE_KLU_BINDING_TABLE(VDMOSTemptcasePtr, VDMOSTemptcaseBinding, VDMOStempNode, VDMOStcaseNode); CREATE_KLU_BINDING_TABLE(VDMOSTptpPtr, VDMOSTptpBinding, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */ - CREATE_KLU_BINDING_TABLE(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStempNode); - CREATE_KLU_BINDING_TABLE(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStempNode, VDMOStNodePrime); - CREATE_KLU_BINDING_TABLE(VDMOSCktTcktTPtr, VDMOSCktTcktTBinding, VDMOSvcktTbranch, VDMOSvcktTbranch); /* Vsrc=cktTemp to gnd */ - CREATE_KLU_BINDING_TABLE(VDMOSCktTtpPtr, VDMOSCktTtpBinding, VDMOSvcktTbranch, VDMOStNodePrime); - CREATE_KLU_BINDING_TABLE(VDMOSTpcktTPtr, VDMOSTpcktTBinding, VDMOStNodePrime, VDMOSvcktTbranch); + CREATE_KLU_BINDING_TABLE(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStcaseNode); + CREATE_KLU_BINDING_TABLE(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStcaseNode, VDMOStNodePrime); + CREATE_KLU_BINDING_TABLE(VDMOSDevTdevTPtr, VDMOSDevTdevTBinding, VDMOSvdevTbranch, VDMOSvdevTbranch); /* Vsrc=devTemp to gnd */ + CREATE_KLU_BINDING_TABLE(VDMOSDevTtpPtr, VDMOSDevTtpBinding, VDMOSvdevTbranch, VDMOStNodePrime); + CREATE_KLU_BINDING_TABLE(VDMOSTpdevTPtr, VDMOSTpdevTBinding, VDMOStNodePrime, VDMOSvdevTbranch); } } } @@ -142,18 +142,18 @@ VDMOSbindCSCComplex (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTempdPtr, VDMOSTempdBinding, VDMOStempNode, VDMOSdNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDIOPosPrimetempPtr, VDIOPosPrimetempBinding, VDIOposPrimeNode, VDMOStempNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSDtempPtr, VDMOSDtempBinding, VDMOSdNode, VDMOStempNode); - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOStempSPtr, VDMOStempSBinding, VDMOStempNode, VDMOSsNode); - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSSTempPtr, VDMOSSTempBinding, VDMOSsNode, VDMOStempNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTempsPtr, VDMOStempSBinding, VDMOStempNode, VDMOSsNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSStempPtr, VDMOSSTempBinding, VDMOSsNode, VDMOStempNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTcasetcasePtr, VDMOSTcasetcaseBinding, VDMOStcaseNode, VDMOStcaseNode); /* Rthjc between tj and tcase*/ CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTcasetempPtr, VDMOSTcasetempBinding, VDMOStcaseNode, VDMOStempNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTemptcasePtr, VDMOSTemptcaseBinding, VDMOStempNode, VDMOStcaseNode); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTptpPtr, VDMOSTptpBinding, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */ - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStempNode); - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStempNode, VDMOStNodePrime); - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSCktTcktTPtr, VDMOSCktTcktTBinding, VDMOSvcktTbranch, VDMOSvcktTbranch); /* Vsrc=cktTemp to gnd */ - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSCktTtpPtr, VDMOSCktTtpBinding, VDMOSvcktTbranch, VDMOStNodePrime); - CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTpcktTPtr, VDMOSTpcktTBinding, VDMOStNodePrime, VDMOSvcktTbranch); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStcaseNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStcaseNode, VDMOStNodePrime); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSDevTdevTPtr, VDMOSDevTdevTBinding, VDMOSvdevTbranch, VDMOSvdevTbranch); /* Vsrc=devTemp to gnd */ + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSDevTtpPtr, VDMOSDevTtpBinding, VDMOSvdevTbranch, VDMOStNodePrime); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTpdevTPtr, VDMOSTpdevTBinding, VDMOStNodePrime, VDMOSvdevTbranch); } } } @@ -217,18 +217,18 @@ VDMOSbindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTempdPtr, VDMOSTempdBinding, VDMOStempNode, VDMOSdNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(VDIOPosPrimetempPtr, VDIOPosPrimetempBinding, VDIOposPrimeNode, VDMOStempNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSDtempPtr, VDMOSDtempBinding, VDMOSdNode, VDMOStempNode); - CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOStempSPtr, VDMOStempSBinding, VDMOStempNode, VDMOSsNode); - CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSSTempPtr, VDMOSSTempBinding, VDMOSsNode, VDMOStempNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTempsPtr, VDMOStempSBinding, VDMOStempNode, VDMOSsNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSStempPtr, VDMOSSTempBinding, VDMOSsNode, VDMOStempNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTcasetcasePtr, VDMOSTcasetcaseBinding, VDMOStcaseNode, VDMOStcaseNode); /* Rthjc between tj and tcase*/ CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTcasetempPtr, VDMOSTcasetempBinding, VDMOStcaseNode, VDMOStempNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTemptcasePtr, VDMOSTemptcaseBinding, VDMOStempNode, VDMOStcaseNode); CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTptpPtr, VDMOSTptpBinding, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */ - CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStempNode); - CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStempNode, VDMOStNodePrime); - CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSCktTcktTPtr, VDMOSCktTcktTBinding, VDMOSvcktTbranch, VDMOSvcktTbranch); /* Vsrc=cktTemp to gnd */ - CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSCktTtpPtr, VDMOSCktTtpBinding, VDMOSvcktTbranch, VDMOStNodePrime); - CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTpcktTPtr, VDMOSTpcktTBinding, VDMOStNodePrime, VDMOSvcktTbranch); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStcaseNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStcaseNode, VDMOStNodePrime); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSDevTdevTPtr, VDMOSDevTdevTBinding, VDMOSvdevTbranch, VDMOSvdevTbranch); /* Vsrc=devTemp to gnd */ + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSDevTtpPtr, VDMOSDevTtpBinding, VDMOSvdevTbranch, VDMOStNodePrime); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTpdevTPtr, VDMOSTpdevTBinding, VDMOStNodePrime, VDMOSvdevTbranch); } } } diff --git a/src/spicelib/devices/vdmos/vdmosconv.c b/src/spicelib/devices/vdmos/vdmosconv.c index c51a94a0a..49e0ccde8 100644 --- a/src/spicelib/devices/vdmos/vdmosconv.c +++ b/src/spicelib/devices/vdmos/vdmosconv.c @@ -82,8 +82,9 @@ VDMOSconvTest(GENmodel *inModel, CKTcircuit *ckt) * initialization */ - vd = *(ckt->CKTrhsOld+here->VDIOposPrimeNode)- - *(ckt->CKTrhsOld + here->VDMOSdNode); + vd = model->VDMOStype * ( + *(ckt->CKTrhsOld+here->VDIOposPrimeNode)- + *(ckt->CKTrhsOld + here->VDMOSdNode)); delvd=vd- *(ckt->CKTstate0 + here->VDIOvoltage); diff --git a/src/spicelib/devices/vdmos/vdmosdefs.h b/src/spicelib/devices/vdmos/vdmosdefs.h index 28e42b74b..5409a520f 100644 --- a/src/spicelib/devices/vdmos/vdmosdefs.h +++ b/src/spicelib/devices/vdmos/vdmosdefs.h @@ -50,7 +50,7 @@ typedef struct sVDMOSinstance { int VDMOStNodePrime; /* number of the internal temp node between voltage source and Rthca */ int VDIOposPrimeNode; /* number of the internal node of the body diode */ - int VDMOSvcktTbranch; /* equation number of branch equation added for cktTemp source */ + int VDMOSvdevTbranch; /* equation number of branch equation added for cktTemp source */ double VDMOSm; /* parallel device multiplier */ @@ -229,8 +229,8 @@ typedef struct sVDMOSinstance { double *VDMOSTempdPtr; double *VDIOPosPrimetempPtr; double *VDMOSDtempPtr; - double *VDMOStempSPtr; - double *VDMOSSTempPtr; + double *VDMOSTempsPtr; + double *VDMOSStempPtr; double *VDMOSTcasetcasePtr; /* for Rthjc */ double *VDMOSTcasetempPtr; @@ -238,9 +238,9 @@ typedef struct sVDMOSinstance { double *VDMOSTptpPtr; /* for Rthca */ double *VDMOSTptcasePtr; double *VDMOSTcasetpPtr; - double *VDMOSCktTcktTPtr; /* for VcktTemp */ - double *VDMOSCktTtpPtr; - double *VDMOSTpcktTPtr; + double *VDMOSDevTdevTPtr; /* for VdevTemp */ + double *VDMOSDevTtpPtr; + double *VDMOSTpdevTPtr; #ifdef KLU BindElement *VDMOSDdBinding ; @@ -287,9 +287,9 @@ typedef struct sVDMOSinstance { BindElement *VDMOSTptpBinding ; BindElement *VDMOSTptcaseBinding ; BindElement *VDMOSTcasetpBinding ; - BindElement *VDMOSCktTcktTBinding ; - BindElement *VDMOSCktTtpBinding ; - BindElement *VDMOSTpcktTBinding ; + BindElement *VDMOSDevTdevTBinding ; + BindElement *VDMOSDevTtpBinding ; + BindElement *VDMOSTpdevTBinding ; #endif } VDMOSinstance ; diff --git a/src/spicelib/devices/vdmos/vdmosload.c b/src/spicelib/devices/vdmos/vdmosload.c index 5e29a989a..f5c0d4e8d 100644 --- a/src/spicelib/devices/vdmos/vdmosload.c +++ b/src/spicelib/devices/vdmos/vdmosload.c @@ -57,26 +57,27 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) int error; int selfheat; - double rd0T, rd1T, dBeta_dT, dIds_dT; + double rd0T, rd1T, dBeta_dT, dIds_dT=0.0; double Vrd=0.0, dIth_dVrd=0.0, dIrd_dT=0.0; - double drd0T_dT, drd1T_dT, drd_dT, dgdrain_dT=0.0; - double dIrd_dgdrain; + double drd0T_dT, drd1T_dT, dgdrain_dT=0.0; + double rsT, Vrs=0.0, dIth_dVrs=0.0, dIrs_dT=0.0, dgsource_dT=0.0; double deldelTemp=0.0, delTemp, delTemp1, Temp, Vds, Vgs; double ceqqth=0.0; double GmT, gTtg, gTtdp, gTtt, gTtsp, gcTt=0.0; /* loop through all the VDMOS device models */ for (; model != NULL; model = VDMOSnextModel(model)) { - /* VDMOS capacitance parameters */ - const double cgdmin = model->VDMOScgdmin; - const double cgdmax = model->VDMOScgdmax; - const double a = model->VDMOSa; - const double cgs = model->VDMOScgs; /* loop through all the instances of the model */ for (here = VDMOSinstances(model); here != NULL; here = VDMOSnextInstance(here)) { + /* VDMOS capacitance parameters */ + const double cgdmin = here->VDMOSm * model->VDMOScgdmin; + const double cgdmax = here->VDMOSm * model->VDMOScgdmax; + const double a = model->VDMOSa; + const double cgs = here->VDMOSm * model->VDMOScgs; + Temp = here->VDMOStemp; selfheat = (here->VDMOSthermal) && (model->VDMOSrthjcGiven); if (selfheat) @@ -84,16 +85,6 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) else Check_th = 0; - /* FIXME: - this is not a fix, but a hack: - with selfheat, op and op for ac don't work, NaN in self heating evaluation of - first iteration in CKTop(). Calling CKTop() from acan uses flag MODEDCOP, - changing this to MODETRANOP, as used by CKTop() called from dctran, then op is o.k. - */ - if (selfheat) - if(ckt->CKTmode == 528) /* includes MODEDCOP */ - ckt->CKTmode = 544; /* includes MODETRANOP */ - /* first, we compute a few useful values - these could be * pre-computed, but for historical reasons are still done * here. They may be moved at the expense of instance size @@ -279,7 +270,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) } if (selfheat) delTemp = DEVlimitlog(delTemp, - *(ckt->CKTstate0 + here->VDMOSdelTemp),30,&Check_th); + *(ckt->CKTstate0 + here->VDMOSdelTemp),10,&Check_th); else delTemp = 0.0; #endif /*NODELIMITING*/ @@ -287,7 +278,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) } if (selfheat) { - Temp = here->VDMOStemp + delTemp; + Temp = delTemp + CONSTCtoK; VDMOStempUpdate(model, here, Temp, ckt); } else { Temp = here->VDMOStemp; @@ -296,17 +287,24 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) /* Calculate temperature dependent values for self-heating effect */ if (selfheat) { - double TempRatio = Temp / here->VDMOStemp; - Beta = here->VDMOStTransconductance * pow(TempRatio,model->VDMOSmu); + Beta = here->VDMOStTransconductance; dBeta_dT = Beta * model->VDMOSmu / Temp; - rd0T = here->VDMOSdrainResistance * pow(TempRatio, model->VDMOStexp0); - drd0T_dT = rd0T * model->VDMOStexp0 / Temp; + rd0T = here->VDMOSdrainResistance; + if (model->VDMOStexp0Given) + drd0T_dT = rd0T * model->VDMOStexp0 / Temp; + else + drd0T_dT = model->VDMOSdrainResistance / here->VDMOSm + * (model->VDMOStrd1 + 2 * model->VDMOStrd2 * (Temp - model->VDMOStnom)); rd1T = 0.0; drd1T_dT = 0.0; if (model->VDMOSqsGiven) { - rd1T = here->VDMOSqsResistance * pow(TempRatio, model->VDMOStexp1); + rd1T = here->VDMOSqsResistance; drd1T_dT = rd1T * model->VDMOStexp1 / Temp; } + rsT = 1 / here->VDMOSsourceConductance; + double drsT_dT = model->VDMOSsourceResistance / here->VDMOSm + * (model->VDMOStrs1 + 2 * model->VDMOStrs2 * (Temp - model->VDMOStnom)); + dgsource_dT = -drsT_dT / (rsT*rsT); } else { Beta = here->VDMOStTransconductance; dBeta_dT = 0.0; @@ -316,6 +314,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) drd1T_dT = 0.0; if (model->VDMOSqsGiven) rd1T = here->VDMOSqsResistance; + dgsource_dT = 0.0; } /* @@ -368,7 +367,6 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) double betap = Beta*t0/t1; double dbetapdvgs = -Beta*theta*t0/(t1*t1); double dbetapdvds = Beta*lambda/t1; - double dbetapdT = dBeta_dT*t0/t1; double t2 = exp((vgst-shift)/slope); vgst = slope * log(1 + t2); @@ -379,14 +377,27 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) cdrain = betap * vgst*vgst * .5; here->VDMOSgm = betap*vgst*dvgstdvgs + 0.5*dbetapdvgs*vgst*vgst; here->VDMOSgds = .5*dbetapdvds*vgst*vgst; - dIds_dT = dbetapdT * vgst*vgst * .5; } else { /* linear region */ cdrain = betap * vdss * (vgst - .5 * vdss); here->VDMOSgm = betap*vdss*dvgstdvgs + vdss*dbetapdvgs*(vgst-.5*vdss); here->VDMOSgds = vdss*dbetapdvds*(vgst-.5*vdss) + betap*mtr*(vgst-.5*vdss) - .5*vdss*betap*mtr; - dIds_dT = dbetapdT * vdss * (vgst - .5 * vdss); + } + if (selfheat) { + double dvgst_dT = model->VDMOStype * model->VDMOStcvth; + double dvdsat_dT = 0.0; + if (vgst > 0) { + dvdsat_dT = dvgst_dT; + } + double dt1_dT = theta * dvdsat_dT; + double dbetap_dT = t0 * (t1 * dBeta_dT - Beta * dt1_dT) / (t1 * t1); + if (vgst <= vdss) { + dIds_dT = .5 * dbetap_dT * vgst*vgst + betap * vgst * dvgst_dT; + } + else { + dIds_dT = vdss * (dbetap_dT * vgst + betap * dvgst_dT) - dbetap_dT * vdss * .5 * vdss; + } } } @@ -418,7 +429,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) *(ckt->CKTrhsOld + here->VDMOSdNode) - *(ckt->CKTrhsOld + here->VDMOSsNode)); double rd = rd0T + rd1T * (vdsn / (vdsn + fabs(model->VDMOSqsVoltage))); - drd_dT = drd0T_dT + drd1T_dT * (vdsn / (vdsn + fabs(model->VDMOSqsVoltage))); + double drd_dT = drd0T_dT + drd1T_dT * (vdsn / (vdsn + fabs(model->VDMOSqsVoltage))); if (rd > 0) { here->VDMOSdrainConductance = 1 / rd + ckt->CKTgmin; dgdrain_dT = -drd_dT / (rd*rd); @@ -451,10 +462,16 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) - here->VDMOSgtempT * delTemp; Vrd = *(ckt->CKTrhsOld + here->VDMOSdNode) - *(ckt->CKTrhsOld + here->VDMOSdNodePrime); - dIth_dVrd = here->VDMOSdrainConductance * Vrd; - dIrd_dgdrain = Vrd; + dIth_dVrd = here->VDMOSdrainConductance * 2 * Vrd; + double dIrd_dgdrain = Vrd; dIrd_dT = dIrd_dgdrain * dgdrain_dT; here->VDMOScth += here->VDMOSdrainConductance * Vrd*Vrd - dIth_dVrd*Vrd - dIrd_dT*Vrd*delTemp; + + Vrs = *(ckt->CKTrhsOld + here->VDMOSsNode) - *(ckt->CKTrhsOld + here->VDMOSsNodePrime); + dIth_dVrs = here->VDMOSsourceConductance * 2 * Vrs; + double dIrs_dgsource = Vrs; + dIrs_dT = dIrs_dgsource * dgsource_dT; + here->VDMOScth += here->VDMOSsourceConductance * Vrs*Vrs - dIth_dVrs*Vrs - dIrs_dT*Vrs*delTemp; } /* @@ -475,7 +492,11 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) DevCapVDMOS(vgd, cgdmin, cgdmax, a, cgs, (ckt->CKTstate0 + here->VDMOScapgs), (ckt->CKTstate0 + here->VDMOScapgd)); - *(ckt->CKTstate0 + here->VDMOScapth) = model->VDMOScthj; /* always constant */ + /* Everything is computed for m parallel instances... so scale cthj accordingly + * Also, take into account Meyer numerical integration style and + * halve the value of cthj that gets stored in the state. + */ + *(ckt->CKTstate0 + here->VDMOScapth) = here->VDMOSm * model->VDMOScthj / 2; /* always constant */ vgs1 = *(ckt->CKTstate1 + here->VDMOSvgs); vgd1 = vgs1 - *(ckt->CKTstate1 + here->VDMOSvds); @@ -558,8 +579,6 @@ bypass: { error = NIintegrate(ckt, &gcTt, &ceqqth, capth, here->VDMOSqth); if (error) return(error); - ceqqth = ceqqth - gcTt*delTemp + ckt->CKTag[0] * - *(ckt->CKTstate0 + here->VDMOSqth); } } @@ -606,13 +625,16 @@ bypass: *(ckt->CKTrhs + here->VDMOSsNodePrime) += cdreq + model->VDMOStype * ceqgs; if (selfheat) { *(ckt->CKTrhs + here->VDMOSdNode) += dIrd_dT * delTemp; + *(ckt->CKTrhs + here->VDMOSsNode) += dIrs_dT * delTemp; *(ckt->CKTrhs + here->VDMOSdNodePrime) += GmT * delTemp - dIrd_dT * delTemp; - *(ckt->CKTrhs + here->VDMOSsNodePrime) += -GmT * delTemp; + *(ckt->CKTrhs + here->VDMOSsNodePrime) += -GmT * delTemp - dIrs_dT * delTemp; *(ckt->CKTrhs + here->VDMOStempNode) += here->VDMOScth - ceqqth; - double vCktTemp = (ckt->CKTtemp-CONSTCtoK); /* ckt temperature */ + double vDevTemp = (ckt->CKTtemp-CONSTCtoK); /* ckt temperature */ + if (here->VDMOStempGiven) + vDevTemp = (here->VDMOStemp-CONSTCtoK); /* device temperature */ if (ckt->CKTmode & MODETRANOP) - vCktTemp *= ckt->CKTsrcFact; - *(ckt->CKTrhs + here->VDMOSvcktTbranch)+= vCktTemp; + vDevTemp *= ckt->CKTsrcFact; + *(ckt->CKTrhs + here->VDMOSvdevTbranch)+= vDevTemp; } /* @@ -649,24 +671,28 @@ bypass: if (selfheat) { - + /* Everything is computed for m parallel instances... so scale gthjc and gthja accordingly + */ + double gthjc = here->VDMOSm / model->VDMOSrthjc; + double gthca = here->VDMOSm / model->VDMOSrthca; (*(here->VDMOSDtempPtr) += dIrd_dT); (*(here->VDMOSDPtempPtr) += GmT - dIrd_dT); - (*(here->VDMOSSPtempPtr) += -GmT); - (*(here->VDMOSGPtempPtr) += 0.0); - (*(here->VDMOSTemptempPtr) += -gTtt - dIrd_dT*Vrd + 1/model->VDMOSrthjc + gcTt); + (*(here->VDMOSStempPtr) += dIrs_dT); + (*(here->VDMOSSPtempPtr) += -GmT - dIrs_dT); + (*(here->VDMOSTemptempPtr) += -gTtt - dIrd_dT*Vrd - dIrs_dT*Vrs + gthjc + gcTt); (*(here->VDMOSTempgpPtr) += -gTtg); (*(here->VDMOSTempdPtr) += -dIth_dVrd); + (*(here->VDMOSTempsPtr) += -dIth_dVrs); (*(here->VDMOSTempdpPtr) += -gTtdp + dIth_dVrd); - (*(here->VDMOSTempspPtr) += -gTtsp); - (*(here->VDMOSTemptcasePtr) += -1/model->VDMOSrthjc); - (*(here->VDMOSTcasetempPtr) += -1/model->VDMOSrthjc); - (*(here->VDMOSTcasetcasePtr) += 1/model->VDMOSrthjc + 1/model->VDMOSrthca); - (*(here->VDMOSTptpPtr) += 1/model->VDMOSrthca); - (*(here->VDMOSTptcasePtr) += -1/model->VDMOSrthca); - (*(here->VDMOSTcasetpPtr) += -1/model->VDMOSrthca); - (*(here->VDMOSCktTtpPtr) += 1.0); - (*(here->VDMOSTpcktTPtr) += 1.0); + (*(here->VDMOSTempspPtr) += -gTtsp + dIth_dVrs); + (*(here->VDMOSTemptcasePtr) += -gthjc); + (*(here->VDMOSTcasetempPtr) += -gthjc); + (*(here->VDMOSTcasetcasePtr) += gthjc + gthca); + (*(here->VDMOSTptpPtr) += gthca); + (*(here->VDMOSTptcasePtr) += -gthca); + (*(here->VDMOSTcasetpPtr) += -gthca); + (*(here->VDMOSDevTtpPtr) += 1.0); + (*(here->VDMOSTpdevTPtr) += 1.0); } /* body diode model @@ -678,18 +704,18 @@ bypass: double vtebrk, vbrknp; double cdb, cdeq; double capd; - double gd, gdb, gspr; + double gd, gdb, gbpr; double delvd; /* change in diode voltage temporary */ double evrev; double Ith=0.0, dIth_dT=0.0; double dIdio_dT=0.0, dIth_dVdio=0.0; - double vrs=0.0, dIrs_dT=0.0, dIth_dVrs=0.0; + double vrb=0.0, dIrb_dT=0.0, dIth_dVrb=0.0; #ifndef NOBYPASS double tol; /* temporary for tolerance calculations */ #endif - gspr = here->VDIOtConductance; + gbpr = here->VDIOtConductance; vt = CONSTKoverQ * Temp; vte = model->VDIOn * vt; @@ -884,18 +910,18 @@ bypass: load: #endif if (selfheat) { - double dIrs_dgspr, dIth_dIrs; - vrs = *(ckt->CKTrhsOld + here->VDMOSsNode) - *(ckt->CKTrhsOld + here->VDIOposPrimeNode); + double dIrb_dgbpr, dIth_dIrb; + vrb = *(ckt->CKTrhsOld + here->VDMOSsNode) - *(ckt->CKTrhsOld + here->VDIOposPrimeNode); - Ith = vd*cd + vrs*vrs*gspr; + Ith = vd*cd + vrb*vrb*gbpr; dIth_dVdio = cd + vd*gd; - dIth_dVrs = vrs*gspr; + dIth_dVrb = vrb*gbpr; - dIrs_dgspr = vrs; - dIrs_dT = dIrs_dgspr * here->VDIOtConductance_dT; - dIth_dIrs = vrs; - dIth_dT = dIth_dIrs*dIrs_dT + dIdio_dT*vd; + dIrb_dgbpr = vrb; + dIrb_dT = dIrb_dgbpr * here->VDIOtConductance_dT; + dIth_dIrb = vrb; + dIth_dT = dIth_dIrb*dIrb_dT + dIdio_dT*vd; } /* * load current vector @@ -909,28 +935,28 @@ load: *(ckt->CKTrhs + here->VDIOposPrimeNode) += cdeq; } if (selfheat) { - *(ckt->CKTrhs + here->VDIOposPrimeNode) += dIdio_dT*delTemp - dIrs_dT*delTemp; + *(ckt->CKTrhs + here->VDIOposPrimeNode) += dIdio_dT*delTemp - dIrb_dT*delTemp; *(ckt->CKTrhs + here->VDMOSdNode) += -dIdio_dT*delTemp; - *(ckt->CKTrhs + here->VDMOSsNode) += dIrs_dT*delTemp; - *(ckt->CKTrhs + here->VDMOStempNode) += Ith - model->VDMOStype*dIth_dVdio*vd - dIth_dVrs*vrs - dIth_dT*delTemp; + *(ckt->CKTrhs + here->VDMOSsNode) += dIrb_dT*delTemp; + *(ckt->CKTrhs + here->VDMOStempNode) += Ith - model->VDMOStype*dIth_dVdio*vd - dIth_dVrb*vrb - dIth_dT*delTemp; } /* * load matrix */ - *(here->VDMOSSsPtr) += gspr; + *(here->VDMOSSsPtr) += gbpr; *(here->VDMOSDdPtr) += gd; - *(here->VDIORPrpPtr) += (gd + gspr); - *(here->VDIOSrpPtr) -= gspr; + *(here->VDIORPrpPtr) += (gd + gbpr); + *(here->VDIOSrpPtr) -= gbpr; *(here->VDIODrpPtr) -= gd; - *(here->VDIORPsPtr) -= gspr; + *(here->VDIORPsPtr) -= gbpr; *(here->VDIORPdPtr) -= gd; if (selfheat) { - (*(here->VDMOStempSPtr) += -dIth_dVrs); - (*(here->VDIOTempposPrimePtr) += -dIth_dVdio + dIth_dVrs); + (*(here->VDMOSTempsPtr) += -dIth_dVrb); + (*(here->VDIOTempposPrimePtr) += -dIth_dVdio + dIth_dVrb); (*(here->VDMOSTempdPtr) += dIth_dVdio); (*(here->VDMOSTemptempPtr) += -dIth_dT); - (*(here->VDIOPosPrimetempPtr) += dIdio_dT - dIrs_dT); - (*(here->VDMOSSTempPtr) += dIrs_dT); + (*(here->VDIOPosPrimetempPtr) += dIdio_dT - dIrb_dT); + (*(here->VDMOSStempPtr) += dIrb_dT); (*(here->VDMOSDtempPtr) += -dIdio_dT); } } diff --git a/src/spicelib/devices/vdmos/vdmosnoi.c b/src/spicelib/devices/vdmos/vdmosnoi.c index 273d4f34e..8896bd54d 100644 --- a/src/spicelib/devices/vdmos/vdmosnoi.c +++ b/src/spicelib/devices/vdmos/vdmosnoi.c @@ -110,11 +110,12 @@ VDMOSnoise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, NevalSrc(&noizDens[VDMOSFLNOIZ], NULL, ckt, N_GAIN,inst->VDMOSdNodePrime, inst->VDMOSsNodePrime, (double)0.0); + // VDMOScd is scaled with m, no need to scale coxSquared (which is a constant) + // Should be proportional to m noizDens[VDMOSFLNOIZ] *= model->VDMOSfNcoef * exp(model->VDMOSfNexp * log(MAX(fabs(inst->VDMOScd),N_MINLOG))) / - (data->freq * - inst->VDMOSm * coxSquared); + (data->freq * coxSquared); lnNdens[VDMOSFLNOIZ] = log(MAX(noizDens[VDMOSFLNOIZ],N_MINLOG)); diff --git a/src/spicelib/devices/vdmos/vdmosset.c b/src/spicelib/devices/vdmos/vdmosset.c index ab59ede32..dfc6a2da3 100644 --- a/src/spicelib/devices/vdmos/vdmosset.c +++ b/src/spicelib/devices/vdmos/vdmosset.c @@ -259,6 +259,13 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, here->VDMOSstates = *states; *states += VDMOSnumStates; + if ((here->VDMOStempGiven) && (here->VDMOSdtempGiven)) { + SPfrontEnd->IFerrorf(ERR_WARNING, + "%s: temp and dtemp instance parameter given - using dtemp", + here->VDMOSname); + here->VDMOStempGiven = FALSE; + } + if (!here->VDMOSicVDSGiven) { here->VDMOSicVDS = 0; } @@ -409,10 +416,10 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, if (error) return(error); here->VDMOStcaseNode = tmp->number; } - if(here->VDMOSvcktTbranch == 0) { - error = CKTmkCur(ckt,&tmp,here->VDMOSname,"VcktTemp"); + if(here->VDMOSvdevTbranch == 0) { + error = CKTmkCur(ckt,&tmp,here->VDMOSname,"VdevTemp"); if(error) return(error); - here->VDMOSvcktTbranch = tmp->number; + here->VDMOSvdevTbranch = tmp->number; } if (here->VDMOStNodePrime == 0) { error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "cktTemp"); @@ -472,18 +479,18 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ TSTALLOC(VDMOSTempdPtr, VDMOStempNode, VDMOSdNode); TSTALLOC(VDIOPosPrimetempPtr, VDIOposPrimeNode, VDMOStempNode); TSTALLOC(VDMOSDtempPtr, VDMOSdNode, VDMOStempNode); - TSTALLOC(VDMOStempSPtr, VDMOStempNode, VDMOSsNode); - TSTALLOC(VDMOSSTempPtr, VDMOSsNode, VDMOStempNode); + TSTALLOC(VDMOSTempsPtr, VDMOStempNode, VDMOSsNode); + TSTALLOC(VDMOSStempPtr, VDMOSsNode, VDMOStempNode); TSTALLOC(VDMOSTcasetcasePtr, VDMOStcaseNode, VDMOStcaseNode); /* Rthjc between tj and tcase*/ TSTALLOC(VDMOSTcasetempPtr, VDMOStcaseNode, VDMOStempNode); TSTALLOC(VDMOSTemptcasePtr, VDMOStempNode, VDMOStcaseNode); TSTALLOC(VDMOSTptpPtr, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */ - TSTALLOC(VDMOSTptcasePtr, VDMOStNodePrime, VDMOStempNode); - TSTALLOC(VDMOSTcasetpPtr, VDMOStempNode, VDMOStNodePrime); - TSTALLOC(VDMOSCktTcktTPtr, VDMOSvcktTbranch, VDMOSvcktTbranch); /* Vsrc=cktTemp to gnd */ - TSTALLOC(VDMOSCktTtpPtr, VDMOSvcktTbranch, VDMOStNodePrime); - TSTALLOC(VDMOSTpcktTPtr, VDMOStNodePrime, VDMOSvcktTbranch); + TSTALLOC(VDMOSTptcasePtr, VDMOStNodePrime, VDMOStcaseNode); + TSTALLOC(VDMOSTcasetpPtr, VDMOStcaseNode, VDMOStNodePrime); + TSTALLOC(VDMOSDevTdevTPtr, VDMOSvdevTbranch, VDMOSvdevTbranch); /* Vsrc=cktTemp to gnd */ + TSTALLOC(VDMOSDevTtpPtr, VDMOSvdevTbranch, VDMOStNodePrime); + TSTALLOC(VDMOSTpdevTPtr, VDMOStNodePrime, VDMOSvdevTbranch); } } } @@ -526,9 +533,9 @@ VDMOSunsetup(GENmodel *inModel, CKTcircuit *ckt) if (here->VDMOStNodePrime > 0) CKTdltNNum(ckt, here->VDMOStNodePrime); here->VDMOStNodePrime = 0; - if (here->VDMOSvcktTbranch > 0) - CKTdltNNum(ckt, here->VDMOSvcktTbranch); - here->VDMOSvcktTbranch = 0; + if (here->VDMOSvdevTbranch > 0) + CKTdltNNum(ckt, here->VDMOSvdevTbranch); + here->VDMOSvdevTbranch = 0; } } diff --git a/src/spicelib/devices/vdmos/vdmostemp.c b/src/spicelib/devices/vdmos/vdmostemp.c index 53d92a548..202a4611a 100644 --- a/src/spicelib/devices/vdmos/vdmostemp.c +++ b/src/spicelib/devices/vdmos/vdmostemp.c @@ -56,9 +56,15 @@ void VDMOStempUpdate(VDMOSmodel *inModel, VDMOSinstance *here, double Temp, CKTc else here->VDMOSdrainResistance = model->VDMOSdrainResistance / here->VDMOSm * (1.0 + (model->VDMOStrd1 * dt) + (model->VDMOStrd2 * dt * dt)); - here->VDMOSgateConductance = here->VDMOSgateConductance / (1.0 + (model->VDMOStrg1 * dt) + (model->VDMOStrg2 * dt * dt)); + if (model->VDMOSgateResistance > 0) + here->VDMOSgateConductance = here->VDMOSm / model->VDMOSgateResistance / (1.0 + (model->VDMOStrg1 * dt) + (model->VDMOStrg2 * dt * dt)); + else + here->VDMOSgateConductance = 0.0; - here->VDMOSsourceConductance = here->VDMOSsourceConductance / (1.0 + (model->VDMOStrs1 * dt) + (model->VDMOStrs2 * dt * dt)); + if (model->VDMOSsourceResistance > 0) + here->VDMOSsourceConductance = here->VDMOSm / model->VDMOSsourceResistance / (1.0 + (model->VDMOStrs1 * dt) + (model->VDMOStrs2 * dt * dt)); + else + here->VDMOSsourceConductance = 0.0; if (model->VDMOSqsGiven) here->VDMOSqsResistance = model->VDMOSqsResistance / here->VDMOSm * pow(ratio, model->VDMOStexp1); diff --git a/src/spicelib/parser/inppas2.c b/src/spicelib/parser/inppas2.c index cd446f3c2..f569fe056 100644 --- a/src/spicelib/parser/inppas2.c +++ b/src/spicelib/parser/inppas2.c @@ -34,7 +34,7 @@ void INPpas2(CKTcircuit *ckt, struct card *data, INPtables * tab, TSKtask *task) char *groundname = "0"; char *gname; CKTnode *gnode; - int error; /* used by the macros defined above */ + int error; /* used by the macros defined above */ #ifdef HAS_PROGREP int linecount = 0, actcount = 0; #endif @@ -45,28 +45,28 @@ void INPpas2(CKTcircuit *ckt, struct card *data, INPtables * tab, TSKtask *task) #endif error = INPgetTok(&groundname, &gname, 1); - if (error) - data->error = - INPerrCat(data->error, - INPmkTemp - ("can't read internal ground node name!\n")); - + if (error) { + data->error = + INPerrCat(data->error, + INPmkTemp + ("can't read internal ground node name!\n")); + } error = INPgndInsert(ckt, &gname, tab, &gnode); - if (error && error != E_EXISTS) - data->error = - INPerrCat(data->error, - INPmkTemp - ("can't insert internal ground node in symbol table!\n")); - -#ifdef TRACE + if (error && error != E_EXISTS) { + data->error = + INPerrCat(data->error, + INPmkTemp + ("can't insert internal ground node in symbol table!\n")); + } + +#ifdef TRACE printf("Examining this deck:\n"); for (current = data; current != NULL; current = current->nextcard) { - printf("%s\n", current->line); + printf("%s\n", current->line); } printf("\n"); #endif - #ifdef HAS_PROGREP for (current = data; current != NULL; current = current->nextcard) linecount++; @@ -75,195 +75,195 @@ void INPpas2(CKTcircuit *ckt, struct card *data, INPtables * tab, TSKtask *task) for (current = data; current != NULL; current = current->nextcard) { #ifdef TRACE - /* SDB debug statement */ - printf("In INPpas2, examining card %s . . .\n", current->line); + /* SDB debug statement */ + printf("In INPpas2, examining card %s . . .\n", current->line); #endif #ifdef HAS_PROGREP - if (linecount > 0) { - SetAnalyse( "Parse", (int) (1000.*actcount/linecount)); - actcount++; - } + if (linecount > 0) { + SetAnalyse( "Parse", (int) (1000.*actcount/linecount)); + actcount++; + } #endif - Current_parse_line = current->linenum_orig; - Sourcefile = current->linesource; + Current_parse_line = current->linenum_orig; + Sourcefile = current->linesource; - c = *(current->line); - if(islower_c(c)) - c = toupper_c(c); + c = *(current->line); + if(islower_c(c)) + c = toupper_c(c); - switch (c) { + switch (c) { - case ' ': - /* blank line (space leading) */ - case '\t': - /* blank line (tab leading) */ - break; + case ' ': + /* blank line (space leading) */ + case '\t': + /* blank line (tab leading) */ + break; #ifdef XSPICE - /* gtri - add - wbk - 10/23/90 - add case for 'A' devices */ + /* gtri - add - wbk - 10/23/90 - add case for 'A' devices */ - case 'A': /* Aname */ - MIF_INP2A(ckt, tab, current); - ckt->CKTadevFlag = 1; /* an 'A' device is requested */ - break; + case 'A': /* Aname */ + MIF_INP2A(ckt, tab, current); + ckt->CKTadevFlag = 1; /* an 'A' device is requested */ + break; - /* gtri - end - wbk - 10/23/90 */ + /* gtri - end - wbk - 10/23/90 */ #endif - case 'R': - /* Rname [][][w=][l=] */ - INP2R(ckt, tab, current); - break; + case 'R': + /* Rname [][][w=][l=] */ + INP2R(ckt, tab, current); + break; - case 'C': - /* Cname [IC=] */ - INP2C(ckt, tab, current); - break; + case 'C': + /* Cname [IC=] */ + INP2C(ckt, tab, current); + break; - case 'L': - /* Lname [IC=] */ - INP2L(ckt, tab, current); - break; + case 'L': + /* Lname [IC=] */ + INP2L(ckt, tab, current); + break; - case 'G': - /* Gname */ - INP2G(ckt, tab, current); - break; + case 'G': + /* Gname */ + INP2G(ckt, tab, current); + break; - case 'E': - /* Ename */ - INP2E(ckt, tab, current); - break; + case 'E': + /* Ename */ + INP2E(ckt, tab, current); + break; - case 'F': - /* Fname */ - INP2F(ckt, tab, current); - break; + case 'F': + /* Fname */ + INP2F(ckt, tab, current); + break; - case 'H': - /* Hname */ - INP2H(ckt, tab, current); - break; + case 'H': + /* Hname */ + INP2H(ckt, tab, current); + break; - case 'D': - /* Dname [] [OFF] [IC=] */ - INP2D(ckt, tab, current); - break; + case 'D': + /* Dname [] [OFF] [IC=] */ + INP2D(ckt, tab, current); + break; - case 'J': - /* Jname [] [OFF] + case 'J': + /* Jname [] [OFF] + [IC=,] */ + INP2J(ckt, tab, current); + break; + + case 'Z': + /* Zname [] [OFF] [IC=,] */ - INP2J(ckt, tab, current); - break; + INP2Z(ckt, tab, current); + break; - case 'Z': - /* Zname [] [OFF] - [IC=,] */ - INP2Z(ckt, tab, current); - break; - - case 'M': - /* Mname [L=] - [W=] [AD=] [AS=] [PD=] - [PS=] [NRD=] [NRS=] [OFF] - [IC=,,] */ - INP2M(ckt, tab, current); - break; + case 'M': + /* Mname [L=] + [W=] [AD=] [AS=] [PD=] + [PS=] [NRD=] [NRS=] [OFF] + [IC=,,] */ + INP2M(ckt, tab, current); + break; #ifdef OSDI - case 'N': - /* Nname [...] [] */ - INP2N(ckt, tab, current); - break; + case 'N': + /* Nname [...] [] */ + INP2N(ckt, tab, current); + break; #endif - case 'O': - /* Oname - [IC=,,,] */ - INP2O(ckt, tab, current); - break; + case 'O': + /* Oname + [IC=,,,] */ + INP2O(ckt, tab, current); + break; - case 'V': - /* Vname [ [DC] ] [AC [ [ ] ] ] - [] */ - INP2V(ckt, tab, current); - break; + case 'V': + /* Vname [ [DC] ] [AC [ [ ] ] ] + [] */ + INP2V(ckt, tab, current); + break; - case 'I': - /* Iname [ [DC] ] [AC [ [ ] ] ] - [] */ - INP2I(ckt, tab, current); - break; + case 'I': + /* Iname [ [DC] ] [AC [ [ ] ] ] + [] */ + INP2I(ckt, tab, current); + break; - case 'Q': - /* Qname [] [] [OFF] - [IC=,] */ - INP2Q(ckt, tab, current, gnode); - break; + case 'Q': + /* Qname [] [] [OFF] + [IC=,] */ + INP2Q(ckt, tab, current, gnode); + break; - case 'T': - /* Tname [TD=] - [F= [NL=]][IC=,,,] */ - INP2T(ckt, tab, current); - break; + case 'T': + /* Tname [TD=] + [F= [NL=]][IC=,,,] */ + INP2T(ckt, tab, current); + break; - case 'S': - /* Sname [] [IC] */ - INP2S(ckt, tab, current); - break; + case 'S': + /* Sname [] [IC] */ + INP2S(ckt, tab, current); + break; - case 'W': - /* Wname [] [IC] */ - /* CURRENT CONTROLLED SWITCH */ - INP2W(ckt, tab, current); - break; + case 'W': + /* Wname [] [IC] */ + /* CURRENT CONTROLLED SWITCH */ + INP2W(ckt, tab, current); + break; - case 'U': - /* Uname [l=] [n=] */ - INP2U(ckt, tab, current); - break; + case 'U': + /* Uname [l=] [n=] */ + INP2U(ckt, tab, current); + break; - /* Kspice addition - saj */ - case 'P': - /* Pname ... ... [] */ - /* R= L= G= C= len= */ - INP2P(ckt, tab, current); - break; - case 'Y': - /* Yname R= L= G= C= len= */ - INP2Y(ckt, tab, current); - break; - /* end Kspice */ + /* Kspice addition - saj */ + case 'P': + /* Pname ... ... [] */ + /* R= L= G= C= len= */ + INP2P(ckt, tab, current); + break; + case 'Y': + /* Yname R= L= G= C= len= */ + INP2Y(ckt, tab, current); + break; + /* end Kspice */ - case 'K': - /* Kname Lname Lname */ - INP2K(ckt, tab, current); - break; + case 'K': + /* Kname Lname Lname */ + INP2K(ckt, tab, current); + break; - case '*': case '$': - /* * - a comment - ignore */ - break; + case '*': case '$': + /* * - a comment - ignore */ + break; - case 'B': - /* Bname [V=expr] [I=expr] */ - /* Arbitrary source. */ - INP2B(ckt, tab, current); - break; + case 'B': + /* Bname [V=expr] [I=expr] */ + /* Arbitrary source. */ + INP2B(ckt, tab, current); + break; - case '.': /* . Many possibilities */ - if (INP2dot(ckt,tab,current,task,gnode)) - return; - break; + case '.': /* . Many possibilities */ + if (INP2dot(ckt,tab,current,task,gnode)) + return; + break; - case '\0': - break; + case '\0': + break; - default: - /* the un-implemented device */ - LITERR(" unknown device type - error \n"); - break; - } - } + default: + /* the un-implemented device */ + LITERR(" unknown device type - error \n"); + break; + } + } return; } diff --git a/src/xspice/Makefile.am b/src/xspice/Makefile.am index 7359ac577..fe83489bb 100644 --- a/src/xspice/Makefile.am +++ b/src/xspice/Makefile.am @@ -9,7 +9,7 @@ EXTRA_DIST = README examples icm xspice.c .gitignore \ tlines/msline_common.c tlines/msline_common.h \ tlines/tline_common.c tlines/tline_common.h -SUBDIRS = mif cm enh evt ipc idn cmpp icm verilog vhdl +SUBDIRS = mif cm enh evt idn cmpp icm verilog vhdl dist-hook: rm -f "$(distdir)/icm/makedefs" diff --git a/src/xspice/evt/evtdump.c b/src/xspice/evt/evtdump.c index 2f1c6db61..40a73f083 100644 --- a/src/xspice/evt/evtdump.c +++ b/src/xspice/evt/evtdump.c @@ -53,10 +53,6 @@ NON-STANDARD FEATURES #include "ngspice/evtproto.h" #include "ngspice/evtudn.h" -#include "ngspice/ipc.h" -#include "ngspice/ipctiein.h" -#include "ngspice/ipcproto.h" - #ifdef SHARED_MODULE /* global flag, TRUE if callback is used */ extern bool wantevtdata; @@ -76,13 +72,6 @@ static void EVTsharedsend_line( int mode); /* mode (op, dc, tran) we are in */ #endif -static void EVTsend_line( - int ipc_index, /* The index used in the dictionary */ - double step, /* The analysis step */ - void *node_value, /* The node value */ - int udn_index); /* The user-defined node index */ - - /* EVTdump @@ -129,250 +118,25 @@ void EVTdump( double step) /* The sweep step for a DCTRCURVE analysis, or */ /* 0.0 for DCOP and TRAN */ { - static evtdump_dict_t *node_dict = NULL; - static int num_send_nodes; - - int i; - int j; - int num_nodes; - int num_modified; - int index; - - char *name; - int name_len; - - Mif_Boolean_t firstcall; - - Evt_Node_Data_t *node_data; - - Evt_Node_t *rhsold; - Evt_Node_t **head; - Evt_Node_t *here; - - Evt_Node_Info_t **node_table; - - char buff[10000]; - - Mif_Boolean_t equal; #ifdef SHARED_MODULE - if((! g_ipc.enabled) && (!wantevtdata)) + if (!wantevtdata) return; - if ((!g_ipc.enabled) && (wantevtdata)) { + else { EVTshareddump(ckt, mode, step); return; } #else - /* Return immediately if IPC is not enabled */ - if(! g_ipc.enabled) - return; + (void)*ckt; + (void)mode; + (void)step; + + /* Return immediately */ + return; #endif - /* Get number of event-driven nodes */ - num_nodes = ckt->evt->counts.num_nodes; - - /* Exit immediately if no event-driven nodes in circuit */ - if(num_nodes <= 0) - return; - - - /* Get pointers for fast access to event data */ - node_data = ckt->evt->data.node; - node_table = ckt->evt->info.node_table; - rhsold = node_data->rhsold; - head = node_data->head; - - - /* Determine if this is the first call */ - if(node_dict == NULL) - firstcall = MIF_TRUE; - else - firstcall = MIF_FALSE; - - - /* If this is the first call, get the dictionary info */ - if(firstcall) { - - /* Allocate local data structure used to process nodes */ - node_dict = TMALLOC(evtdump_dict_t, num_nodes); - - /* Loop through all nodes to determine which nodes should be sent. */ - /* Only nodes not within subcircuits qualify. */ - - num_send_nodes = 0; - for(i = 0; i < num_nodes; i++) { - - /* Get the name of the node. */ - name = node_table[i]->name; - - /* If name is in a subcircuit, mark that node should not be sent */ - /* and continue to next node. */ - name_len = (int) strlen(name); - for(j = 0; j < name_len; j++) { - if(name[j] == ':') - break; - } - if(j < name_len) { - node_dict[i].send = MIF_FALSE; - continue; - } - - /* Otherwise, fill in info in dictionary. */ - node_dict[i].send = MIF_TRUE; - node_dict[i].ipc_index = num_send_nodes; - node_dict[i].node_name_str = name; - node_dict[i].udn_type_str = g_evt_udn_info[node_table[i]->udn_index]->name; - - /* Increment the count of nodes to be sent. */ - num_send_nodes++; - } /* end for */ - } /* end if first call */ - - - /* Exit if there are no nodes to be sent */ - if(num_send_nodes <= 0) - return; - - - /* If this is the first call, send the dictionary */ - if(firstcall) { - ipc_send_evtdict_prefix(); - for(i = 0; i < num_nodes; i++) { - if(node_dict[i].send) { - sprintf(buff, "%d %s %s", node_dict[i].ipc_index, - node_dict[i].node_name_str, - node_dict[i].udn_type_str); - ipc_send_line(buff); - } - } - ipc_send_evtdict_suffix(); - } - - /* If this is the first call, send the operating point solution */ - /* and return. */ - if(firstcall) { - ipc_send_evtdata_prefix(); - for(i = 0; i < num_nodes; i++) { - if(node_dict[i].send) { - EVTsend_line(node_dict[i].ipc_index, - step, - rhsold[i].node_value, - node_table[i]->udn_index); - } - } - ipc_send_evtdata_suffix(); - return; - } - - /* Otherwise, this must be DCTRCURVE or TRAN mode and we need to */ - /* send only stuff that has changed since the last call. */ - /* The determination of what to send is modeled after code in */ - /* EVTop_save() for DCTRCURVE and EVTaccept() for TRAN. */ - - if(mode == IPC_ANAL_DCTRCURVE) { - /* Send data prefix */ - ipc_send_evtdata_prefix(); - /* Loop through event nodes */ - for(i = 0; i < num_nodes; i++) { - /* If dictionary indicates this node should be sent */ - if(node_dict[i].send) { - /* Locate end of node data */ - here = head[i]; - for(;;) { - if(here->next) - here = here->next; - else - break; - } - /* Compare entry at end of list to rhsold */ - g_evt_udn_info[node_table[i]->udn_index]->compare ( - rhsold[i].node_value, - here->node_value, - &equal); - /* If value in rhsold is different, send it */ - if(!equal) { - EVTsend_line(node_dict[i].ipc_index, - step, - rhsold[i].node_value, - node_table[i]->udn_index); - } - } - } - /* Send data suffix and return */ - ipc_send_evtdata_suffix(); - return; - } - - - if(mode == IPC_ANAL_TRAN) { - /* Send data prefix */ - ipc_send_evtdata_prefix(); - /* Loop through list of nodes modified since last time */ - num_modified = node_data->num_modified; - for(i = 0; i < num_modified; i++) { - /* Get the index of the node modified */ - index = node_data->modified_index[i]; - /* If dictionary indicates this node should be sent */ - if(node_dict[index].send) { - /* Scan through new events and send the data for each event */ - here = *(node_data->last_step[index]); - while((here = here->next) != NULL) { - EVTsend_line(node_dict[index].ipc_index, - here->step, - here->node_value, - node_table[index]->udn_index); - } - } - } - /* Send data suffix and return */ - ipc_send_evtdata_suffix(); - return; - } } - - -/* -EVTsend_line - -This function formats the event node data and sends it to the IPC channel. -*/ - - -static void EVTsend_line( - int ipc_index, /* The index used in the dictionary */ - double step, /* The analysis step */ - void *node_value, /* The node value */ - int udn_index) /* The user-defined node index */ -{ - double dvalue; - char *svalue; - void *pvalue; - int len; - - /* Get the data to send */ - if(g_evt_udn_info[udn_index]->plot_val) - g_evt_udn_info[udn_index]->plot_val (node_value, "", &dvalue); - else - dvalue = 0.0; - - if(g_evt_udn_info[udn_index]->print_val) - g_evt_udn_info[udn_index]->print_val (node_value, "", &svalue); - else - svalue = ""; - - if(g_evt_udn_info[udn_index]->ipc_val) - g_evt_udn_info[udn_index]->ipc_val (node_value, &pvalue, &len); - else { - pvalue = NULL; - len = 0; - } - - /* Send it to the IPC channel */ - ipc_send_event(ipc_index, step, dvalue, svalue, pvalue, len); -} - - #ifdef SHARED_MODULE static void EVTshareddump( CKTcircuit *ckt, /* The circuit structure */ diff --git a/src/xspice/ipc/Makefile.am b/src/xspice/ipc/Makefile.am deleted file mode 100644 index 40e4650c6..000000000 --- a/src/xspice/ipc/Makefile.am +++ /dev/null @@ -1,17 +0,0 @@ -## Process this file with automake to produce Makefile.in -# -# JW 3/9/01 - had a go and makeing an autoconf script. - -noinst_LTLIBRARIES = libipcxsp.la - -libipcxsp_la_SOURCES = \ - ipcaegis.c \ - ipc.c \ - ipcsockets.c \ - ipcstdio.c \ - ipctiein.c - -AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include -I$(top_srcdir)/src/spicelib/devices -AM_CFLAGS = $(STATIC) - -MAINTAINERCLEANFILES = Makefile.in diff --git a/src/xspice/ipc/ipc.c b/src/xspice/ipc/ipc.c deleted file mode 100644 index a689c051b..000000000 --- a/src/xspice/ipc/ipc.c +++ /dev/null @@ -1,978 +0,0 @@ -/*============================================================================ -FILE IPC.c - -MEMBER OF process XSPICE - -Public Domain - -Georgia Tech Research Corporation -Atlanta, Georgia 30332 -PROJECT A-8503 - -AUTHORS - - 9/12/91 Steve Tynor - -MODIFICATIONS - - 6/13/92 Bill Kuhn Added some comments - -SUMMARY - - Provides compatibility for the new SPICE simulator to both the MSPICE user - interface and BCP (via ATESSE v.1 style AEGIS mailboxes) and the new ATESSE - v.2 Simulator Interface and BCP (via Bsd Sockets). - - The Interprocess Communications package provides functions - called to receive XSPICE decks from the ATESSE Simulator Interface - or Batch Control processes, and to return results to those - processes. Functions callable from the simulator packages include: - - ipc_initialize_server - ipc_terminate_server - ipc_get_line - ipc_send_line - ipc_send_data_prefix - ipc_send_data_suffix - ipc_send_dcop_prefix - ipc_send_dcop_suffix - ipc_send_evtdict_prefix - ipc_send_evtdict_suffix - ipc_send_evtdata_prefix - ipc_send_evtdata_suffix - ipc_send_errchk - ipc_send_end - ipc_send_boolean - ipc_send_int - ipc_send_double - ipc_send_complex - ipc_send_event - ipc_flush - - These functions communicate with a set of transport-level functions - that implement the interprocess communications under one of - the following protocol types determined by a compile-time option: - - BSD UNIX Sockets - HP/Apollo Mailboxes - - For each transport protocol, the following functions are written: - - ipc_transport_initialize_server - ipc_transport_get_line - ipc_transport_terminate_server - ipc_transport_send_line - - - -============================================================================*/ - -#include "ngspice/ngspice.h" - -#include -#include "ngspice/memory.h" /* NOTE: I think this is a Sys5ism (there is not man - * page for it under Bsd, but it's in /usr/include - * and it has a BSD copyright header. Go figure. - */ - -#include "ngspice/ipc.h" -#include "ngspice/ipctiein.h" -#include "ngspice/ipcproto.h" - - -/* - * Conditional compilation sanity check: - */ -#if !defined (IPC_AEGIS_MAILBOXES) && !defined (IPC_UNIX_SOCKETS)\ - && !defined (IPC_DEBUG_VIA_STDIO) -" compiler error - must specify a transport mechanism"; -#endif - -/* - * static 'globals' - */ - -/* typedef unsigned char Buffer_Char_t; */ -typedef char Buffer_Char_t; - -#define OUT_BUFFER_SIZE 1000 -#define MAX_NUM_RECORDS 200 -static int end_of_record_index [MAX_NUM_RECORDS]; -static int num_records; -static Buffer_Char_t out_buffer [OUT_BUFFER_SIZE]; -static int fill_count; - -static Ipc_Mode_t mode; -static Ipc_Protocol_t protocol; -static Ipc_Boolean_t end_of_deck_seen; -static int batch_fd; - -#define FMT_BUFFER_SIZE 80 -static char fmt_buffer [FMT_BUFFER_SIZE]; - -/*---------------------------------------------------------------------------*/ -Ipc_Boolean_t -kw_match (char *keyword, char *str) - /* - * returns IPC_TRUE if the first `strlen(keyword)' characters of `str' match - * the ones in `keyword' - case sensitive - */ -{ - char *k = keyword; - char *s = str; - - /* - * quit if we run off the end of either string: - */ - while (*s && *k) { - if (*s != *k) { - return IPC_FALSE; - } - s++; - k++; - } - /* - * if we get this far, it sould be because we ran off the end of the - * keyword else we didn't match: - */ - return (*k == '\0'); -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_initialize_server - -This function creates the interprocess communication channel -server mailbox or socket. -*/ - - -Ipc_Status_t -ipc_initialize_server ( - char *server_name, /* Mailbox path or host/portnumber pair */ - Ipc_Mode_t m, /* Interactive or batch */ - Ipc_Protocol_t p ) /* Type of IPC protocol */ - /* - * For mailboxes, `server_name' would be the mailbox pathname; for - * sockets, this needs to be a host/portnumber pair. Maybe this should be - * automatically generated by the routine... - */ -{ - Ipc_Status_t status; - char batch_filename [1025]; - - mode = m; - protocol = p; - end_of_deck_seen = IPC_FALSE; - - num_records = 0; - fill_count = 0; - - status = ipc_transport_initialize_server (server_name, m, p, - batch_filename); - - if (status != IPC_STATUS_OK) { - fprintf (stderr, "ERROR: IPC: error initializing server\n"); - return IPC_STATUS_ERROR; - } - - if (mode == IPC_MODE_BATCH) { -#ifdef IPC_AEGIS_MAILBOXES - strcat (batch_filename, ".log"); -#endif - batch_fd = open (batch_filename, O_WRONLY | O_CREAT, 0666); - if (batch_fd < 0) { - /* fprintf (stderr, "ERROR: IPC: Error opening batch output file: %s\n",batch_filename); */ - perror ("IPC"); - return IPC_STATUS_ERROR; - } - } - return status; -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_terminate_server - -This function deallocates the interprocess communication channel -mailbox or socket. -*/ - - - -Ipc_Status_t -ipc_terminate_server (void) -{ - return ipc_transport_terminate_server (); -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_get_line - -This function gets a SPICE deck input line from the interprocess -communication channel. Any special control commands in the deck -beginning with a ``>'' or ``#'' character are processed internally by -this function and not returned to SPICE. -*/ - -Ipc_Status_t -ipc_get_line ( - char *str, /* Text retrieved from IPC channel */ - int *len, /* Length of text string */ - Ipc_Wait_t wait ) /* Select blocking or non-blocking */ - /* - * Reads one SPICE line from the connection. Strips any control lines - * which cannot be interpretted by the simulator (e.g. >INQCON) and - * processes them. If such a line is read, it is processed and the next - * line is read. `ipc_get_line' does not return until a non-interceptable - * line is read or end of file. - * - * If `wait' is IPC_NO_WAIT and there is no data available on the - * connection, `ipc_get_line' returns IPC_STATUS_NO_DATA. If `wait' is - * IPC_WAIT, `ipc_get_line' will not return until there is data available - * or and end of file condition is reached or an error occurs. - * - * Intercepts and processes the following commands: - * #RETURNI, #MINTIME, #VTRANS, - * >PAUSE, >CONT, >STOP, >INQCON, >NETLIST, >ENDNET - * Other > records are silently ignored. - * - * Intercepts old-style .TEMP card generated by MSPICE - * - * Returns: - * IPC_STATUS_OK - for successful reads - * IPC_STATUS_NO_DATA - when NO_WAIT and no data available - * IPC_STATUS_END_OF_DECK - at end of deck (>ENDNET seen) - * IPC_STATUS_ERROR - otherwise - */ -{ - Ipc_Status_t status; - Ipc_Boolean_t need_another = IPC_TRUE; - - do { - - status = ipc_transport_get_line (str, len, wait); - - switch (status) { - case IPC_STATUS_NO_DATA: - case IPC_STATUS_ERROR: - need_another = IPC_FALSE; - break; - case IPC_STATUS_END_OF_DECK: - assert (0); /* should never get this from the low-level get-line */ - status = IPC_STATUS_ERROR; - need_another = IPC_FALSE; - break; - case IPC_STATUS_OK: - /* - * Got a good line - check to see if it's one of the ones we need to - * intercept - */ - if (str[0] == '>') { - if (kw_match (">STOP", str)) { - ipc_handle_stop(); - } else if (kw_match (">PAUSE", str)) { - /* assert (need_another); */ - /* - * once more around the loop to do a blocking wait for the >CONT - */ - need_another = IPC_TRUE; - wait = IPC_WAIT; - } else if (kw_match (">INQCON", str)) { - ipc_send_line (">ABRTABL"); - ipc_send_line (">PAUSABL"); - ipc_send_line (">KEEPABL"); - status = ipc_flush (); - if (IPC_STATUS_OK != status) { - need_another = IPC_FALSE; - } - } else if (kw_match (">ENDNET", str)) { - end_of_deck_seen = IPC_TRUE; - need_another = IPC_FALSE; - status = IPC_STATUS_END_OF_DECK; - } else { - /* silently ignore */ - } - } else if (str[0] == '#') { - if (kw_match ("#RETURNI", str)) { - ipc_handle_returni (); - } else if (kw_match ("#MINTIME", str)) { - double d1/*,d2*/; - if (1 != sscanf (&str[8], "%lg", &d1)) { - status = IPC_STATUS_ERROR; - need_another = IPC_FALSE; - } else { - ipc_handle_mintime (d1); - } - } else if (kw_match ("#VTRANS", str)) { - char *tok1; - char *tok2; - char *tok3; - - tok1 = &str[8]; - for (tok2 = tok1; *tok2; tok2++) { - if (isspace_c(*tok2)) { - *tok2 = '\0'; - tok2++; - break; - } - } - for(tok3 = tok2; *tok3; tok3++) { - if(isspace_c(*tok3)) { - *tok3 = '\0'; - break; - } - } - ipc_handle_vtrans (tok1, tok2); - } else { - /* silently ignore */ - } - } else if (str[0] == '.') { - if (kw_match (".TEMP", str)) { - /* don't pass .TEMP card to caller */ - printf("Old-style .TEMP card found - ignored\n"); - } - else { - /* pass all other . cards to the caller */ - need_another = IPC_FALSE; - } - } else { - /* - * Not a '>' or '#' record - let the caller deal with it - */ - need_another = IPC_FALSE; - } - break; - default: - /* - * some unknown status value! - */ - assert (0); - status = IPC_STATUS_ERROR; - need_another = IPC_FALSE; - break; - } - } while (need_another); - - return status; -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_flush - -This function flushes the interprocess communication channel -buffer contents. -*/ - -Ipc_Status_t -ipc_flush (void) - /* - * Flush all buffered messages out the connection. - */ -{ - Ipc_Status_t status; - int last = 0; - /*int bytes;*/ - int i; - - /* if batch mode */ - if (mode == IPC_MODE_BATCH) { - - assert (batch_fd >= 0); - - /* for number of records in buffer */ - for (i = 0; i < num_records; i++) { - - /* write the records to the .log file */ - if ((end_of_record_index [i] - last) != - write (batch_fd, &out_buffer[last], (size_t) (end_of_record_index [i] - last))) { - /* fprintf (stderr,"ERROR: IPC: Error writing to batch output file\n"); */ - perror ("IPC"); - return IPC_STATUS_ERROR; - } - - /* If the record is one of the batch simulation status messages, */ - /* send it over the ipc channel too */ - if( kw_match("#ERRCHK", &out_buffer[last]) || - kw_match(">ENDANAL", &out_buffer[last]) || - kw_match(">ABORTED", &out_buffer[last]) ) { - - status = ipc_transport_send_line (&out_buffer[last], - end_of_record_index [i] - last); - if (IPC_STATUS_OK != status) { - return status; - } - } - last = end_of_record_index [i]; - } - - /* else, must be interactive mode */ - } else { - /* send the full buffer over the ipc channel */ - status = ipc_transport_send_line (&out_buffer[0], - end_of_record_index [num_records - 1]); - if (IPC_STATUS_OK != status) { - return status; - } - } - - /* reset counts to zero and return */ - num_records = 0; - fill_count = 0; - return IPC_STATUS_OK; -} - -/*---------------------------------------------------------------------------*/ -Ipc_Status_t -ipc_send_line_binary ( - char *str, - int len ) - /* - * Same as `ipc_send_line' except does not expect the str to be null - * terminated. Sends exactly `len' characters. Use this for binary data - * strings that may have embedded nulls. - * - * Modified by wbk to append newlines for compatibility with - * ATESSE 1.0 - * - */ -{ - int length = len + 1; - /*int diff;*/ - Ipc_Status_t status; - - /* - * If we can't add the whole str to the buffer, or if there are no more - * record indices free, flush the buffer: - */ - if (((fill_count + length) >= OUT_BUFFER_SIZE) || - (num_records >= MAX_NUM_RECORDS)) { - status = ipc_flush (); - if (IPC_STATUS_OK != status) { - return status; - } - } - - /* - * make sure that the str will fit: - */ - if (length + fill_count > OUT_BUFFER_SIZE) { - /* fprintf (stderr,"ERROR: IPC: String too long to fit in output buffer (> %d bytes) - truncated\n",OUT_BUFFER_SIZE); */ - length = OUT_BUFFER_SIZE - fill_count; - } - - /* - * finally, concatenate the str to the end of the buffer and add the newline: - */ - memcpy (&out_buffer[fill_count], str, (size_t) len); - fill_count += len; - - out_buffer[fill_count] = '\n'; - fill_count++; - - end_of_record_index [num_records++] = fill_count; - - return IPC_STATUS_OK; -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_line - -This function sends a line of text over the interprocess -communication channel. -*/ - - -Ipc_Status_t -ipc_send_line (char *str ) /* The text to send */ -{ - int len; - int send_len; - - char *s; - - Ipc_Status_t status= IPC_STATUS_OK; - - - len = (int) strlen(str); - - /* if short string, send it immediately */ - if(len < 80) - status = ipc_send_line_binary (str, len); - else { - /* otherwise, we have to send it as multiple strings */ - /* because Mspice cannot handle things longer than 80 chars */ - s = str; - while(len > 0) { - if(len < 80) - send_len = len; - else - send_len = 79; - status = ipc_send_line_binary (str, send_len); - if(status != IPC_STATUS_OK) - break; - s += send_len; - len -= send_len; - } - } - - return(status); -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_data_prefix - -This function sends a ``>DATAB'' line over the interprocess -communication channel to signal that this is the beginning of a -results dump for the current analysis point. -*/ - -Ipc_Status_t -ipc_send_data_prefix (double time ) /* The analysis point for this data set */ -{ - char buffer[40]; - - sprintf (buffer, ">DATAB %.5E", time); - return ipc_send_line (buffer); -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_data_suffix - -This function sends a ``>ENDDATA'' line over the interprocess -communication channel to signal that this is the end of a results -dump from a particular analysis point. -*/ - - -Ipc_Status_t -ipc_send_data_suffix (void) -{ - Ipc_Status_t status; - - status = ipc_send_line (">ENDDATA"); - - if(status != IPC_STATUS_OK) - return(status); - - return(ipc_flush()); -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_dcop_prefix - -This function sends a ``>DCOPB'' line over the interprocess -communication channel to signal that this is the beginning of a -results dump from a DC operating point analysis. -*/ - -Ipc_Status_t -ipc_send_dcop_prefix (void) -{ - return ipc_send_line (">DCOPB"); -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_dcop_suffix - -This function sends a ``>ENDDATA'' line over the interprocess -communication channel to signal that this is the end of a results -dump from a particular analysis point. -*/ - - -Ipc_Status_t -ipc_send_dcop_suffix (void) -{ - Ipc_Status_t status; - - status = ipc_send_line (">ENDDCOP"); - - if(status != IPC_STATUS_OK) - return(status); - - return(ipc_flush()); -} - - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_evtdict_prefix - -This function sends a ``>EVTDICT'' line over the interprocess -communication channel to signal that this is the beginning of an -event-driven node dictionary. - -The line is sent only if the IPC is configured -for UNIX sockets, indicating use with the V2 ATESSE SI process. -*/ - -Ipc_Status_t -ipc_send_evtdict_prefix (void) -{ -#ifdef IPC_AEGIS_MAILBOXES - return IPC_STATUS_OK; -#else - return ipc_send_line (">EVTDICT"); -#endif -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_evtdict_suffix - -This function sends a ``>ENDDICT'' line over the interprocess -communication channel to signal that this is the end of an -event-driven node dictionary. - -The line is sent only if the IPC is configured -for UNIX sockets, indicating use with the V2 ATESSE SI process. -*/ - - -Ipc_Status_t -ipc_send_evtdict_suffix (void) -{ -#ifdef IPC_AEGIS_MAILBOXES - return IPC_STATUS_OK; -#else - Ipc_Status_t status; - - status = ipc_send_line (">ENDDICT"); - - if(status != IPC_STATUS_OK) - return(status); - - return(ipc_flush()); -#endif -} - - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_evtdata_prefix - -This function sends a ``>EVTDATA'' line over the interprocess -communication channel to signal that this is the beginning of an -event-driven node data block. - -The line is sent only if the IPC is configured -for UNIX sockets, indicating use with the V2 ATESSE SI process. -*/ - -Ipc_Status_t -ipc_send_evtdata_prefix (void) -{ -#ifdef IPC_AEGIS_MAILBOXES - return IPC_STATUS_OK; -#else - return ipc_send_line (">EVTDATA"); -#endif -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_evtdata_suffix - -This function sends a ``>ENDDATA'' line over the interprocess -communication channel to signal that this is the end of an -event-driven node data block. - -The line is sent only if the IPC is configured -for UNIX sockets, indicating use with the V2 ATESSE SI process. -*/ - - -Ipc_Status_t -ipc_send_evtdata_suffix (void) -{ -#ifdef IPC_AEGIS_MAILBOXES - return IPC_STATUS_OK; -#else - Ipc_Status_t status; - - status = ipc_send_line (">ENDDATA"); - - if(status != IPC_STATUS_OK) - return(status); - - return(ipc_flush()); -#endif -} - - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_errchk - -This function sends a ``\ERRCHK [GO|NOGO]'' message over the -interprocess communication channel to signal that the initial -parsing of the input deck has been completed and to indicate -whether or not errors were detected. -*/ - - -Ipc_Status_t -ipc_send_errchk(void) -{ - char str[IPC_MAX_LINE_LEN+1]; - Ipc_Status_t status; - - if(g_ipc.errchk_sent) - return(IPC_STATUS_OK); - - if(g_ipc.syntax_error) - sprintf(str, "#ERRCHK NOGO"); - else - sprintf(str, "#ERRCHK GO"); - - g_ipc.errchk_sent = IPC_TRUE; - - status = ipc_send_line(str); - if(status != IPC_STATUS_OK) - return(status); - - return(ipc_flush()); -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_end - -This function sends either an ``>ENDANAL'' or an ``>ABORTED'' message -over the interprocess communication channel together with the -total CPU time used to indicate whether or not the simulation -completed normally. -*/ - - -Ipc_Status_t -ipc_send_end(void) -{ - char str[IPC_MAX_LINE_LEN+1]; - Ipc_Status_t status; - - if(g_ipc.syntax_error || g_ipc.run_error) - sprintf(str, ">ABORTED %.4f", g_ipc.cpu_time); - else - sprintf(str, ">ENDANAL %.4f", g_ipc.cpu_time); - - status = ipc_send_line(str); - if(status != IPC_STATUS_OK) - return(status); - - return(ipc_flush()); -} - - -/*---------------------------------------------------------------------------*/ -int -stuff_binary_v1 ( - double d1, double d2, /* doubles to be stuffed */ - int n, /* how many of d1, d2 ( 1 <= n <= 2 ) */ - char *buf, /* buffer to stuff to */ - int pos ) /* index at which to stuff */ -{ - union { - float float_val[2]; - char ch[32]; - } trick; - int i, j; - - assert (protocol == IPC_PROTOCOL_V1); - assert (sizeof(float) == 4); - assert (sizeof(char) == 1); - assert ((n >= 1) && (n <= 2)); - - trick.float_val[0] = (float)d1; - if (n > 1) { - trick.float_val[1] = (float)d2; - } - for (i = 0, j = pos; i < n * (int) sizeof(float); j++, i++) - buf[j] = trick.ch[i]; - buf[0] = (char) ('A' + j - 1); - return j; -} - -/*---------------------------------------------------------------------------*/ - - -/* -ipc_send_double - -This function sends a double data value over the interprocess -communication channel preceded by a character string that -identifies the simulation variable. -*/ - -Ipc_Status_t -ipc_send_double ( - char *tag, /* The node or instance */ - double value ) /* The data value to send */ -{ - int len = 0; - - switch (protocol) { - case IPC_PROTOCOL_V1: - strcpy (fmt_buffer, " "); /* save room for the length byte */ - strcat (fmt_buffer, tag); - strcat (fmt_buffer, " "); - - /* If talking to Mentor tools, must force upper case for Mspice 7.0 */ - strtoupper(fmt_buffer); - - len = stuff_binary_v1 (value, 0.0, 1, fmt_buffer, (int) strlen(fmt_buffer)); - break; - case IPC_PROTOCOL_V2: - break; - } - return ipc_send_line_binary (fmt_buffer, len); -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_complex - -This function sends a complex data value over the interprocess -communication channel preceded by a character string that -identifies the simulation variable. -*/ - - -Ipc_Status_t -ipc_send_complex ( - char *tag, /* The node or instance */ - Ipc_Complex_t value ) /* The data value to send */ -{ - int len=0; - - switch (protocol) { - case IPC_PROTOCOL_V1: - strcpy (fmt_buffer, " "); /* save room for the length byte */ - strcat (fmt_buffer, tag); - strcat (fmt_buffer, " "); - - /* If talking to Mentor tools, must force upper case for Mspice 7.0 */ - strtoupper(fmt_buffer); - - len = stuff_binary_v1 (value.real, value.imag, 2, fmt_buffer, - (int) strlen(fmt_buffer)); - break; - case IPC_PROTOCOL_V2: - break; - } - return ipc_send_line_binary (fmt_buffer, len); -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_send_event - -This function sends data from an event-driven node over the interprocess -communication channel. The data is sent only if the IPC is configured -for UNIX sockets, indicating use with the V2 ATESSE SI process. -*/ - - -Ipc_Status_t -ipc_send_event ( - int ipc_index, /* Index used in EVTDICT */ - double step, /* Analysis point or timestep (0.0 for DC) */ - double plot_val, /* The value for plotting purposes */ - char *print_val, /* The value for printing purposes */ - void *ipc_val, /* The binary representation of the node data */ - int len ) /* The length of the binary representation */ -{ -#ifdef IPC_AEGIS_MAILBOXES - return IPC_STATUS_OK; -#else - char buff[OUT_BUFFER_SIZE]; - int i; - int buff_len; - char *buff_ptr; - char *temp_ptr; - float fvalue; - - /* Report error if size of data is too big for IPC channel block size */ - if((len + (int) strlen(print_val) + 100) >= OUT_BUFFER_SIZE) { - printf("ERROR - Size of event-driven data too large for IPC channel\n"); - return IPC_STATUS_ERROR; - } - - /* Place the index into the buffer with a trailing space */ - sprintf(buff, "%d ", ipc_index); - - assert(sizeof(float) == 4); - assert(sizeof(int) == 4); - - /* Put the analysis step bytes in */ - buff_len = (int) strlen(buff); - buff_ptr = buff + buff_len; - fvalue = (float)step; - temp_ptr = (char *) &fvalue; - for(i = 0; i < 4; i++) { - *buff_ptr = temp_ptr[i]; - buff_ptr++; - buff_len++; - } - - /* Put the plot value in */ - fvalue = (float)plot_val; - temp_ptr = (char *) &fvalue; - for(i = 0; i < 4; i++) { - *buff_ptr = temp_ptr[i]; - buff_ptr++; - buff_len++; - } - - /* Put the length of the binary representation in */ - temp_ptr = (char *) &len; - for(i = 0; i < 4; i++) { - *buff_ptr = temp_ptr[i]; - buff_ptr++; - buff_len++; - } - - /* Put the binary representation bytes in last */ - temp_ptr = (char*) ipc_val; - for(i = 0; i < len; i++) - buff_ptr[i] = temp_ptr[i]; - buff_ptr += len; - buff_len += len; - - /* Put the print value in */ - strcpy(buff_ptr, print_val); - buff_ptr += strlen(print_val); - buff_len += (int) strlen(print_val); - - /* Send the data to the IPC channel */ - return ipc_send_line_binary(buff, buff_len); - -#endif -} - - diff --git a/src/xspice/ipc/ipcaegis.c b/src/xspice/ipc/ipcaegis.c deleted file mode 100644 index 2254ee460..000000000 --- a/src/xspice/ipc/ipcaegis.c +++ /dev/null @@ -1,309 +0,0 @@ -/*============================================================================ -FILE IPCaegis.c - -MEMBER OF process XSPICE - -Public Domain - -Georgia Tech Research Corporation -Atlanta, Georgia 30332 -PROJECT A-8503 - -AUTHORS - - 9/12/91 Steve Tynor - -MODIFICATIONS - - - -SUMMARY - - Provides compatibility for the new XSPICE simulator to both the MSPICE user - interface and BCP via ATESSE v.1 style AEGIS mailboxes. - -INTERFACES - - -REFERENCED FILES - - None. - -NON-STANDARD FEATURES - - None. - -============================================================================*/ - -#ifdef IPC_AEGIS_MAILBOXES - -#include -#include -#include -#include -#include "ngspice/memory.h" - -#include "ngspice/ipc.h" - - -typedef unsigned char Buffer_char_t; - -static status_$t status; -typedef enum { - IPC_MBX_UNINITIALIZED, - IPC_MBX_INITIALIZED, - IPC_MBX_CONNECTED_TO_CLIENT, -} Ipc_Mbx_State_t; - -static void *mbx_handle; -static Ipc_Mbx_State_t mbx_state = IPC_MBX_UNINITIALIZED; -static mbx_$server_msg_t mbx_send_msg_buf; -static mbx_$server_msg_t mbx_recieve_msg_buf; -static mbx_$server_msg_t *mbx_ret_ptr; -static int mbx_ret_len; -static short mbx_chan; - -#include "ngspice/ipcproto.h" - -/*---------------------------------------------------------------------------*/ - -/* -ipc_transport_initialize_server - -This function creates an Aegis mailbox, and if successful, -calls ipc_get_line to wait for the first record sent which is -assumed to be the batch output filename. -*/ - - - -Ipc_Status_t ipc_transport_initialize_server (server_name, m, p, - batch_filename) - char *server_name; /* The mailbox pathname */ - Ipc_Mode_t m; /* Mode - interactive or batch */ - Ipc_Protocol_t p; /* Protocol type */ - char *batch_filename; /* Batch filename returned */ -{ - int len; -/* extern void *malloc(); */ - - assert (p == IPC_PROTOCOL_V1); - - mbx_$create_server (server_name, strlen (server_name), mbx_$serv_msg_max, - 1, &mbx_handle, &status); - - if (status.all != status_$ok) { - fprintf (stderr, - "ERROR: IPC: Error creating mailbox server \"%s\"\n", - server_name); - error_$print (status); - mbx_state = IPC_MBX_UNINITIALIZED; - return IPC_STATUS_ERROR; - } else { - mbx_state = IPC_MBX_INITIALIZED; - /* - * First record is the name of the batch filename - whether we're in - * batch mode or not: - */ - return ipc_get_line (batch_filename, &len, IPC_WAIT); - } - /* - * shouldn't get here - */ - assert (0); - return IPC_STATUS_ERROR; -} -/*---------------------------------------------------------------------------*/ -Ipc_Status_t extract_msg (str, len) - char *str; - int *len; -{ - *len = mbx_ret_len - mbx_$serv_msg_hdr_len; - assert (*len >= 0); - - /* - * null terminate before copy: - */ - mbx_ret_ptr->data [*len] = '\0'; - strcpy (str, mbx_ret_ptr->data); - - return IPC_STATUS_OK; -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_transport_get_line - -This function reads data sent by a client over the mailbox -channel. It also handles the initial opening of the -mailbox channel when requested by a client. -*/ - - - -Ipc_Status_t ipc_transport_get_line (str, len, wait) - char *str; /* The string text read from IPC channel */ - int *len; /* The length of str */ - Ipc_Wait_t wait; /* Blocking or non-blocking */ -{ - if (mbx_state == IPC_MBX_UNINITIALIZED) { - fprintf (stderr, - "ERROR: IPC: Attempted to read from non-initialized mailbox\n"); - return IPC_STATUS_ERROR; - } - - assert ((mbx_state == IPC_MBX_CONNECTED_TO_CLIENT) || - (mbx_state == IPC_MBX_INITIALIZED)); - - for (;;) { - if (wait == IPC_WAIT) { - mbx_$get_rec (mbx_handle, &mbx_recieve_msg_buf, mbx_$serv_msg_max, - &mbx_ret_ptr, &mbx_ret_len, &status); - } else { - mbx_$get_conditional (mbx_handle, &mbx_recieve_msg_buf, - mbx_$serv_msg_max, &mbx_ret_ptr, &mbx_ret_len, - &status); - if (status.all == mbx_$channel_empty) { - return IPC_STATUS_NO_DATA; - } - } - - if (status.all != status_$ok) { - fprintf (stderr, "ERROR: IPC: Error reading from mailbox\n"); - error_$print (status); - return IPC_STATUS_ERROR; - } - - switch (mbx_ret_ptr->mt) { - case mbx_$channel_open_mt: - if (mbx_state == IPC_MBX_CONNECTED_TO_CLIENT) { - /* - * we're already connected to a client... refuse the connection - */ - mbx_send_msg_buf.mt = mbx_$reject_open_mt; - } else { - mbx_send_msg_buf.mt = mbx_$accept_open_mt; - mbx_state = IPC_MBX_CONNECTED_TO_CLIENT; - } - mbx_send_msg_buf.cnt = mbx_$serv_msg_hdr_len; - mbx_chan = mbx_ret_ptr->chan; - mbx_send_msg_buf.chan = mbx_chan; - - mbx_$put_rec (mbx_handle, &mbx_send_msg_buf, mbx_$serv_msg_hdr_len, - &status); - - if (status.all != status_$ok) { - fprintf (stderr, "ERROR: IPC: Error writing to mailbox\n"); - error_$print (status); - return IPC_STATUS_ERROR; - } - - /* - * check to see if there was a message buried in the open request: - */ - if (mbx_ret_len > mbx_$serv_msg_hdr_len) { - return extract_msg (str, len); - } - break; - case mbx_$eof_mt: - mbx_chan = mbx_ret_ptr->chan; - mbx_$deallocate(mbx_handle, mbx_chan, &status); - - if (status.all != status_$ok) { - fprintf (stderr, "ERROR: IPC: Error deallocating mailbox\n"); - error_$print (status); - return IPC_STATUS_ERROR; - } - - mbx_state = IPC_MBX_INITIALIZED; - return IPC_STATUS_EOF; - break; - case mbx_$data_mt: - assert (mbx_state == IPC_MBX_CONNECTED_TO_CLIENT); - return extract_msg (str, len); - break; - case mbx_$data_partial_mt: - fprintf (stderr, "ERROR: IPC: Recieved partial data message - ignored\n"); - break; - default: - fprintf (stderr, "ERROR: IPC: Bad message type (0x%x) recieved\n", - mbx_ret_ptr->mt); - } - } - return IPC_STATUS_ERROR; -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_transport_terminate_server - -This function calls ipc\_transport\_get\_line until it -receives an EOF from the client, which concludes the -communication. -*/ - - -Ipc_Status_t ipc_transport_terminate_server () -{ - char buffer[300]; - int len; - Ipc_Status_t status; - - do { - status = ipc_transport_get_line (buffer, &len, IPC_WAIT); - } while ((status != IPC_STATUS_ERROR) && - (status != IPC_STATUS_EOF)); - return status; -} - -/*---------------------------------------------------------------------------*/ - -/* -ipc_transport_send_line - -This function sends a message to the current client through -the mailbox channel. -*/ - - -Ipc_Status_t ipc_transport_send_line (str, len) - char *str; /* The bytes to send */ - int len; /* The number of bytes from str to send */ -{ - long cnt; - - if (mbx_state != IPC_MBX_CONNECTED_TO_CLIENT) { - fprintf (stderr, - "ERROR: IPC: Attempted to write to non-open mailbox\n"); - return IPC_STATUS_ERROR; - } - - mbx_send_msg_buf.mt = mbx_$data_mt; - if (mbx_$serv_msg_hdr_len + len > mbx_$serv_msg_max) { - fprintf (stderr, - "ERROR: IPC: send_line message too long - truncating\n"); - len = mbx_$serv_msg_max - mbx_$serv_msg_hdr_len; - } - - mbx_send_msg_buf.cnt = mbx_$serv_msg_hdr_len + len; - mbx_send_msg_buf.chan = mbx_chan; - memcpy (mbx_send_msg_buf.data, str, len); - - cnt = mbx_send_msg_buf.cnt; - mbx_$put_rec (mbx_handle, &mbx_send_msg_buf, cnt, &status); - - if (status.all != status_$ok) { - fprintf (stderr, "ERROR: IPC: Error writing to mailbox\n"); - error_$print (status); - return IPC_STATUS_ERROR; - } - return IPC_STATUS_OK; -} - -#else - -int intDummy1; - -#endif /* IPC_AEGIS_MAILBOXES */ diff --git a/src/xspice/ipc/ipcsockets.c b/src/xspice/ipc/ipcsockets.c deleted file mode 100644 index 54f6303c7..000000000 --- a/src/xspice/ipc/ipcsockets.c +++ /dev/null @@ -1,756 +0,0 @@ -/*============================================================================= - - FILE IPCsockets.c - -Public Domain - -Georgia Tech Research Corporation -Atlanta, Georgia 30332 -PROJECT A-8503 - - AUTHOR - Stefan Roth July 1991 - - MODIFICATIONS - none - - SUMMARY - Generic Interprocess Communication module - Provides compatibility for the new SPICE simulator to both the MSPICE user - interface and BCP (via ATESSE v.1 style AEGIS mailboxes) and the new ATESSE - v.2 Simulator Interface and BCP (via BSD Sockets). This file contains the - BSD sockets version. - The Simulator is the server, while the SI and BCP will be the clients. - - - INTERFACES - - FILE ROUTINE CALLED - - IPC.c ipc_get_line(); - - - REFERENCED FILES - - Outputs to stderr. - - -=============================================================================*/ - - -/*============================================================================= - - DESCRIPTION OF FUNCTIONALITY: - - Outline of Initialize_Server function: - create socket; - bind name to socket; - getsockname; - listen; - sock_state = IPC_SOCK_INITIALIZED; - return ipc_get_line (); - - - Format of a message line: - bytes description - ----- ------------------- - 0 recognition character for beginning of line; value is BOL_CHAR. - 1-4 message length (not including bytes 0-4); 32 bits in htonl - format; - if value = -1, then EOF and socket should be closed. - 5-N+5 message body of length specified in bytes 1-4. - - The bytes before the message body are the message header. The header - length is specified as SOCK_MSG_HDR_LEN bytes. - - - Outline of Get_Line function: - read 5 characters; - verify that first char is BOL_CHAR; - interpret message length (N) from bytes 1-4; - do error checking on message header bytes; - read N characters as message body; - do error checking on message body read; - - - Outline of Send_Line function: - write BOL_CHAR; - write 4-byte message body length - write message body (N bytes) - do error checking after each write operation - - - Outline of Terminate_Server function: - Continue to read lines (with ipc_transport_get_line) and ignore - them until socket EOF is reached; - Close the socket. - - -=============================================================================*/ - -#include "ngspice/ngspice.h" - -#ifdef IPC_UNIX_SOCKETS - -/*=== INCLUDE FILES ===*/ - -#include -#include - -#include "ngspice/ipc.h" -#include "ngspice/ipctiein.h" - - -/*=== TYPE DEFINITIONS ===*/ - -typedef enum { - IPC_SOCK_UNINITIALIZED, - IPC_SOCK_INITIALIZED, - IPC_SOCK_CONNECTED_TO_CLIENT -} Ipc_Sock_State_t; - - -/*=== LOCAL VARIABLES ===*/ - -static int sock_desc; /* socket descriptor */ -static int msg_stream; /* socket stream */ -static Ipc_Sock_State_t sock_state = IPC_SOCK_UNINITIALIZED; - - -/*=== INCLUDE FILES ===*/ - -#include "ngspice/ipcproto.h" - -/*============================================================================= - -FUNCTION ipc_transport_initialize_server - -AUTHORS - - July 1991 Stefan Roth - -MODIFICATIONS - - NONE - -SUMMARY - - Creates and opens the BSD socket of the server. Listens for requests - by a client and then reads the first line message. - -INTERFACES - - Called by: (IPC.c) ipc_initialize_server(); - -RETURNED VALUE - - Ipc_Status_t - returns status of the socket connection. - -GLOBAL VARIABLES - - NONE - -NON-STANDARD FEATURES - - NONE - -=============================================================================*/ - -Ipc_Status_t -ipc_transport_initialize_server ( - char *server_name, /* not used */ - Ipc_Mode_t mode, /* not used */ - Ipc_Protocol_t protocol, /* IN - only used in assert */ - char *batch_filename ) /* OUT - returns a value */ - /* Note that unused parameters are required to maintain compatibility */ - /* with version 1 (mailboxes) functions of the same names. */ -{ - struct sockaddr_in server; /* Server specifications for socket*/ - socklen_t server_length; /* Size of server structure */ - int port_num; /* Port number converted from server_name */ - - NG_IGNORE(mode); - NG_IGNORE(protocol); - - /* assert (protocol == IPC_PROTOCOL_V2); */ /* allow v1 protocol - wbk */ - assert (sock_state == IPC_SOCK_UNINITIALIZED); - - /* convert server_name (from atesse_xspice invocation line) to a port */ - /* number */ - port_num = atoi(server_name); - if((port_num > 0) && (port_num < 1024)) { - /* Reserved port number */ - perror ("ERROR: IPC Port numbers below 1024 are reserved"); - sock_state = IPC_SOCK_UNINITIALIZED; - return IPC_STATUS_ERROR; - } - - - sock_desc = socket (AF_INET, SOCK_STREAM, 0); - - if (sock_desc < 0) { - /* Unsuccessful socket opening */ - perror ("ERROR: IPC Creating socket"); - sock_state = IPC_SOCK_UNINITIALIZED; - return IPC_STATUS_ERROR; - } - - /* Socket opened successfully */ - - server.sin_family = AF_INET; - server.sin_addr.s_addr = INADDR_ANY; - server.sin_port = SOCKET_PORT; - - server_length = sizeof (server); - if (bind (sock_desc, (struct sockaddr *)&server, server_length) - < 0) { - fprintf (stderr, "ERROR: IPC: Bind unsuccessful\n"); - perror ("ERROR: IPC"); - sock_state = IPC_SOCK_UNINITIALIZED; - return IPC_STATUS_ERROR; - } - - if (getsockname (sock_desc, (struct sockaddr *)&server, &server_length) - < 0) { - fprintf (stderr, "ERROR: IPC: getting socket name\n"); - perror ("ERROR: IPC"); - sock_state = IPC_SOCK_UNINITIALIZED; - return IPC_STATUS_ERROR; - } - - fprintf (stderr, "Socket port %d.\n", ntohs(server.sin_port)); - - listen (sock_desc, 5); - - sock_state = IPC_SOCK_INITIALIZED; - - /* Socket ok to use now */ - - /* - * First record is the name of the batch filename if we're in batch mode. - */ - - if(g_ipc.mode == IPC_MODE_BATCH) { - int len; - return ipc_get_line (batch_filename, &len, IPC_WAIT); - } - - /* Return success */ - return IPC_STATUS_OK; - -} /* end ipc_transport_initialize_server */ - - - -/*============================================================================= - -FUNCTION bytes_to_integer - -AUTHORS - - July 1991 Stefan Roth - -MODIFICATIONS - - NONE - -SUMMARY - - Convert four bytes at START in the string STR - to a 32-bit unsigned integer. The string is assumed - to be in network byte order and the returned value - is converted to host byte order (with ntohl). - -INTERFACES - - Local to this file. - Called by: ipc_transport_get_line(); - -RETURNED VALUE - - u_long - unsigned 32 bit integer - -GLOBAL VARIABLES - - NONE - -NON-STANDARD FEATURES - - NONE - -=============================================================================*/ - -/* FIXME, - * this is seriously broken, - * once it was probably based upon htonl(), - * yet with broken types - * then the game has changed and strtoul() was used - * with a ascii representation of the length - * (probably as a hacky workaround, because it proved unreliable) - * but the buffer is not terminated properly - * Fix this when needed, currently this functionality looks like - * an unused ancient artefact - * Fix it with regard to ipc_transport_get_line() and ipc_transport_send_line() - * and in concert with the actual user at the other side of the socket - */ -static u_long -bytes_to_integer ( - char *str, /* IN - string that contains the bytes to convert */ - int start ) /* IN - index into string where bytes are */ -{ - uint32_t u; /* Value to be returned */ - char buff[4]; /* Transfer str into buff to word align reqd data */ - int index; /* Index into str and buff for transfer */ - - /* Get the str+start character and cast it into a u_long and put - the value through the network-to-host-short converter and store - it in the variable u. */ - - index = 0; - while (index < (int) sizeof(u)) { - buff[index] = str[index+start]; - index++; - } -/* u = ntohl (*((u_long *) buff)); */ - u = (uint32_t) strtoul(buff, NULL, 10); - - return u; -} /* end bytes_to_integer */ - - - -/*============================================================================= - -FUNCTION handle_socket_eof - -AUTHORS - - July 1991 Stefan Roth - -MODIFICATIONS - - NONE - -SUMMARY - - Do processing when the socket reaches EOF or when a message from the - client states that EOF has been reached. - -INTERFACES - - Local to this file. - Called by: ipc_transport_get_line(); - -RETURNED VALUE - - Ipc_Status_t - always IPC_STATUS_EOF - -GLOBAL VARIABLES - - NONE - -NON-STANDARD FEATURES - - NONE - -=============================================================================*/ - - -static Ipc_Status_t -handle_socket_eof (void) -{ - close (msg_stream); - close (sock_desc); - - sock_state = IPC_SOCK_UNINITIALIZED; - - return IPC_STATUS_EOF; -} /* handle_socket_eof */ - - - -/*============================================================================= - -FUNCTION read_sock - -AUTHORS - - July 1991 Stefan Roth - -MODIFICATIONS - - NONE - -SUMMARY - - Read N bytes from a socket. Only returns when the read had an error, - when 0 bytes (EOF) could be read, or LENGTH bytes are read. - -INTERFACES - - Local to this file. - Called by: ipc_transport_get_line(); - -RETURNED VALUE - - int - Returns the total number of bytes read. - -GLOBAL VARIABLES - - NONE - -NON-STANDARD FEATURES - - NONE - -=============================================================================*/ - - -static int -read_sock ( - int stream, /* IN - Socket stream */ - char *buffer, /* OUT - buffer to store incoming data */ - int length, /* IN - Number of bytes to be read */ - Ipc_Wait_t wait, /* IN - type of read operation */ - int flags ) /* IN - Original socket flags for blocking read */ -{ - int count; /* Number of bytes read with last `read` */ - int totalcount; /* total number of bytes read */ - char *buf2; - -/* count = 0; */ -/* while (count < length) { */ -/* buffer[count] = 'x'; */ -/* count++; */ -/* } */ - count = (int) read (stream, buffer, (size_t) length); - if (wait == IPC_NO_WAIT) { - fcntl (stream, F_SETFL, flags); /* Revert to blocking read */ - } - if ((count <= 0) || (count == length)) { - /* If error or if read in reqd number of bytes: */ - return count; - } else { - /* Only got some of the bytes requested */ - totalcount = count; - buf2 = &buffer[totalcount]; - length = length - count; - while (length > 0) { - count = (int) read (stream, buf2, (size_t) length); - if (count <= 0) /* EOF or read error */ - break; - totalcount = totalcount + count; - buf2 = &buffer[totalcount]; - length = length - count; - } - if (length != 0) { - fprintf (stderr, "WARNING: READ_SOCK read %d bytes instead of %d\n", - totalcount, totalcount + length); - } - return totalcount; - } -} /* end read_sock */ - - - -/*============================================================================= - -FUNCTION ipc_transport_get_line - -AUTHORS - - July 1991 Stefan Roth - -MODIFICATIONS - - NONE - -SUMMARY - - Main function for reading one line from a socket. Requires that the - socket be open. Lines are mostly SPICE code, but commands may also - be embedded in the socket data and they are interpreted by this function. - Therefore, this function may cause the socket to be closed. - -INTERFACES - - Called by: ipc_transport_terminate_server(); - (IPC.c) ipc_get_line(); - -RETURNED VALUE - - Ipc_Status_t - returns status of the read operation - -GLOBAL VARIABLES - - NONE - -NON-STANDARD FEATURES - - NONE - -=============================================================================*/ - - -Ipc_Status_t -ipc_transport_get_line ( - char *str, /* returns the result, null terminated */ - int *len, /* length of str passed IN and passed OUT */ - Ipc_Wait_t wait ) /* IN - wait or dont wait on incoming msg */ -{ - int count = 0; /* number of bytes read */ - int message_length; /* extracted from message header */ - - if (sock_state == IPC_SOCK_UNINITIALIZED) { - fprintf (stderr, - "ERROR: IPC: Attempted to read from uninitialized socket\n"); - return IPC_STATUS_ERROR; - } - - assert ((sock_state == IPC_SOCK_CONNECTED_TO_CLIENT) || - (sock_state == IPC_SOCK_INITIALIZED)); - - if (sock_state == IPC_SOCK_INITIALIZED) { - /* We have an open socket but have not connected to a client. */ - /* Accept a connection from a client. */ - msg_stream = accept (sock_desc, (struct sockaddr *)0, (socklen_t*)0); - - if (msg_stream == -1) { - fprintf (stderr, "ERROR: IPC: Server accepting request\n"); - perror ("ERROR: IPC"); - return IPC_STATUS_ERROR; - } - sock_state = IPC_SOCK_CONNECTED_TO_CLIENT; - } - /*-----------------------------------------------------------------------*/ - /* First read in the message header. */ - { - int flags; - flags = fcntl(msg_stream, F_GETFL, NULL); /* Blocking read mode */ - - if (wait == IPC_WAIT) { - /* Block here and wait for the next message */ - count = read_sock (msg_stream, str, SOCK_MSG_HDR_LEN, wait, flags); - if (count == 0) { - /* EOF, will this ever happen? */ - /* fprintf (stderr, "WARNING: IPC: Reached eof on socket\n"); */ - return handle_socket_eof (); - } - } else if (wait == IPC_NO_WAIT) { - /* Read message, but do not wait if none available. */ - - fcntl (msg_stream, F_SETFL, flags | O_NDELAY); - count = read_sock (msg_stream, str, SOCK_MSG_HDR_LEN, wait, flags); - - if (count == 0) { - /* EOF, will this ever happen? */ - /* fprintf (stderr, "WARNING: IPC: Reached eof on socket\n"); */ - return handle_socket_eof (); - } else if (count == -1) { - if (errno == EWOULDBLOCK) { - return IPC_STATUS_NO_DATA; - } - } - - } else { - /* Serious problem, since it is not reading anything. */ - fprintf (stderr, - "ERROR: IPC: invalid wait arg to ipc_transport_get_line\n"); - } - } - - /* Do more error checking on the read in values of the message header: */ - if (count == -1) { - fprintf (stderr, "ERROR: IPC: Reading from socket\n"); - perror ("ERROR: IPC"); - return IPC_STATUS_ERROR; - } else if (str[0] != BOL_CHAR) { - fprintf (stderr, - "ERROR: IPC: Did not find beginning of message header (%c)\n", - str[0]); - return IPC_STATUS_ERROR; - } else if ((message_length = (int) bytes_to_integer (str, 1)) == -1) { - /* fprintf (stderr, "WARNING: IPC: Reached eof on socket\n"); */ - return handle_socket_eof (); - } else if (message_length == 0) { - *len = 0; - return IPC_STATUS_NO_DATA; - -/* Invalid test... delete - wbk - } else if (message_length > *len) { - fprintf (stderr, - "ERROR: IPC: Buffer (%d) is too short for message (%d)\n", - *len, message_length); - return IPC_STATUS_ERROR; -*/ - - } - - /*-----------------------------------------------------------------------*/ - /* Now read in the message body. */ - /* Always block here since the message header was already read and */ - /* we must get the body. */ - - *len = message_length; - count = read_sock (msg_stream, str, message_length, IPC_WAIT, 0); - if (count == 0) { - /* EOF, will this ever happen? */ - /* fprintf (stderr, */ - /* "WARNING: IPC: Reached eof in message body on socket\n");*/ - return handle_socket_eof (); - } else if (count == -1) { - fprintf (stderr, "ERROR: IPC: reading message body from socket\n"); - perror ("ERROR: IPC"); - return IPC_STATUS_ERROR; - } - - /* Looks like we have a valid message here. Put in the string terminator. */ - *len = count; - str[count] = '\0'; - - return IPC_STATUS_OK; - -} /* end ipc_transport_get_line */ - - - -/*============================================================================= - -FUNCTION ipc_transport_send_line - -AUTHORS - - July 1991 Stefan Roth - -MODIFICATIONS - - NONE - -SUMMARY - Send a line of information. First sends a message header and - then the actual message body. - Error checking is done to make reasonably sure that the data was sent. - - -INTERFACES - - Called by: (IPC.c) ipc_flush (); - -RETURNED VALUE - - Ipc_Status_t - returns status of the send operation (typically - IPC_STATUS_ERROR or IPC_STATUS_OK). - - -GLOBAL VARIABLES - - NONE - -NON-STANDARD FEATURES - - NONE - -=============================================================================*/ - - -Ipc_Status_t -ipc_transport_send_line ( - char *str, /* IN - String to write */ - int len ) /* IN - Number of characters out of STR to write */ -{ - int count; /* Counts how many bytes were actually written */ - u_long u; /* 32-bit placeholder for transmission of LEN */ - char hdr_buff[5]; /* Buffer for building header message in */ - int i; /* Temporary counter */ - char *char_ptr; /* Pointer for int to bytes conversion */ - - if (sock_state != IPC_SOCK_CONNECTED_TO_CLIENT) { - fprintf (stderr, "ERROR: IPC: Attempt to write to non-open socket\n"); - return IPC_STATUS_ERROR; - } - - /* Write message body header with length: */ - hdr_buff[0] = BOL_CHAR; - u = htonl ((uint32_t) len); - char_ptr = (char *) &u; - for(i = 0; i < 4; i++) - hdr_buff[i+1] = char_ptr[i]; - - count = (int) write (msg_stream, hdr_buff, 5); - if (count != 5) { - fprintf (stderr, "ERROR: IPC: (%d) send line error 1\n", count); - return IPC_STATUS_ERROR; - } - - /* Write message body: */ - count = (int) write (msg_stream, str, (size_t) len); - if (count != len) { - fprintf (stderr, "ERROR: IPC: (%d) send line error 2\n", count); - return IPC_STATUS_ERROR; - } - - return IPC_STATUS_OK; -} /* end ipc_transport_send_line */ - - - -/*============================================================================= - -FUNCTION ipc_transport_terminate_server - -AUTHORS - - July 1991 Stefan Roth - -MODIFICATIONS - - NONE - -SUMMARY - - This function reads all pending incoming messages and discards them. - Reading continues until a read error occurs or EOF is reached, at which - time the socket is closed. - Note that this function does not actually close the socket. This is - done in ipc_transport_get_line, which is called in this function. - - In this function, the incoming line length is limited. See buffer below. - -INTERFACES - - Called by: (IPC.c) ipc_terminate_server(); - -RETURNED VALUE - - Ipc_Status_t - returns status of last read operation (always - IPC_STATUS_ERROR or IPC_STATUS_EOF). - -GLOBAL VARIABLES - - NONE - -NON-STANDARD FEATURES - - NONE - -=============================================================================*/ - - -Ipc_Status_t -ipc_transport_terminate_server (void) -{ - char buffer[17000]; /* temp buffer for incoming data */ - int len; /* placeholder var to as arg to function */ - Ipc_Status_t status; /* value to be returned from function */ - int max_size; /* Max length of buffer */ - - max_size = sizeof (buffer); - do { - len = max_size; - status = ipc_transport_get_line (buffer, &len, IPC_WAIT); - } while ((status != IPC_STATUS_ERROR) && - (status != IPC_STATUS_EOF)); - return status; -} - -#endif /* IPC_UNIX_SOCKETS */ diff --git a/src/xspice/ipc/ipcstdio.c b/src/xspice/ipc/ipcstdio.c deleted file mode 100644 index 229fff3ba..000000000 --- a/src/xspice/ipc/ipcstdio.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Steve Tynor - * - * Generic Interprocess Communication module - * - * Used for debugging in absense of IPC interface. - * - */ - -#include "ngspice/ngspice.h" - -#ifdef IPC_DEBUG_VIA_STDIO - -#include - - -#include "ngspice/ipc.h" - -#include "ngspice/ipcproto.h" - -#include /* 12/1/97 jg */ - -/*---------------------------------------------------------------------------*/ -Ipc_Status_t ipc_transport_initialize_server ( - char *server_name, - Ipc_Mode_t m, - Ipc_Protocol_t p, - char *batch_filename ) -{ - NG_IGNORE(server_name); - NG_IGNORE(p); - NG_IGNORE(batch_filename); - - assert (m == IPC_MODE_INTERACTIVE); - printf ("INITIALIZE_SERVER\n"); - return IPC_STATUS_OK; -} - -/*---------------------------------------------------------------------------*/ -Ipc_Status_t ipc_transport_get_line ( - char *str, - int *len, - Ipc_Wait_t wait ) -{ - NG_IGNORE(wait); - - printf ("GET_LINE\n"); - fgets (str, 512, stdin); - char *tmp = strchr(str, '\n'); - if (tmp) - *tmp = '\0'; - *len = (int) strlen (str); - return IPC_STATUS_OK; -} - -/*---------------------------------------------------------------------------*/ -Ipc_Status_t ipc_transport_send_line ( - char *str, - int len ) -{ - int i; - - printf ("SEND_LINE: /"); - for (i = 0; i < len; i++) - putchar (str[i]); - printf ("/\n"); - return IPC_STATUS_OK; -} - -/*---------------------------------------------------------------------------*/ -Ipc_Status_t ipc_transport_terminate_server (void) -{ -return IPC_STATUS_OK; -} - - -#endif /* IPC_DEBUG_VIA_STDIO */ diff --git a/src/xspice/ipc/ipctiein.c b/src/xspice/ipc/ipctiein.c deleted file mode 100644 index d104158bb..000000000 --- a/src/xspice/ipc/ipctiein.c +++ /dev/null @@ -1,520 +0,0 @@ -/*============================================================================ -FILE IPCtiein.c - -MEMBER OF process XSPICE - -Public Domain - -Georgia Tech Research Corporation -Atlanta, Georgia 30332 -PROJECT A-8503 - -AUTHORS - - 9/12/91 Bill Kuhn - -MODIFICATIONS - - - -SUMMARY - - Provides a protocol independent interface between the simulator - and the IPC method used to interface to CAE packages. - -INTERFACES - - g_ipc (global variable) - - ipc_handle_stop() - ipc_handle_returni() - ipc_handle_mintime() - ipc_handle_vtrans() - ipc_send_stdout() - ipc_send_stderr() - ipc_send_std_files() - ipc_screen_name() - ipc_get_devices() - ipc_free_devices() - ipc_check_pause_stop() - -REFERENCED FILES - - None. - -NON-STANDARD FEATURES - - None. - -============================================================================*/ - - -#define CONFIG - -#include "ngspice/ngspice.h" -#include "ngspice/inpdefs.h" -#include "ngspice/gendefs.h" -#include "ngspice/cktdefs.h" -#include "bjt/bjtdefs.h" -#include "jfet/jfetdefs.h" -#include "mos1/mos1defs.h" -#include "mos2/mos2defs.h" -#include "mos3/mos3defs.h" -#include "ngspice/mifproto.h" -#include "ngspice/ipc.h" -#include "ngspice/ipctiein.h" - - - -/* -Global variable g_ipc is used by the SPICE mods that take care of -interprocess communications activities. -*/ - - -Ipc_Tiein_t g_ipc = { - IPC_FALSE, /* enabled */ - IPC_MODE_INTERACTIVE, /* mode */ - IPC_ANAL_DCOP, /* analysis mode */ - IPC_FALSE, /* parse_error */ - IPC_FALSE, /* run_error */ - IPC_FALSE, /* errchk_sent */ - IPC_FALSE, /* returni */ - 0.0, /* mintime */ - 0.0, /* lasttime */ - 0.0, /* cpu time */ - NULL, /* send array */ - NULL, /* log file */ - { /* vtrans struct */ - 0, /* size */ - NULL, /* vsrc_name array */ - NULL, /* device_name array */ - }, - IPC_FALSE, /* stop analysis */ -}; - - - -/* -ipc_handle_stop - -This function sets a flag in the g_ipc variable to signal that -a stop message has been received over the IPC channel. -*/ - -void ipc_handle_stop(void) -{ - g_ipc.stop_analysis = IPC_TRUE; -} - - -/* -ipc_handle_returni - -This function sets a flag in the g_ipc variable to signal that -a message has been received over the IPC channel specifying that -current values are to be returned in the results data sets. -*/ - -void ipc_handle_returni(void) -{ - g_ipc.returni = IPC_TRUE; -} - - -/* -ipc_handle_mintime - -This function sets a value in the g_ipc variable that specifies -how often data is to be returned as it is computed. If the -simulator takes timestep backups, data may still be returned -more often that that specified by 'mintime' so that glitches -are not missed. -*/ - -void ipc_handle_mintime(double time) -{ - g_ipc.mintime = time; -} - - - -/* -ipc_handle_vtrans - -This function processes arguments from a #VTRANS card received over -the IPC channel. The data on the card specifies that a particular -zero-valued voltage source name should be translated to the specified -instance name for which it was setup to monitor currents. -*/ - -void ipc_handle_vtrans( - char *vsrc, /* The name of the voltage source to be translated */ - char *dev) /* The device name the vsource name should be translated to */ -{ - int i; - int size; - - - if(g_ipc.vtrans.size == 0) { - g_ipc.vtrans.size = 1; - g_ipc.vtrans.vsrc_name = TMALLOC(char *, 1); - g_ipc.vtrans.device_name = TMALLOC(char *, 1); - g_ipc.vtrans.vsrc_name[0] = MIFcopy(vsrc); - g_ipc.vtrans.device_name[0] = MIFcopy(dev); - } - else { - g_ipc.vtrans.size++; - - size = g_ipc.vtrans.size; - i = g_ipc.vtrans.size - 1; - - g_ipc.vtrans.vsrc_name = TREALLOC(char *, g_ipc.vtrans.vsrc_name, size); - g_ipc.vtrans.device_name = TREALLOC(char *, g_ipc.vtrans.device_name, size); - g_ipc.vtrans.vsrc_name[i] = MIFcopy(vsrc); - g_ipc.vtrans.device_name[i] = MIFcopy(dev); - } -} - - - -/* -ipc_send_stdout - -This function sends the data written to stdout over the IPC channel. -This stream was previously redirected to a temporary file during -the simulation. -*/ - -void ipc_send_stdout(void) -{ - int c; - int len; - - char buf[IPC_MAX_LINE_LEN+1]; - - /* rewind the redirected stdout stream */ - rewind(stdout); - - /* Begin reading from the top of file and send lines */ - /* over the IPC channel. */ - - /* Don't send newlines. Also, if line is > IPC_MAX_LINE_LEN chars */ - /* we must wrap it because Mspice can't handle it */ - - len = 0; - while( (c=fgetc(stdout)) != EOF) { - if(c != '\n') { - buf[len] = (char) c; - len++; - } - if((c == '\n') || (len == IPC_MAX_LINE_LEN)) { - buf[len] = '\0'; - ipc_send_line(buf); - len = 0; - } - } - if(len > 0) { - buf[len] = '\0'; - ipc_send_line(buf); - } - - /* Finally, rewind file again to discard the data already sent */ - rewind(stdout); -} - - -/* -ipc_send_stderr - -This function sends the data written to stderr over the IPC channel. -This stream was previously redirected to a temporary file during -the simulation. -*/ - -void ipc_send_stderr(void) -{ - int c; - int len; - - char buf[IPC_MAX_LINE_LEN+1]; - - /* rewind the redirected stderr stream */ - rewind(stderr); - - /* Begin reading from the top of file and send lines */ - /* over the IPC channel. */ - - /* Don't send newlines. Also, if line is > IPC_MAX_LINE_LEN chars */ - /* we must wrap it because Mspice can't handle it */ - - len = 0; - while( (c=fgetc(stderr)) != EOF) { - if(c != '\n') { - buf[len] = (char) c; - len++; - } - if((c == '\n') || (len == IPC_MAX_LINE_LEN)) { - buf[len] = '\0'; - ipc_send_line(buf); - len = 0; - } - } - if(len > 0) { - buf[len] = '\0'; - ipc_send_line(buf); - } - - /* Finally, rewind file again to discard the data already sent */ - rewind(stderr); -} - - -/* -ipc_send_std_files - -This function sends the data written to stdout and stderr over the -IPC channel. These streams were previously redirected to temporary -files during the simulation. -*/ - -Ipc_Status_t ipc_send_std_files(void) -{ - ipc_send_stdout(); - ipc_send_stderr(); - - return(ipc_flush()); -} - - - -/* -ipc_screen_name - -This function screens names of instances and nodes to limit the -data returned over the IPC channel. -*/ - -Ipc_Boolean_t ipc_screen_name(char *name, char *mapped_name) -{ - char *endp; - int i; - int len; - long l; - - /* Return FALSE if name is in a subcircuit */ - for(i = 0; name[i] != '\0'; i++) { - if(name[i] == ':') - return(IPC_FALSE); - } - - /* Determine if name is numeric and what value is */ - l = strtol(name, &endp, 10); - - /* If numeric */ - if(*endp == '\0') { - /* Return FALSE if >100,000 -> added by ms_server in ATESSE 1.0 */ - if(l >= 100000) - return(IPC_FALSE); - /* Otherwise, copy name to mapped name and return true */ - else { - strcpy(mapped_name,name); - return(IPC_TRUE); - } - } - - /* If node is an internal node from a semiconductor (indicated by a */ - /* trailing #collector, #source, ...), do not return its current. */ - /* Otherwise, map to upper case and eliminate trailing "#branch" if any. */ - for(i = 0; name[i]; i++) { - if(name[i] == '#') { - if(strcmp(name + i, "#branch") == 0) - break; - else - return(IPC_FALSE); - } - else { - if(islower_c(name[i])) - mapped_name[i] = toupper_c(name[i]); - else - mapped_name[i] = name[i]; - } - } - mapped_name[i] = '\0'; - len = i; - - /* If len != 8 or 6'th char not equal to $, then doesn't need vtrans */ - /* Otherwise, translate to device name that it monitors */ - if(len != 8) - return(IPC_TRUE); - else if(name[5] != '$') - return(IPC_TRUE); - else { - /* Scan list of prefixes in VTRANS table and convert name */ - for(i = 0; i < g_ipc.vtrans.size; i++) { - if(strncmp(mapped_name, g_ipc.vtrans.vsrc_name[i], 5) == 0) { - strcpy(mapped_name, g_ipc.vtrans.device_name[i]); - return(IPC_TRUE); - } - } - return(IPC_TRUE); - } - -} - - - -/* -ipc_get_devices - -This function is used to setup the OUTinterface data structure that -determines what instances will have data returned over the IPC channel. -*/ - - -int ipc_get_devices( - CKTcircuit *ckt, /* The circuit structure */ - char *device, /* The device name as it appears in the info struct */ - char ***names, /* Array of name strings to be built */ - double **modtypes) /* Array of types to be built */ -{ - int index; - int num_instances; - GENmodel *model; - GENinstance *here; - char *inst_name; - int inst_name_len; - int i; - - BJTmodel *BJTmod; - JFETmodel *JFETmod; - MOS1model *MOS1mod; - MOS2model *MOS2mod; - MOS3model *MOS3mod; - - /* Initialize local variables */ - num_instances = 0; - - /* Get the index into the circuit structure linked list of models */ - index = INPtypelook(device); - - /* Iterate through all models of this type */ - for(model = ckt->CKThead[index]; model; model = model->GENnextModel) { - - /* Iterate through all instance of this model */ - for(here = model->GENinstances; here; here = here->GENnextInstance) { - - /* Get the name of the instance */ - inst_name = here->GENname; - inst_name_len = (int) strlen(inst_name); - - /* Skip if it is a inside a subcircuit */ - for(i = 0; i < inst_name_len; i++) - if(inst_name[i] == ':') - break; - if(i < inst_name_len) - continue; - - /* Otherwise, add the name to the list */ - num_instances++; - if(num_instances == 1) - *names = TMALLOC(char *, 1); - else - *names = TREALLOC(char *, *names, num_instances); - (*names)[num_instances-1] = MIFcopy(inst_name); - - /* Then get the type if it is a Q J or M */ - if(num_instances == 1) - *modtypes = TMALLOC(double, 1); - else - *modtypes = TREALLOC(double, *modtypes, num_instances); - - if(strcmp(device,"BJT") == 0) { - BJTmod = (BJTmodel *) model; - (*modtypes)[num_instances-1] = BJTmod->BJTtype; - } - else if(strcmp(device,"JFET") == 0) { - JFETmod = (JFETmodel *) model; - (*modtypes)[num_instances-1] = JFETmod->JFETtype; - } - else if(strcmp(device,"Mos1") == 0) { - MOS1mod = (MOS1model *) model; - (*modtypes)[num_instances-1] = MOS1mod->MOS1type; - } - else if(strcmp(device,"Mos2") == 0) { - MOS2mod = (MOS2model *) model; - (*modtypes)[num_instances-1] = MOS2mod->MOS2type; - } - else if(strcmp(device,"Mos3") == 0) { - MOS3mod = (MOS3model *) model; - (*modtypes)[num_instances-1] = MOS3mod->MOS3type; - } - else { - (*modtypes)[num_instances-1] = 1.0; - } - - } /* end for all instances */ - } /* end for all models */ - - return(num_instances); -} - - - -/* -ipc_free_devices - -This function frees temporary data created by ipc_get_devices(). -*/ - - -void ipc_free_devices( - int num_items, /* Number of things to free */ - char **names, /* Array of name strings to be built */ - double *modtypes) /* Array of types to be built */ -{ - int i; - - for(i = 0; i < num_items; i++) - { - FREE(names[i]); - names[i] = NULL; - } - - if(num_items > 0) - { - FREE(names); - FREE(modtypes); - - names = NULL; - modtypes = NULL; - } -} - - -/* -ipc_check_pause_stop - -This function is called at various times during a simulation to check -for incoming messages of the form >STOP or >PAUSE signaling that -simulation should be stopped or paused. Processing of the messages -is handled by ipc_get_line(). -*/ - -void ipc_check_pause_stop(void) -{ - char buf[1025]; - int len; - - /* If already seen stop analysis, don't call ipc_get_line, just return. */ - /* This is provided so that the function can be called multiple times */ - /* during the process of stopping */ - if(g_ipc.stop_analysis) - return; - - /* Otherwise do a non-blocking call to ipc_get_line() to check for messages. */ - /* We assume that the only possible messages at this point are >PAUSE */ - /* and >STOP, so we don't do anything with the returned text if any */ - ipc_get_line(buf, &len, IPC_NO_WAIT); -} - diff --git a/visualc/sharedspice.vcxproj b/visualc/sharedspice.vcxproj index c62fafd5e..d8f8ff189 100644 --- a/visualc/sharedspice.vcxproj +++ b/visualc/sharedspice.vcxproj @@ -740,7 +740,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 - @@ -795,8 +794,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 - - @@ -1544,7 +1541,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 - @@ -2614,11 +2610,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 - - - - - diff --git a/visualc/src/include/ngspice/config.h b/visualc/src/include/ngspice/config.h index 61541cf88..18840505a 100644 --- a/visualc/src/include/ngspice/config.h +++ b/visualc/src/include/ngspice/config.h @@ -47,9 +47,6 @@ /* Define to 1 if the `closedir' function returns void instead of `int'. */ /* #undef CLOSEDIR_VOID */ -/* Spice cluster support */ -/* #undef CLUSTER */ - /* Define if you want to debug ngspice shell */ /* #undef CPDEBUG */ diff --git a/visualc/vngspice-fftw.vcxproj b/visualc/vngspice-fftw.vcxproj index 33b7c33e0..d6e3a6343 100644 --- a/visualc/vngspice-fftw.vcxproj +++ b/visualc/vngspice-fftw.vcxproj @@ -956,7 +956,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 - @@ -1012,8 +1011,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 - - @@ -1765,7 +1762,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 - @@ -2835,11 +2831,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 - - - - - diff --git a/visualc/vngspice.vcxproj b/visualc/vngspice.vcxproj index 8e80be4e2..b4e342411 100644 --- a/visualc/vngspice.vcxproj +++ b/visualc/vngspice.vcxproj @@ -971,7 +971,6 @@ - @@ -1027,8 +1026,6 @@ - - @@ -1779,7 +1776,6 @@ - @@ -2849,11 +2845,6 @@ - - - - -