diff --git a/NEWS b/NEWS index bedb63582..50f5f5101 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,31 @@ +Ngspice-42, Dec 24th, 2023 +============ +- New features: + + New optional matrix solver KLU (select by 'option klu') + + improve error messages (more verbose, user centric) + + Add variable wr_onspace to allow printing the vetor name with + one space delimiter + + Re-write of the code model PWM generator + + Linked list modtab has been enhanced by a hash table + modtabhash + + Add a code model function cm_cexit(const int exitcode). + + PSP103 model pspnqs103va is now standard + + Add Isotel d_process xspice digital model (enable C models). + + OSDI interface allows small signal noise simulation in Verilog-A + compact models compiled by current OpenVAF. + + Add series resistance 1e-4 Ohms to diode model, if RS is not given + + Generate seed numbers from a microseconds clock, not a seconds clock + + Add functions ngSpice_LockRealloc and ngSpice_UnlockRealloc + + Add new code model function cm_irreversible(). + + Add XSPICE code model d_cosim, a generic adaptor for digital cosimulation. + + New interpreter commands strstr, strslice, fopen, fread and fclose. + + Recognise *ng_script_with_params" + + Add a predifined variable 'skywaterpdk' to speed up circuit + loading and parsing. + + Add scripts for running the paranoia tests in parallel on Linux with valgrind. + + + Ngspice-41, Aug 13th, 2023 ============ - New features: diff --git a/examples/measure/buggy-meas-tran.sp b/examples/measure/buggy-meas-tran.sp index a2a3906af..36277ebe8 100644 --- a/examples/measure/buggy-meas-tran.sp +++ b/examples/measure/buggy-meas-tran.sp @@ -91,5 +91,7 @@ meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG VAL=0.5 RISE=2 meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG v(1) RISE=2 meas tran tdiff TRIG v(1) VAL= RISE=1 TARG v(1) VAL=0.5 RISE=2 meas tran tdiff TRIG v(1) VAL=0.5 RISE= TARG v(1) VAL=0.5 RISE=2 +meas sp tmax MAX v(2) from=2m to=3m +meas dc ymax MAX v(2) from=2m to=3m .endc .end diff --git a/src/frontend/com_measure2.c b/src/frontend/com_measure2.c index 7033abbec..b36a510ce 100644 --- a/src/frontend/com_measure2.c +++ b/src/frontend/com_measure2.c @@ -432,7 +432,10 @@ com_measure_when( value = get_value(meas, d, i); //d->v_compdata[i].cx_real; else value = d->v_realdata[i]; - scaleValue = dScale->v_compdata[i].cx_real; + if (dScale->v_compdata) + scaleValue = dScale->v_compdata[i].cx_real; + else + scaleValue = dScale->v_realdata[i]; } else if (sp_check) { if (d->v_compdata) value = get_value(meas, d, i); //d->v_compdata[i].cx_real; @@ -688,7 +691,10 @@ measure_at( value = d->v_realdata[i]; // fprintf(cp_err, "Warning: 'meas ac' input vector is real!\n"); } - svalue = dScale->v_compdata[i].cx_real; + if (dScale->v_compdata) + svalue = dScale->v_compdata[i].cx_real; + else + svalue = dScale->v_realdata[i]; //prevent crash in case if buggy input } else if (sp_check) { if (d->v_compdata) value = get_value(meas, d, i); //d->v_compdata[i].cx_real; @@ -768,22 +774,40 @@ measure_minMaxAvg( if (ac_check || sp_check) { dScale = vec_get("frequency"); + if (dScale == NULL) { + fprintf(cp_err, "Error: meas %s ...\n", meas->m_analysis); + fprintf(cp_err, " no such scale vector as frequency.\n"); + return MEASUREMENT_FAILURE; + } } else if (tran_check) { dScale = vec_get("time"); + if (dScale == NULL) { + fprintf(cp_err, "Error: meas %s ...\n", meas->m_analysis); + fprintf(cp_err, " no such scale vector as time.\n"); + return MEASUREMENT_FAILURE; + } } else if (dc_check) { dScale = vec_get("v-sweep"); + if (!dScale) { + dScale = vec_get("i-sweep"); + if (!dScale) { + dScale = vec_get("temp-sweep"); + if (!dScale) + dScale = vec_get("res-sweep"); + } + } + if (dScale == NULL) { + fprintf(cp_err, "Error: meas %s ...\n", meas->m_analysis); + fprintf(cp_err, " no such scale vector as v-sweep, i-sweep, temp-sweep, or res-sweep.\n"); + return MEASUREMENT_FAILURE; + } } else { /* error */ fprintf(cp_err, "Error: no such analysis type as %s.\n", meas->m_analysis); return MEASUREMENT_FAILURE; } - if (dScale == NULL) { - fprintf(cp_err, "Error: no such vector as time, frequency or v-sweep.\n"); - return MEASUREMENT_FAILURE; - } - if (dScale->v_realdata == NULL && dScale->v_compdata == NULL) { - fprintf(cp_err, "Error: scale vector time, frequency or v-sweep has no data.\n"); + fprintf(cp_err, "Error: scale vector time, frequency or ?-sweep has no data.\n"); return MEASUREMENT_FAILURE; } @@ -949,22 +973,40 @@ measure_rms_integral( if (ac_check || sp_check) { xScale = vec_get("frequency"); + if (xScale == NULL) { + fprintf(cp_err, "Error: meas %s ...\n", meas->m_analysis); + fprintf(cp_err, " no such scale vector as frequency.\n"); + return MEASUREMENT_FAILURE; + } } else if (tran_check) { xScale = vec_get("time"); + if (xScale == NULL) { + fprintf(cp_err, "Error: meas %s ...\n", meas->m_analysis); + fprintf(cp_err, " no such scale vector as time.\n"); + return MEASUREMENT_FAILURE; + } } else if (dc_check) { xScale = vec_get("v-sweep"); + if (!xScale) { + xScale = vec_get("i-sweep"); + if (!xScale) { + xScale = vec_get("temp-sweep"); + if (!xScale) + xScale = vec_get("res-sweep"); + } + } + if (xScale == NULL) { + fprintf(cp_err, "Error: meas %s ...\n", meas->m_analysis); + fprintf(cp_err, " no such scale vector as v-sweep, i-sweep, temp-sweep, or res-sweep.\n"); + return MEASUREMENT_FAILURE; + } } else { /* error */ fprintf(cp_err, "Error: no such analysis type as %s.\n", meas->m_analysis); return MEASUREMENT_FAILURE; } - if (xScale == NULL) { - fprintf(cp_err, "Error: no such vector as time, frequency or v-sweep.\n"); - return MEASUREMENT_FAILURE; - } - if (xScale->v_realdata == NULL && xScale->v_compdata == NULL) { - fprintf(cp_err, "Error: scale vector time, frequency or v-sweep has no data.\n"); + fprintf(cp_err, "Error: scale vector time, frequency or ?-sweep has no data.\n"); return MEASUREMENT_FAILURE; } diff --git a/src/maths/poly/interpolate.c b/src/maths/poly/interpolate.c index a736aa15d..cbcd31bf8 100644 --- a/src/maths/poly/interpolate.c +++ b/src/maths/poly/interpolate.c @@ -133,7 +133,7 @@ ft_interpolate(double *data, double *ndata, double *oscale, int olen, /* Now plot the rest, piece by piece. l is the * last element under consideration. */ - for (++l; l < olen; l++) { + for (++l; l < olen && lastone < nlen - 1; l++) { double out; /* Shift the old stuff by one and get another value. */ diff --git a/src/spicelib/devices/bsim3v1/b3v1ld.c b/src/spicelib/devices/bsim3v1/b3v1ld.c index 61362a3d0..79629f3eb 100644 --- a/src/spicelib/devices/bsim3v1/b3v1ld.c +++ b/src/spicelib/devices/bsim3v1/b3v1ld.c @@ -121,7 +121,10 @@ double Cgg1, Cgb1, Cgd1, Cbg1, Cbb1, Cbd1, Qac0, Qsub0; double dQac0_dVg, dQac0_dVd, dQac0_dVb, dQsub0_dVg, dQsub0_dVd, dQsub0_dVb; double m = 1.0; - +#ifndef NEWCONV +double tol; +#endif + struct bsim3v1SizeDependParam *pParam; int ByPass, Check, ChargeComputationNeeded = 0, error; diff --git a/src/spicelib/devices/bsimsoi/b4soild.c b/src/spicelib/devices/bsimsoi/b4soild.c index 29e4a7caa..f0379fd3c 100644 --- a/src/spicelib/devices/bsimsoi/b4soild.c +++ b/src/spicelib/devices/bsimsoi/b4soild.c @@ -487,6 +487,9 @@ int B4SOILoadOMP(B4SOIinstance *here, CKTcircuit *ckt) { double eggbcp2, eggdep, agb1, bgb1, agb2, bgb2, agbc2n, agbc2p, bgbc2n, bgbc2p, Vtm00; /* v4.3.1 bugfix for mtrlMod=1 -Tanvir */ double m; +#ifndef NEWCONV + double tol; +#endif #ifndef USE_OMP for (; model != NULL; model = B4SOInextModel(model)) diff --git a/src/spicelib/devices/hisim2/hsm2ld.c b/src/spicelib/devices/hisim2/hsm2ld.c index cf694177a..d72a8459b 100644 --- a/src/spicelib/devices/hisim2/hsm2ld.c +++ b/src/spicelib/devices/hisim2/hsm2ld.c @@ -853,7 +853,6 @@ tm0 = gtodsecld() ; isConv = 0; } } - } #endif /* NEWCONV */ } } diff --git a/src/spicelib/devices/res/resmpar.c b/src/spicelib/devices/res/resmpar.c index 8166b6bff..35df4c7ce 100644 --- a/src/spicelib/devices/res/resmpar.c +++ b/src/spicelib/devices/res/resmpar.c @@ -79,7 +79,7 @@ RESmParam(int param, IFvalue *value, GENmodel *inModel) model->RESefGiven = TRUE; break; case RES_MOD_R: - if ( value->rValue > 1e-03 ) { + if ( value->rValue > 0 ) { model->RESres = value->rValue; model->RESresGiven = TRUE; } diff --git a/src/spicelib/devices/res/restemp.c b/src/spicelib/devices/res/restemp.c index 993a7795f..0d0a0b61f 100644 --- a/src/spicelib/devices/res/restemp.c +++ b/src/spicelib/devices/res/restemp.c @@ -69,7 +69,7 @@ RESupdate_conduct(RESinstance *here, bool spill_warnings) } else { if (spill_warnings) SPfrontEnd->IFerrorf (ERR_WARNING, - "%s: resistance to low, set to 1 mOhm", here->RESname); + "%s: resistance too low or not given, set to 1 mOhm", here->RESname); here->RESresist = 1e-03; } } diff --git a/src/spicelib/devices/vsrc/vsrctemp.c b/src/spicelib/devices/vsrc/vsrctemp.c index 413e356e9..359e0bdc6 100644 --- a/src/spicelib/devices/vsrc/vsrctemp.c +++ b/src/spicelib/devices/vsrc/vsrctemp.c @@ -76,7 +76,7 @@ VSRCtemp(GENmodel *inModel, CKTcircuit *ckt) if (!here->VSRCportZ0Given) here->VSRCportZ0 = 50.0; - here->VSRCisPort = here->VSRCportZ0 > 0.0; + here->VSRCisPort = here->VSRCportZ0 > 0.0 && here->VSRCportNum > 0; } else here->VSRCisPort = FALSE; diff --git a/src/spicelib/parser/inp2c.c b/src/spicelib/parser/inp2c.c index 7ef15766f..3fc4da4ed 100644 --- a/src/spicelib/parser/inp2c.c +++ b/src/spicelib/parser/inp2c.c @@ -32,7 +32,7 @@ void INP2C(CKTcircuit *ckt, INPtables * tab, struct card *current) int error1; /* secondary error code temporary */ INPmodel *thismodel; /* pointer to model structure describing our model */ GENmodel *mdfast = NULL; /* pointer to the actual model */ - GENinstance *fast; /* pointer to the actual instance */ + GENinstance *fast = NULL;/* pointer to the actual instance */ IFvalue ptemp; /* a value structure to package resistance into */ int waslead; /* flag to indicate that funny unlabeled number was found */ double leadval; /* actual value of unlabeled number */ @@ -49,11 +49,25 @@ void INP2C(CKTcircuit *ckt, INPtables * tab, struct card *current) } } line = current->line; - INPgetNetTok(&line, &name, 1); + + INPgetNetTok(&line, &name, 1); /* Cname */ + if (*line == '\0') { + fprintf(stderr, "\nWarning: '%s' is not a valid capacitor instance line, ignored!\n\n", current->line); + return; + } + INPgetNetTok(&line, &nname1, 1); /* */ + if (*line == '\0') { + fprintf(stderr, "\nWarning: '%s' is not a valid capacitor instance line, ignored!\n\n", current->line); + return; + } + INPgetNetTok(&line, &nname2, 1); /* */ + if (*line == '\0') { + fprintf(stderr, "\nWarning: '%s' is not a valid capacitor instance line, ignored!\n\n", current->line); + return; + } + INPinsert(&name, tab); - INPgetNetTok(&line, &nname1, 1); INPtermInsert(ckt, &nname1, tab, &node1); - INPgetNetTok(&line, &nname2, 1); INPtermInsert(ckt, &nname2, tab, &node2); /* enable reading values like 4u7 */ @@ -109,7 +123,12 @@ void INP2C(CKTcircuit *ckt, INPtables * tab, struct card *current) #endif } } - + + if (!fast || !fast->GENmodPtr) { + fprintf(stderr, "\nWarning: Instance for capacitor '%s' could not be set up properly, ignored!\n\n", current->line); + return; + } + if (error1 == 0) { /* Looks like a number */ ptemp.rValue = val; GCA(INPpName, ("capacitance", &ptemp, ckt, type, fast)); diff --git a/src/spicelib/parser/inp2l.c b/src/spicelib/parser/inp2l.c index da66650f0..adfd885b3 100644 --- a/src/spicelib/parser/inp2l.c +++ b/src/spicelib/parser/inp2l.c @@ -32,7 +32,7 @@ void INP2L(CKTcircuit *ckt, INPtables * tab, struct card *current) int error1; /* secondary error code temporary */ INPmodel *thismodel; /* pointer to model structure describing our model */ GENmodel *mdfast = NULL; /* pointer to the actual model */ - GENinstance *fast; /* pointer to the actual instance */ + GENinstance *fast = NULL;/* pointer to the actual instance */ IFvalue ptemp; /* a value structure to package inductance into */ int waslead; /* flag to indicate that funny unlabeled number was found */ double leadval; /* actual value of unlabeled number */ @@ -49,14 +49,25 @@ void INP2L(CKTcircuit *ckt, INPtables * tab, struct card *current) } } line = current->line; - INPgetNetTok(&line, &name, 1); - INPinsert(&name, tab); - INPgetNetTok(&line, &nname1, 1); - INPtermInsert(ckt, &nname1, tab, &node1); - INPgetNetTok(&line, &nname2, 1); - INPtermInsert(ckt, &nname2, tab, &node2); + INPgetNetTok(&line, &name, 1); /* Lname */ + if (*line == '\0') { + fprintf(stderr, "\nWarning: '%s' is not a valid inductor instance line, ignored!\n\n", current->line); + return; + } + INPgetNetTok(&line, &nname1, 1); /* */ + if (*line == '\0') { + fprintf(stderr, "\nWarning: '%s' is not a valid inductor instance line, ignored!\n\n", current->line); + return; + } + INPgetNetTok(&line, &nname2, 1); /* */ + if (*line == '\0') { + fprintf(stderr, "\nWarning: '%s' is not a valid inductor instance line, ignored!\n\n", current->line); + return; + } -// val = INPevaluate(&line, &error1, 1); + INPinsert(&name, tab); + INPtermInsert(ckt, &nname1, tab, &node1); + INPtermInsert(ckt, &nname2, tab, &node2); /* enable reading values like 4u7 */ if (newcompat.lt) @@ -110,7 +121,12 @@ void INP2L(CKTcircuit *ckt, INPtables * tab, struct card *current) #endif } } - + + if (!fast || !fast->GENmodPtr) { + fprintf(stderr, "\nWarning: Instance for inductor '%s' could not be set up properly, ignored!\n\n", current->line); + return; + } + if (error1 == 0) { /* Looks like a number */ ptemp.rValue = val; GCA(INPpName, ("inductance", &ptemp, ckt, type, fast)); diff --git a/src/spicelib/parser/inp2r.c b/src/spicelib/parser/inp2r.c index 587f940a5..5241b3035 100644 --- a/src/spicelib/parser/inp2r.c +++ b/src/spicelib/parser/inp2r.c @@ -39,7 +39,7 @@ void INP2R(CKTcircuit *ckt, INPtables * tab, struct card *current) int error1; /* secondary error code temporary */ INPmodel *thismodel; /* pointer to model structure describing our model */ GENmodel *mdfast = NULL; /* pointer to the actual model */ - GENinstance *fast; /* pointer to the actual instance */ + GENinstance *fast = NULL; /* pointer to the actual instance */ IFvalue ptemp; /* a value structure to package resistance into */ int waslead; /* flag to indicate that funny unlabeled number was found */ double leadval; /* actual value of unlabeled number */ @@ -59,10 +59,23 @@ void INP2R(CKTcircuit *ckt, INPtables * tab, struct card *current) } line = current->line; INPgetNetTok(&line, &name, 1); /* Rname */ - INPinsert(&name, tab); + if (*line == '\0') { + fprintf(stderr, "\nWarning: '%s' is not a valid resistor instance line, ignored!\n\n", current->line); + return; + } INPgetNetTok(&line, &nname1, 1); /* */ - INPtermInsert(ckt, &nname1, tab, &node1); + if (*line == '\0') { + fprintf(stderr, "\nWarning: '%s' is not a valid resistor instance line, ignored!\n\n", current->line); + return; + } INPgetNetTok(&line, &nname2, 1); /* */ + if (*line == '\0') { + fprintf(stderr, "\nWarning: '%s' is not a valid resistor instance line, ignored!\n\n", current->line); + return; + } + + INPinsert(&name, tab); + INPtermInsert(ckt, &nname1, tab, &node1); INPtermInsert(ckt, &nname2, tab, &node2); /* enable reading values like 4k7 */ @@ -197,6 +210,11 @@ void INP2R(CKTcircuit *ckt, INPtables * tab, struct card *current) } } + if (!fast || !fast->GENmodPtr) { + fprintf(stderr, "\nWarning: Instance for resistor '%s' could not be set up properly, ignored!\n\n", current->line); + return; + } + if (error1 == 0) { /* got a resistance above */ ptemp.rValue = val; GCA(INPpName, ("resistance", &ptemp, ckt, type, fast));