diff --git a/src/frontend/inp.c b/src/frontend/inp.c index c12489ef8..56951b617 100644 --- a/src/frontend/inp.c +++ b/src/frontend/inp.c @@ -530,7 +530,9 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) char *dir_name = ngdirname(filename ? filename : "."); startTime = seconds(); - /* inp_source() called with fp: load from file, */ + /* Parsing the circuit 2. + This is the next major step: + inp_source() called with fp: load circuit netlist from file, */ /* called with *fp == NULL and intfile: we want to load circuit from circarray */ if (fp || intfile) { deck = inp_readall(fp, dir_name, filename, comfile, intfile, &expr_w_temper); @@ -931,7 +933,9 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) } } - /* Now expand subcircuit macros and substitute numparams.*/ + /* Parsing the circuit 4. + This is the next major step: + Expand subcircuit macros and substitute numparams.*/ if (!cp_getvar("nosubckt", CP_BOOL, NULL, 0)) if ((deck->nextcard = inp_subcktexpand(deck->nextcard)) == NULL) { line_free(realdeck, TRUE); @@ -985,8 +989,11 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) continue; /* Only truncated .model lines */ if (ciprefix(".model", tc->line)) { - fprintf(fdo, "%6d %.100s ...\n", + fprintf(fdo, "%6d %.100s ", tc->linenum, tc->line); + if (strlen(tc->line) > 100) + fprintf(fdo, " ... (truncated)"); + fprintf(fdo, "\n"); } else { fprintf(fdo, "%6d %s\n", @@ -1084,7 +1091,9 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) if (newcompat.hs || newcompat.spe) rem_unused_mos_models(deck->nextcard); #endif - /* now load deck into ft_curckt -- the current circuit. */ + /* Parsing the circuit 5. + This is the next major step: + load deck into ft_curckt -- the current circuit. */ if(inp_dodeck(deck, tt, wl_first, FALSE, options, filename) != 0) return 1; @@ -1411,6 +1420,10 @@ inp_dodeck( *---------------------------------------------------*/ if (!noparse) { startTime = seconds(); + /* Parsing the circuit 6. + This is the next major step: + Input a single deck, and return a pointer to the circuit. + Parse all models and instances */ ckt = if_inpdeck(deck, &tab); ft_curckt->FTEstats->FTESTATnetParseTime = seconds() - startTime; /* if .probe, rename the current measurement node vcurr_ */ diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index ff693b115..1f90d2732 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -1054,6 +1054,10 @@ struct card *inp_readall(FILE *fp, const char *dir_name, const char* file_name, /* set the members of the compatibility structure */ set_compat_mode(); + /* Parsing the circuit 3. + This is the next major step: + Reading the netlist line by line, handle .include and .lib, + line continuation and upper/lower casing */ rv = inp_read(fp, 0, dir_name, file_name, comfile, intfile); cc = rv.cc; @@ -1241,8 +1245,11 @@ struct card *inp_readall(FILE *fp, const char *dir_name, const char* file_name, continue; /* Only truncated .model lines */ if (ciprefix(".model", t->line)) { - fprintf(fd, "%6d %.100s ...\n", + fprintf(fd, "%6d %.100s ", t->linenum, t->line); + if (strlen(t->line) > 100) + fprintf(fd, " ... (truncated)"); + fprintf(fd, "\n"); } else { fprintf(fd, "%6d %s\n", @@ -1602,11 +1609,8 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name char* tmpstr = copy(nexttok(buffer)); wl_append_word(&sourceinfo, &sourceinfo, tmpstr); - /* Add source of netlist data, for use in verbose error messages. - Set the compatibility mode flag to 1, if pslt is read. */ + /* Set the compatibility mode flag to 1, if pslt is read. */ for (tmpcard = newcard; tmpcard; tmpcard = tmpcard->nextcard) { - /* skip *include */ - tmpcard->linesource = tmpstr; if (compset) tmpcard->compmod = 1; else @@ -9038,7 +9042,7 @@ static void inp_check_syntax(struct card *deck) acline = nexttok(acline); if (!acline) { fprintf(stderr, "Error in line %s\n", cut_line); - fprintf(stderr, " Not enough parameters\n"); + fprintf(stderr, " Not enough parameters for %c source\n", *cut_line); fprintf(stderr, " line no. %d from file %s\n", card->linenum_orig, card->linesource); diff --git a/src/frontend/resource.c b/src/frontend/resource.c index 2008efc48..47b4ae400 100644 --- a/src/frontend/resource.c +++ b/src/frontend/resource.c @@ -339,9 +339,9 @@ printres(char *name) ft_curckt->ci_ckt->CKTstat->devTimes[i]/(double)(ft_curckt->ci_ckt->CKTstat->devCounts[i]) ); } + yy = TRUE; } - yy = TRUE; - + #ifdef CIDER /* begin cider integration */ if (!name || eq(name, "circuit") || eq(name, "task")) diff --git a/src/frontend/spiceif.c b/src/frontend/spiceif.c index 2615a5978..9697d7298 100644 --- a/src/frontend/spiceif.c +++ b/src/frontend/spiceif.c @@ -93,8 +93,9 @@ static int finddev(CKTcircuit *ckt, char *name, GENinstance **devptr, GENmodel * /* espice fix integration */ static int finddev_special(CKTcircuit *ckt, char *name, GENinstance **devptr, GENmodel **modptr, int *device_or_model); -/* Input a single deck, and return a pointer to the circuit. */ - +/* Input a single deck, and return a pointer to the circuit. + Parse all models in function INPpas1, instances (devices) in INPpas2, + consider initial conditions (INPpas3), and shunt capacitors (INPpas4). */ CKTcircuit * if_inpdeck(struct card *deck, INPtables **tab) { @@ -162,16 +163,23 @@ if_inpdeck(struct card *deck, INPtables **tab) ft_curckt->ci_curTask = ft_curckt->ci_defTask; - /* Parse the .model lines. Enter the model into the global model table modtab. */ modtab = NULL; modtabhash = NULL; - /* Parse .model lines, put them into 'tab' */ + /* Parsing the circuit 7. + This is the next major step: + Parse the .model lines. + Enter the model into the global model table modtab + and into the corresponding hash table modtabhash. + The role of 'tab' is unclear (not used any more?). */ INPpas1(ckt, deck->nextcard, *tab); - /* store the new model table in the current circuit */ + /* store the new model tables in the current circuit */ ft_curckt->ci_modtab = modtab; ft_curckt->ci_modtabhash = modtabhash; - /* Scan through the instance lines and parse the circuit. */ + /* Parsing the circuit 8. + This is the next major step: + Scan through the instance lines and parse the circuit. + Set up the circuit matrix. */ INPpas2(ckt, deck->nextcard, *tab, ft_curckt->ci_defTask); #ifdef XSPICE if (!Evtcheck_nodes(ckt, *tab)) { diff --git a/src/frontend/subckt.c b/src/frontend/subckt.c index 4cb7be417..52eb230f5 100644 --- a/src/frontend/subckt.c +++ b/src/frontend/subckt.c @@ -97,11 +97,10 @@ struct bxx_buffer; static void finishLine(struct bxx_buffer *dst, char *src, char *scname); static int settrans(char *formal, int flen, char *actual, const char *subname); static char *gettrans(const char *name, const char *name_end, bool *isglobal); -static int numnodes(const char *line, struct subs *subs, wordlist const *modnames); +static int numnodes(const char *line); static int numdevs(char *s); static wordlist *modtranslate(struct card *deck, char *subname, wordlist *new_modnames); static void devmodtranslate(struct card *deck, char *subname, wordlist * const orig_modnames); -static int inp_numnodes(char c); /* hash table to store the global nodes * For now its use is limited to avoid double entries in global_nodes[] */ @@ -1384,9 +1383,11 @@ translate(struct card *deck, char *formal, int flen, char *actual, char *scname, tfree(name); bxx_putc(&buffer, ' '); - /* Next iterate over all nodes (netnames) found and translate them. */ - nnodes = numnodes(c->line, subs, modnames); + /* Next iterate over all nodes (netnames) found and translate them. + * Ignore controlling nodes as they get special treatment for POLY. + */ + nnodes = numnodes(c->line); while (--nnodes >= 0) { name = gettok_node(&s); if (name == NULL) { @@ -1476,13 +1477,7 @@ translate(struct card *deck, char *formal, int flen, char *actual, char *scname, tfree(name); bxx_putc(&buffer, ' '); - /* FIXME anothet hack: if no models found for m devices, set number of nodes to 4 */ - if (!modnames && *(c->line) == 'm') - nnodes = get_number_terminals(c->line); - else if (*(c->line) == 'n') - nnodes = get_number_terminals(c->line); - else - nnodes = numnodes(c->line, subs, modnames); + nnodes = numnodes(c->line); while (--nnodes >= 0) { name = gettok_node(&s); if (name == NULL) { @@ -1692,91 +1687,23 @@ gettrans(const char *name, const char *name_end, bool *isglobal) } -/*-------------------------------------------------------------------*/ -/*-------------------------------------------------------------------*/ +/* Control nodes for E and G sources are not counted as they vary in + * the case of POLY. The count returned by get_number_terminals() includes + * devices for K (mutual inductors) and W (current-controlled switch). + */ + static int -numnodes(const char *line, struct subs *subs, wordlist const *modnames) +numnodes(const char *line) { - /* gtri - comment - wbk - 10/23/90 - Do not modify this routine for */ - /* 'A' type devices since the callers will not know how to find the */ - /* nodes even if they know how many there are. Modify the callers */ - /* instead. */ - /* gtri - end - wbk - 10/23/90 */ - char c; - int n; - - line = skip_ws(line); - - c = tolower_c(*line); - - if (c == 'x') { /* Handle this ourselves. */ - const char *xname_e = skip_back_ws(strchr(line, '\0'), line); - const char *xname = skip_back_non_ws(xname_e, line); - for (; subs; subs = subs->su_next) - if (eq_substr(xname, xname_e, subs->su_name)) - return subs->su_numargs; - /* - * number of nodes not known so far. - * lets count the nodes ourselves, - * assuming `buf' looks like this: - * xname n1 n2 ... nn subname - */ - { - int nodes = -2; - while (*line) { - nodes++; - line = skip_ws(skip_non_ws(line)); - } - return (nodes); - } - } - /* if we use option skywaterpdk, MOS has four nodes. Required if number of devices is large */ - if (ft_skywaterpdk && c == 'm') - return 4; - - n = inp_numnodes(c); - - /* Added this code for variable number of nodes on certain devices. */ - /* The consequence of this code is that the value returned by the */ - /* inp_numnodes(c) call must be regarded as "maximum number of nodes */ - /* for a given device type. */ - /* Paolo Nenzi Jan-2001 */ - - /* If model names equal node names, this code will fail! */ - if ((c == 'm') || (c == 'p') || (c == 'q') || (c == 'd')) { /* IF this is a mos, cpl, bjt or diode */ - char *s = nexttok(line); /* Skip the instance name */ - int gotit = 0; - int i = 0; - - while ((i <= n) && (*s) && !gotit) { - char *t = gettok_node(&s); /* get nodenames . . . */ - const wordlist *wl; - for (wl = modnames; wl; wl = wl->wl_next) - if (model_name_match(t, wl->wl_word)) { - gotit = 1; - break; - } - i++; - tfree(t); - } - - /* Note: node checks must be done on #_of_node-1 because the */ - /* "while" cycle increments the counter even when a model is */ - /* recognized. This code may be better! */ - - if ((i < 4) && ((c == 'm') || (c == 'q'))) { - fprintf(cp_err, "Error: too few nodes for MOS or BJT: %s\n", line); - return (0); - } - if ((i < 5) && (c == 'p')) { - fprintf(cp_err, "Error: too few nodes for CPL: %s\n", line); - return (0); - } - return (i-1); /* compensate the unnecessary increment in the while cycle */ - } else { - /* for all other elements */ - return (n); + switch (*line) { + case 'e': + case 'g': + case 'w': + return 2; + case 'k': + return 0; } + return get_number_terminals((char *)line); } @@ -2286,78 +2213,3 @@ devmodtranslate(struct card *s, char *subname, wordlist * const orig_modnames) bxx_free(&buffer); } - - -/*----------------------------------------------------------------------* - * inp_numnodes returns the maximum number of nodes (netnames) attached - * to the component. - * This is a spice-dependent thing. It should probably go somewhere - * else, but... Note that we pretend that dependent sources and mutual - * inductors have more nodes than they really do... - *----------------------------------------------------------------------*/ -static int -inp_numnodes(char c) -{ - if (isupper_c(c)) - c = tolower_c(c); - switch (c) { - case ' ': - case '\t': - case '.': - case 'x': - case '*': - case '$': - return (0); - - case 'b': - return (2); - case 'c': - return (2); - case 'd': - return (3); - case 'e': - return (2); /* changed from 4 to 2 by SDB on 4.22.2003 to enable POLY */ - case 'f': - return (2); - case 'g': - return (2); /* changed from 4 to 2 by SDB on 4.22.2003 to enable POLY */ - case 'h': - return (2); - case 'i': - return (2); - case 'j': - return (3); - case 'k': - return (0); - case 'l': - return (2); - case 'm': - return (7); /* This means that 7 is the maximun number of nodes */ - case 'o': - return (4); - case 'p': - return (18);/* 16 lines + 2 gnd is the maximum number of nodes for CPL */ - case 'q': - return (5); - case 'r': - return (2); - case 's': - return (4); - case 't': - return (4); - case 'u': - return (3); - case 'v': - return (2); - case 'w': - return (2); /* change 3 to 2 here to fix w bug, NCF 1/31/95 */ - case 'y': - return (4); - case 'z': - return (3); - - default: - fprintf(cp_err, "Warning: unknown device type: %c\n", c); - return (2); - } -} diff --git a/src/main.c b/src/main.c index a5a83c011..986714e72 100644 --- a/src/main.c +++ b/src/main.c @@ -1490,7 +1490,10 @@ int main(int argc, char **argv) gotone = FALSE; // Re-use if (tempfile && (!err || !ft_batchmode)) { - /* Copy the input file name for becoming another file search path */ + /* Parsing the circuit 1. + This is the next major step: + Source the input file, then parse the data and create the circuit. + Copy the input file name for becoming another file search path */ if (inp_spsource(tempfile, FALSE, dname, FALSE) != 0) { fprintf(stderr, " Simulation interrupted due to error!\n\n"); if (ft_stricterror || (oflag && !cp_getvar("interactive", CP_BOOL, NULL, 0))) diff --git a/src/spicelib/parser/inppas1.c b/src/spicelib/parser/inppas1.c index b990cadf6..c5048d134 100644 --- a/src/spicelib/parser/inppas1.c +++ b/src/spicelib/parser/inppas1.c @@ -8,9 +8,8 @@ Author: 1985 Thomas L. Quarles #include "inppas1.h" /* - * The first pass of the circuit parser just looks for '.model' lines - */ - + The first pass of the circuit parser just looks for '.model' lines, + and sticks model into model table tab. */ void INPpas1(CKTcircuit *ckt, struct card *deck, INPtables * tab) { struct card *current; diff --git a/src/winmain.c b/src/winmain.c index d380ff753..a851f4242 100644 --- a/src/winmain.c +++ b/src/winmain.c @@ -1340,7 +1340,9 @@ wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR /* Wait until everything is settled */ WaitForIdle(); - /* Go to main() */ + /* Parsing the command line. + This is the next major step: + Go to main() for reading the start command line and preparing the simulator. */ nReturnCode = xmain(argc, argv); THE_END: diff --git a/src/xspice/enh/enhtrans.c b/src/xspice/enh/enhtrans.c index 5e2bf8339..2eb23aa2a 100644 --- a/src/xspice/enh/enhtrans.c +++ b/src/xspice/enh/enhtrans.c @@ -124,6 +124,9 @@ ENHtranslate_poly( l1->linenum = d->linenum; l2->linenum = d->linenum; + l1->linesource = copy("internal"); + l2->linesource = copy("internal"); + /* Create the translated cards */ d->error = two2three_translate(d->line, &(l1->line), &(l2->line)); diff --git a/src/xspice/icm/analog/pwlts/cfunc.mod b/src/xspice/icm/analog/pwlts/cfunc.mod index 8aaf26d45..c26cbd89e 100644 --- a/src/xspice/icm/analog/pwlts/cfunc.mod +++ b/src/xspice/icm/analog/pwlts/cfunc.mod @@ -13,6 +13,7 @@ AUTHORS Pwl with time input and smoothing: pwlts 9 Sep 2022 Holger Vogt + 10 Oct 2025 Holger Vogt SUMMARY @@ -211,6 +212,46 @@ void cm_pwlts(ARGS) /* structure holding parms, y[0] = 2. * y[1] - y[2]; y[size - 1] = 2. * y[size - 2] - y[size - 3]; } + + /* See if input_domain is absolute...if so, test against */ + /* breakpoint segments for violation of 50% rule... */ + if (PARAM(fraction) == MIF_FALSE) { + if ( 3 < size ) { + for (i=1; i<(size-2); i++) { + /* Test for overlap...0.999999999 factor is to */ + /* prevent floating point problems with comparison. */ + if ( (test1 = x[i+1] - x[i]) < + (test2 = 0.999999999 * (2.0 * input_domain)) ) { + cm_message_send(limit_error); + } + } + } + } + + /* add permanent breakpoints */ + if (PARAM(fraction) == MIF_FALSE) { + for (i=1; i= dthi) ? dthi : dtlo) * input_domain; + if (x[i] - dt <= 0) + continue; + cm_analog_set_perm_bkpt(x[i] - dt); + cm_analog_set_perm_bkpt(x[i]); + cm_analog_set_perm_bkpt(x[i] + dt); + } + } + /* debug printout for (i = 0; i < size; i++) fprintf(stderr, "%e ", y[i]); @@ -229,22 +270,6 @@ void cm_pwlts(ARGS) /* structure holding parms, } - /* See if input_domain is absolute...if so, test against */ - /* breakpoint segments for violation of 50% rule... */ - if (PARAM(fraction) == MIF_FALSE) { - if ( 3 < size ) { - for (i=1; i<(size-2); i++) { - /* Test for overlap...0.999999999 factor is to */ - /* prevent floating point problems with comparison. */ - if ( (test1 = x[i+1] - x[i]) < - (test2 = 0.999999999 * (2.0 * input_domain)) ) { - cm_message_send(limit_error); - } - } - } - - } - /* Retrieve x_input value as current simulation time. */ x_input = TIME;