From db9711daf4dd3080ec91191d3841ace4a7f49ec6 Mon Sep 17 00:00:00 2001 From: dwarning Date: Sat, 8 Apr 2023 17:29:25 +0200 Subject: [PATCH 01/72] use true vector size for memcpy --- src/spicelib/devices/vbic/vbicload.c | 2 +- src/spicelib/devices/vbic/vbictemp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spicelib/devices/vbic/vbicload.c b/src/spicelib/devices/vbic/vbicload.c index af723c4b8..da41d6a05 100644 --- a/src/spicelib/devices/vbic/vbicload.c +++ b/src/spicelib/devices/vbic/vbicload.c @@ -129,7 +129,7 @@ VBICload(GENmodel *inModel, CKTcircuit *ckt) /* * model parameters */ - memcpy (&p, &model->VBICtnom, 108*8); + memcpy (&p, &model->VBICtnom, sizeof(p)); p[0] = here->VBICtemp - CONSTCtoK + p[105]; /* temperature dependent parameter are already calculated */ diff --git a/src/spicelib/devices/vbic/vbictemp.c b/src/spicelib/devices/vbic/vbictemp.c index 84cb2121b..97126bbde 100644 --- a/src/spicelib/devices/vbic/vbictemp.c +++ b/src/spicelib/devices/vbic/vbictemp.c @@ -42,7 +42,7 @@ VBICtemp(GENmodel *inModel, CKTcircuit *ckt) TAMB = here->VBICtemp - CONSTCtoK; - memcpy (&pnom, &model->VBICtnom, 108*8); + memcpy (&pnom, &model->VBICtnom, sizeof(pnom)); iret = vbic_4T_et_cf_t(p,pnom,&TAMB); From af1963fc394904d09317c5a205ed693d56447382 Mon Sep 17 00:00:00 2001 From: dwarning Date: Sat, 8 Apr 2023 20:44:19 +0200 Subject: [PATCH 02/72] selfheating only with rth>0 --- src/spicelib/devices/vbic/vbicsetup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spicelib/devices/vbic/vbicsetup.c b/src/spicelib/devices/vbic/vbicsetup.c index c82f36871..f40a59988 100644 --- a/src/spicelib/devices/vbic/vbicsetup.c +++ b/src/spicelib/devices/vbic/vbicsetup.c @@ -469,7 +469,7 @@ VBICsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) } if(model->VBICselftGiven) - if(model->VBICselft == 1) + if((model->VBICselft == 1) && (model->VBICthermalResistGiven) && (model->VBICthermalResist > 0.0)) here->VBIC_selfheat = 1; else here->VBIC_selfheat = 0; From fc97e658b083328c2ecd27b767ac8c13f916a813 Mon Sep 17 00:00:00 2001 From: dwarning Date: Sat, 8 Apr 2023 21:20:26 +0200 Subject: [PATCH 03/72] more realistic self-heating example --- examples/vbic/self-heat.sp | 47 ++++++++------------------------------ 1 file changed, 10 insertions(+), 37 deletions(-) diff --git a/examples/vbic/self-heat.sp b/examples/vbic/self-heat.sp index 02a9695d1..93ceb9195 100644 --- a/examples/vbic/self-heat.sp +++ b/examples/vbic/self-heat.sp @@ -1,7 +1,6 @@ VBIC Output Test Ic=f(Vc,Ib) vs self heating -.option absmos=1e-12 relmos=1e-6 relv=1e-6 absv=1e-9 post vc c 0 0 -vb b 0 1 +ib 0 b 10u ve e 0 0 vs s 0 0 vc1 c c1 0 @@ -9,42 +8,16 @@ vb1 b b1 0 ve1 e e1 0 vs1 s s1 0 .temp 27 -Q1 c1 b1 e1 s1 t mod1 area=1 -.model mod1 npn Level=4 -+ Tnom=27 RCX=10 RCI=60 VO=2 GAMM=2.e-11 -+ HRCF=2 RBX=10 RBI=40 RE=2 -+ RS=20 RBP=40 IS=1e-16 NF=1.00000e+00 -+ NR=1.00000e+00 FC=9.00000e-01 CBEO=0 -+ CJE=1.e-13 PE=0.75 ME=0.33 -+ AJE=-5.00000e-01 CBCO=0 CJC=2e-14 -+ QCO=1e-12 CJEP=1e-13 PC=7.50000e-01 -+ MC=3.30000e-01 AJC=-5.00000e-01 CJCP=4e-13 -+ PS=7.50000e-01 MS=3.30000e-01 AJS=-5.00000e-01 -+ IBEI=1e-18 WBE=1.0000 NEI=1.00000e+00 -+ IBEN=5e-15 NEN=2.00000e+00 IBCI=2e-17 -+ NCI=1.00000e+00 IBCN=5e-15 NCN=2.00000e+00 -+ AVC1=2 AVC2=15 ISP=1e-15 -+ WSP=1.000e+00 NFP=1.00000e+00 IBEIP=0 -+ IBENP=0 IBCIP=0 NCIP=1.00000e+00 -+ IBCNP=0 NCNP=2.00000e+00 VEF=10 -+ VER=4 IKF=0.002 IKR=0.0002 IKP=0.0002 -+ TF=1.e-11 QTF=0 XTF=20 -+ VTF=0 ITF=0.08 TR=1e-10 -+ KFN=0 AFN=1.0e+00 -+ BFN=1.0000e+00 XRE=0 XRB=0 -+ XRC=0 XRS=0 XVO=0 -+ EA=1.12000e+00 EAIE=1.12000e+00 -+ EANE=1.12000e+00 EANC=1.12000e+00 -+ EANS=1.12000e+00 XIS=3.00000e+00 -+ XII=3.00000e+00 XIN=3.00000e+00 -+ TNF=0 TAVC=0 -+ RTH=300 CTH=0 -+ TD=0 -*+ TD=2.e-11 +Q1 c1 b1 e1 s1 dt M_BFP780 area=1 + +.include Infineon_VBIC.lib + .control -dc vc 0.0 5.0001 0.05 vb 0.7 1.0001 0.05 -altermod @mod1[RTH]=0 -dc vc 0.0 5.0001 0.05 vb 0.7 1.0001 0.05 +dc vc 0.0 5.0 0.05 ib 50u 500u 50u +settype temperature v(dt) +plot v(dt) +altermod @M_BFP780[RTH]=0 +dc vc 0.0 5.0 0.05 ib 50u 500u 50u plot dc1.vc1#branch dc2.vc1#branch .endc .end From add9b1d77fab19181ae0fcdb26a77fd3d0ae23c4 Mon Sep 17 00:00:00 2001 From: dwarning Date: Mon, 10 Apr 2023 11:36:20 +0200 Subject: [PATCH 04/72] not to forget the overlap capacitances in AC --- src/spicelib/devices/vbic/vbicacld.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/spicelib/devices/vbic/vbicacld.c b/src/spicelib/devices/vbic/vbicacld.c index 0844fccd0..3faed1866 100644 --- a/src/spicelib/devices/vbic/vbicacld.c +++ b/src/spicelib/devices/vbic/vbicacld.c @@ -30,7 +30,7 @@ VBICacLoad(GENmodel *inModel, CKTcircuit *ckt) ,Ibcp_Vbcp,Iccp_Vbep,Irs_Vrs,Iccp_Vbci,Iccp_Vbcp; double XQbe_Vbei, XQbe_Vbci, XQbex_Vbex, XQbc_Vbci, XQbcx_Vbcx, XQbep_Vbep, XQbep_Vbci, - XQbcp_Vbcp; + XQbcp_Vbcp, XQbeo_Vbe, XQbco_Vbc; /* loop through all the models */ for( ; model != NULL; model = VBICnextModel(model)) { @@ -229,6 +229,8 @@ c The complex part XQbep_Vbep = *(ckt->CKTstate0 + here->VBICcqbep) * ckt->CKTomega; XQbep_Vbci = *(ckt->CKTstate0 + here->VBICcqbepci) * ckt->CKTomega; XQbcp_Vbcp = *(ckt->CKTstate0 + here->VBICcqbcp) * ckt->CKTomega; + XQbeo_Vbe = *(ckt->CKTstate0 + here->VBICcqbeo) * ckt->CKTomega; + XQbco_Vbc = *(ckt->CKTstate0 + here->VBICcqbco) * ckt->CKTomega; /* c Stamp element: Qbe */ @@ -279,6 +281,21 @@ c Stamp element: Qbcp *(here->VBICsubsSIBaseBPPtr + 1) += -XQbcp_Vbcp; *(here->VBICbaseBPSubsSIPtr + 1) += -XQbcp_Vbcp; *(here->VBICbaseBPBaseBPPtr + 1) += XQbcp_Vbcp; +/* +c Stamp element: Qbeo +*/ + *(here->VBICbaseBasePtr + 1) += XQbeo_Vbe; + *(here->VBICemitEmitPtr + 1) += XQbeo_Vbe; + *(here->VBICbaseEmitPtr + 1) += -XQbeo_Vbe; + *(here->VBICemitBasePtr + 1) += -XQbeo_Vbe; +/* +c Stamp element: Qbco +*/ + *(here->VBICbaseBasePtr + 1) += XQbco_Vbc; + *(here->VBICcollCollPtr + 1) += XQbco_Vbc; + *(here->VBICbaseCollPtr + 1) += -XQbco_Vbc; + *(here->VBICcollBasePtr + 1) += -XQbco_Vbc; + } } From 3d0fab9c55b9a0884af6c6d5b1ad21dbcddf99a0 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 12 Apr 2023 13:40:05 +0200 Subject: [PATCH 05/72] Prevent reading from NULL when user input is something like .ic=v --- src/spicelib/parser/inppas3.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/spicelib/parser/inppas3.c b/src/spicelib/parser/inppas3.c index d1eaf6b13..f1d97b7b8 100644 --- a/src/spicelib/parser/inppas3.c +++ b/src/spicelib/parser/inppas3.c @@ -148,6 +148,8 @@ INPpas3(CKTcircuit *ckt, struct card *data, INPtables *tab, TSKtask *task, FREE(name); /* Gobble the rest of the token */ line = nexttok(line); + if (!line) + break; continue; } ptemp.rValue = INPevaluate(&line,&error,1); From c8a7f07ac164421b2f0fbbeeb4fc3938a797c88b Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 15 Apr 2023 10:52:59 +0200 Subject: [PATCH 06/72] A preliminary fix to reduce the amount of missing pulses considerably. Probably not yet the final solution. --- src/xspice/icm/digital/d_pwm/cfunc.mod | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/xspice/icm/digital/d_pwm/cfunc.mod b/src/xspice/icm/digital/d_pwm/cfunc.mod index 4aa5ec6be..8ed3930b1 100644 --- a/src/xspice/icm/digital/d_pwm/cfunc.mod +++ b/src/xspice/icm/digital/d_pwm/cfunc.mod @@ -404,6 +404,8 @@ void cm_d_pwm(ARGS) *t3 = T(1) + (1 - dphase)/frequency; } + cm_analog_set_temp_bkpt(*t1); + cm_analog_set_temp_bkpt(*t3); } break; From 4e5159856214844f2b7bc69cebd223b026765431 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 15 Apr 2023 11:10:25 +0200 Subject: [PATCH 07/72] Make voltage ramp smooth around 0 and around end of ramp. --- src/spicelib/analysis/optran.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spicelib/analysis/optran.c b/src/spicelib/analysis/optran.c index aceddbc2c..175d96146 100644 --- a/src/spicelib/analysis/optran.c +++ b/src/spicelib/analysis/optran.c @@ -657,7 +657,7 @@ resume: /* supply ramping, when opramptime > 0 */ if (opramptime > 0) - ckt->CKTsrcFact = MIN(1., optime / opramptime); + ckt->CKTsrcFact = 0.5 * (1 - cos(M_PI * optime / opramptime)); ckt->CKTdeltaOld[0]=ckt->CKTdelta; NIcomCof(ckt); From 9f2192e7113d4831a31a6ca9376325deb4f05be2 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Sat, 8 Apr 2023 16:36:23 -0700 Subject: [PATCH 08/72] Create correct translations of degenerate compound gates with $d_hi/$d_lo inputs. --- src/frontend/udevices.c | 76 ++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/src/frontend/udevices.c b/src/frontend/udevices.c index 60677cea4..7b6399e59 100644 --- a/src/frontend/udevices.c +++ b/src/frontend/udevices.c @@ -209,6 +209,7 @@ struct name_entry { }; static char *get_zero_rise_fall(void); +static char *get_name_hilo(char *tok_str); #ifdef TRACE static void print_name_list(NAME_ENTRY nelist); @@ -2126,13 +2127,16 @@ static Xlatorp gen_compound_instance(struct compound_instance *compi) char *model_name = NULL, *inst = NULL, **connector = NULL; char *new_inst = NULL, *model_stmt = NULL, *final_model_name = NULL; char *new_stmt = NULL, *instance_name = NULL; - char *tmp; + char *high_name = NULL, *low_name = NULL; char *zero_delay_str = NULL; - size_t sz = 0; Xlatorp xxp = NULL; Xlatep xdata = NULL; + DS_CREATE(tmp_dstr, 128); - if (!compi) { return NULL; } + if (!compi) { + ds_free(&tmp_dstr); + return NULL; + } itype = compi->hdrp->instance_type; inst = compi->hdrp->instance_name; if (eq(itype, "aoi")) { @@ -2152,6 +2156,7 @@ static Xlatorp gen_compound_instance(struct compound_instance *compi) ingates = "d_or"; logic_val = "$d_lo"; } else { + ds_free(&tmp_dstr); return NULL; } inarr = compi->inputs; @@ -2164,33 +2169,38 @@ static Xlatorp gen_compound_instance(struct compound_instance *compi) xxp = create_xlator(); k = 0; for (i = 0; i < num_gates; i++) { - for (j = 0; j < width; j++) { - sz += strlen(inarr[k]) + 8; // Room for space between each name - k++; - } - } - tmp = TMALLOC(char, sz); - tmp[0] = '\0'; - k = 0; - for (i = 0; i < num_gates; i++) { + ds_clear(&tmp_dstr); connector[i] = tprintf("con_%s_%d", inst, i); check_name_unused(connector[i]); num_ins_kept = 0; - tmp[0] = '\0'; /* $d_hi AND gate inputs are ignored */ /* $d_lo OR gate inputs are ignored */ for (j = 0; j < width; j++) { if (!eq(inarr[k], logic_val)) { num_ins_kept++; - sprintf(tmp + strlen(tmp), " %s", inarr[k]); - add_input_pin(inarr[k]); + if (eq(inarr[k], "$d_hi")) { + /* This must be a 1 input on an OR gate of oa/oai */ + if (!high_name) { + high_name = get_name_hilo("$d_hi"); + } + ds_cat_printf(&tmp_dstr, " %s", high_name); + } else if (eq(inarr[k], "$d_lo")) { + /* This must be a 0 input on an AND gate of ao/aoi */ + if (!low_name) { + low_name = get_name_hilo("$d_lo"); + } + ds_cat_printf(&tmp_dstr, " %s", low_name); + } else { + ds_cat_printf(&tmp_dstr, " %s", inarr[k]); + add_input_pin(inarr[k]); + } } k++; } if (num_ins_kept >= 2) { instance_name = tprintf("a%s_%d", inst, i); new_inst = tprintf("%s [%s ] %s %s", instance_name, - tmp, connector[i], model_name); + ds_get_buf(&tmp_dstr), connector[i], model_name); xdata = create_xlate_translated(new_inst); xxp = add_xlator(xxp, xdata); tfree(new_inst); @@ -2201,7 +2211,22 @@ static Xlatorp gen_compound_instance(struct compound_instance *compi) directly to the OR/NOR, AND/NAND final gate. */ tfree(connector[i]); - connector[i] = tprintf("%s", tmp); + connector[i] = tprintf("%s", ds_get_buf(&tmp_dstr)); + } else { + tfree(connector[i]); + if (eq(ingates, "d_or")) { + /* Current oa/oai input OR gate has all 0 inputs, so drive 0 */ + if (!low_name) { + low_name = get_name_hilo("$d_lo"); + } + connector[i] = tprintf("%s", low_name); + } else { + /* Current ao/aoi input AND gate has all 1 inputs, so drive 1 */ + if (!high_name) { + high_name = get_name_hilo("$d_hi"); + } + connector[i] = tprintf("%s", high_name); + } } } /* .model statement for the input gates */ @@ -2215,27 +2240,19 @@ static Xlatorp gen_compound_instance(struct compound_instance *compi) /* Final OR/NOR, AND/NAND gate */ final_model_name = tprintf("%s_out", model_name); - tfree(tmp); - - sz = 0; + ds_clear(&tmp_dstr); for (i = 0; i < num_gates; i++) { - sz += strlen(connector[i]) + 8; // Room for space between each name - } - tmp = TMALLOC(char, sz); - tmp[0] = '\0'; - for (i = 0; i < num_gates; i++) { - sprintf(tmp + strlen(tmp), " %s", connector[i]); + ds_cat_printf(&tmp_dstr, " %s", connector[i]); } /* instance statement for the final gate */ add_output_pin(output); instance_name = tprintf("a%s_out", inst); new_stmt = tprintf("%s [%s ] %s %s", - instance_name, tmp, output, final_model_name); + instance_name, ds_get_buf(&tmp_dstr), output, final_model_name); xdata = create_xlate_translated(new_stmt); xxp = add_xlator(xxp, xdata); tfree(new_stmt); tfree(instance_name); - tfree(tmp); /* timing model for output gate */ if (!gen_timing_model(tmodel, "ugate", outgate, final_model_name, xxp)) { @@ -2249,6 +2266,9 @@ static Xlatorp gen_compound_instance(struct compound_instance *compi) } if (connector) { tfree(connector); } tfree(model_name); + if (high_name) { tfree(high_name); } + if (low_name) { tfree(low_name); } + ds_free(&tmp_dstr); return xxp; } From 601d4bf57db832e429a4853e260139deeff900a9 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Sun, 9 Apr 2023 09:57:55 -0700 Subject: [PATCH 09/72] Allocate compound gate connectors where needed. --- src/frontend/udevices.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/frontend/udevices.c b/src/frontend/udevices.c index 7b6399e59..cfe27e84d 100644 --- a/src/frontend/udevices.c +++ b/src/frontend/udevices.c @@ -2170,8 +2170,6 @@ static Xlatorp gen_compound_instance(struct compound_instance *compi) k = 0; for (i = 0; i < num_gates; i++) { ds_clear(&tmp_dstr); - connector[i] = tprintf("con_%s_%d", inst, i); - check_name_unused(connector[i]); num_ins_kept = 0; /* $d_hi AND gate inputs are ignored */ /* $d_lo OR gate inputs are ignored */ @@ -2198,6 +2196,8 @@ static Xlatorp gen_compound_instance(struct compound_instance *compi) k++; } if (num_ins_kept >= 2) { + connector[i] = tprintf("con_%s_%d", inst, i); + check_name_unused(connector[i]); instance_name = tprintf("a%s_%d", inst, i); new_inst = tprintf("%s [%s ] %s %s", instance_name, ds_get_buf(&tmp_dstr), connector[i], model_name); @@ -2210,10 +2210,8 @@ static Xlatorp gen_compound_instance(struct compound_instance *compi) connector[i] is the remaining input connected directly to the OR/NOR, AND/NAND final gate. */ - tfree(connector[i]); connector[i] = tprintf("%s", ds_get_buf(&tmp_dstr)); } else { - tfree(connector[i]); if (eq(ingates, "d_or")) { /* Current oa/oai input OR gate has all 0 inputs, so drive 0 */ if (!low_name) { From 77afc678ddfa7c8da8af316cab8c9d6108617c20 Mon Sep 17 00:00:00 2001 From: dwarning Date: Sat, 15 Apr 2023 13:49:51 +0200 Subject: [PATCH 10/72] prevent unitialized variables --- src/spicelib/devices/vbic/vbicload.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/spicelib/devices/vbic/vbicload.c b/src/spicelib/devices/vbic/vbicload.c index da41d6a05..b0c7efff4 100644 --- a/src/spicelib/devices/vbic/vbicload.c +++ b/src/spicelib/devices/vbic/vbicload.c @@ -75,8 +75,8 @@ VBICload(GENmodel *inModel, CKTcircuit *ckt) ,Iccp_Vbci,Iccp_Vbcp,Irs,Irs_Vrs,Irs_Vrth=0.0,Qbcp,Qbcp_Vrth ,Qbcp_Vbcp,Irth,Irth_Vrth=0.0,Ith=0.0,Ith_Vrth=0.0,Ith_Vbei=0.0,Ith_Vbci=0.0 ,Ith_Vcei=0.0,Ith_Vbex=0.0,Ith_Vbep=0.0,Ith_Vrs=0.0,Ith_Vbcp=0.0,Ith_Vcep=0.0,Ith_Vrcx=0.0 - ,Ith_Vrci=0.0,Ith_Vbcx=0.0,Ith_Vrbx=0.0,Ith_Vrbi=0.0,Ith_Vre=0.0,Ith_Vrbp=0.0,Qcth - ,Qcth_Vrth,SCALE; + ,Ith_Vrci=0.0,Ith_Vbcx=0.0,Ith_Vrbx=0.0,Ith_Vrbi=0.0,Ith_Vre=0.0,Ith_Vrbp=0.0,Qcth=0.0 + ,Qcth_Vrth=0.0,SCALE; int iret; double vce; #ifndef PREDICTOR @@ -714,7 +714,8 @@ VBICload(GENmodel *inModel, CKTcircuit *ckt) here->VBICcapbcx = Qbcx_Vbcx; here->VBICcapbep = Qbep_Vbep; here->VBICcapbcp = Qbcp_Vbcp; - here->VBICcapcth = Qcth_Vrth; + if (here->VBIC_selfheat) + here->VBICcapcth = Qcth_Vrth; /* * store small-signal parameters @@ -894,9 +895,11 @@ VBICload(GENmodel *inModel, CKTcircuit *ckt) *(ckt->CKTstate0 + here->VBICirbx_Vrbx) = Irbx_Vrbx; *(ckt->CKTstate0 + here->VBICirs_Vrs) = Irs_Vrs; *(ckt->CKTstate0 + here->VBICire_Vre) = Ire_Vre; - *(ckt->CKTstate0 + here->VBICcqcth) = Icth; - *(ckt->CKTstate0 + here->VBICicth_Vrth) = Icth_Vrth; - + if (here->VBIC_selfheat) + { + *(ckt->CKTstate0 + here->VBICcqcth) = Icth; + *(ckt->CKTstate0 + here->VBICicth_Vrth) = Icth_Vrth; + } load: /* * load current excitation vector and matrix From 4fed4bafa1948f094b2a6539c6d2143f1b5e3962 Mon Sep 17 00:00:00 2001 From: dwarning Date: Sat, 15 Apr 2023 16:57:33 +0200 Subject: [PATCH 11/72] few cleanings to prevent compiler warnings --- src/frontend/inpcom.c | 4 ---- src/frontend/subckt.c | 3 ++- src/maths/ni/nidest.c | 3 +-- src/maths/ni/niiter.c | 1 - 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index e2344177a..9fa67d8e8 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -136,7 +136,6 @@ static void inp_reorder_params( static int inp_split_multi_param_lines(struct card *deck, int line_number); static void inp_sort_params(struct card *param_cards, struct card *card_bf_start, struct card *s_c, struct card *e_c); -char *inp_remove_ws(char *s); static void inp_compat(struct card *deck); static void inp_bsource_compat(struct card *deck); static bool inp_temper_compat(struct card *card); @@ -167,7 +166,6 @@ static void inp_check_syntax(struct card *deck); static char *inp_spawn_brace(char *s); static char *inp_pathresolve_at(const char *name, const char *dir); -char *search_plain_identifier(char *str, const char *identifier); struct nscope *inp_add_levels(struct card *deck); static struct card_assoc *find_subckt(struct nscope *scope, const char *name); @@ -185,8 +183,6 @@ static char* eval_m(char* line, char* tline); static char* eval_tc(char* line, char* tline); static char* eval_mvalue(char* line, char* tline); -static void rem_double_braces(struct card* card); - extern void inp_probe(struct card* card); #ifndef EXT_ASC static void utf8_syntax_check(struct card *deck); diff --git a/src/frontend/subckt.c b/src/frontend/subckt.c index 9cd9db8d3..002fd9f1d 100644 --- a/src/frontend/subckt.c +++ b/src/frontend/subckt.c @@ -1165,7 +1165,6 @@ translate(struct card *deck, char *formal, int flen, char *actual, char *scname, } for (c = deck; c; c = c->nextcard) { - bool got_vnam = FALSE; char *s = c->line; char dev_type = tolower_c(s[0]); @@ -1249,6 +1248,8 @@ translate(struct card *deck, char *formal, int flen, char *actual, char *scname, /* gtri - add - wbk - 10/23/90 - process A devices specially */ /* since they have a more involved and variable length node syntax */ + bool got_vnam = FALSE; + case 'a': /* translate the instance name according to normal rules */ diff --git a/src/maths/ni/nidest.c b/src/maths/ni/nidest.c index 06827285c..0982e60f1 100644 --- a/src/maths/ni/nidest.c +++ b/src/maths/ni/nidest.c @@ -16,7 +16,6 @@ Author: 1985 Thomas L. Quarles void NIdestroy(CKTcircuit *ckt) { - int i; if (ckt->CKTmatrix) SMPdestroy(ckt->CKTmatrix); ckt->CKTmatrix = NULL; @@ -36,7 +35,7 @@ NIdestroy(CKTcircuit *ckt) #endif #ifdef PREDICTOR if(ckt->CKTpred) FREE(ckt->CKTpred); - for( i=0;i<8;i++) { + for(int i=0;i<8;i++) { if(ckt->CKTsols[i]) FREE(ckt->CKTsols[i]); } #endif diff --git a/src/maths/ni/niiter.c b/src/maths/ni/niiter.c index fd7966dc9..4979f0901 100644 --- a/src/maths/ni/niiter.c +++ b/src/maths/ni/niiter.c @@ -22,7 +22,6 @@ Modified: 2001 AlansFixes /* Limit the number of 'singular matrix' warnings */ static int msgcount = 0; -void NIresetwarnmsg(void); /* NIiter() - return value is non-zero for convergence failure */ From 7fc90a332ac5a2cf81a1798e45da1756afe302d5 Mon Sep 17 00:00:00 2001 From: dwarning Date: Sat, 15 Apr 2023 17:42:20 +0200 Subject: [PATCH 12/72] get the right place for variable declaration --- src/frontend/subckt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/frontend/subckt.c b/src/frontend/subckt.c index 002fd9f1d..6de79afd8 100644 --- a/src/frontend/subckt.c +++ b/src/frontend/subckt.c @@ -1147,7 +1147,9 @@ translate(struct card *deck, char *formal, int flen, char *actual, char *scname, char *next_name, *name, *t, *nametofree, *paren_ptr; int nnodes, i, dim; int rtn = 0; - +#ifdef XSPICE + bool got_vnam = FALSE; +#endif bxx_init(&buffer); /* settrans builds the table holding the translated netnames. */ @@ -1248,8 +1250,6 @@ translate(struct card *deck, char *formal, int flen, char *actual, char *scname, /* gtri - add - wbk - 10/23/90 - process A devices specially */ /* since they have a more involved and variable length node syntax */ - bool got_vnam = FALSE; - case 'a': /* translate the instance name according to normal rules */ From 200cff4bdc1d7c3d04e5cff86c19064725d4c0be Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 17 Apr 2023 11:54:25 +0200 Subject: [PATCH 13/72] Prevent reading from NULL --- src/spicelib/analysis/optran.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/spicelib/analysis/optran.c b/src/spicelib/analysis/optran.c index 175d96146..3f32263d2 100644 --- a/src/spicelib/analysis/optran.c +++ b/src/spicelib/analysis/optran.c @@ -100,6 +100,11 @@ void com_optran(wordlist* wl) { getdata = TRUE; } + if (!getdata && !ft_curckt) { + /* no circuit, but optran already set */ + return; + } + int saved = errno; errno = 0; nooptran = FALSE; From c179b0173488b4a7f45d1ed0095fdca7d41b050b Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 17 Apr 2023 13:53:37 +0200 Subject: [PATCH 14/72] Avoid user induced buffer overflows. Check against NULL pointer. --- src/spicelib/parser/inpptree.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/spicelib/parser/inpptree.c b/src/spicelib/parser/inpptree.c index 1f97cf082..4828c8fd4 100644 --- a/src/spicelib/parser/inpptree.c +++ b/src/spicelib/parser/inpptree.c @@ -1107,8 +1107,14 @@ INPparseNode *PT_mkfnode(const char *fname, INPparseNode * arg) INPparseNode *p; char buf[128]; + if (!fname) { + fprintf(stderr, "Error: bogus function name \n"); + return mkfirst(NULL, arg); + } + /* Make sure the case is ok. */ - (void) strcpy(buf, fname); + (void)strncpy(buf, fname, 127); + buf[127] = 0; strtolower(buf); if(!strcmp("ternary_fcn", buf)) { @@ -1142,7 +1148,6 @@ INPparseNode *PT_mkfnode(const char *fname, INPparseNode * arg) fprintf(stderr, "Error: no such function '%s'\n", buf); if (ft_stricterror) controlled_exit(EXIT_BAD); - return mkfirst(NULL, arg); } @@ -1250,7 +1255,8 @@ INPparseNode *PT_mksnode(const char *string, void *ckt) INPparseNode *p; /* Make sure the case is ok. */ - (void) strcpy(buf, string); + (void) strncpy(buf, string, 127); + buf[127] = 0; strtolower(buf); p = TMALLOC(INPparseNode, 1); From 9bc9d942445fb64765a6c4c1a02f6b347e588ea6 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 17 Apr 2023 15:00:28 +0200 Subject: [PATCH 15/72] Formatting --- src/spicelib/devices/cktinit.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/spicelib/devices/cktinit.c b/src/spicelib/devices/cktinit.c index 7fde41af6..92e83093b 100644 --- a/src/spicelib/devices/cktinit.c +++ b/src/spicelib/devices/cktinit.c @@ -29,16 +29,13 @@ CKTinit(CKTcircuit **ckt) /* new circuit to create */ CKTcircuit *sckt = TMALLOC(CKTcircuit, 1); *ckt = sckt; if (sckt == NULL) - return(E_NOMEM); -/* gtri - begin - dynamically allocate the array of model lists */ -/* CKThead used to be statically sized in CKTdefs.h, but has been changed */ -/* to a ** pointer */ + return(E_NOMEM); + + /* dynamically allocate the array of model lists */ sckt->CKThead = TMALLOC(GENmodel *, DEVmaxnum); - if(sckt->CKThead == NULL) return(E_NOMEM); -/* gtri - end - dynamically allocate the array of model lists */ + if(sckt->CKThead == NULL) + return(E_NOMEM); - - for (i = 0; i < DEVmaxnum; i++) sckt->CKThead[i] = NULL; From ee238b16327d4d15e16f66d5f19dc6b1e76475b2 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 17 Apr 2023 15:03:53 +0200 Subject: [PATCH 16/72] Remove linker warnings in MSVC --- src/osdi/osdisetup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/osdi/osdisetup.c b/src/osdi/osdisetup.c index 9699fd509..c3504cc38 100644 --- a/src/osdi/osdisetup.c +++ b/src/osdi/osdisetup.c @@ -186,7 +186,7 @@ int OSDIsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, OsdiInitInfo init_info; OsdiNgspiceHandle handle; GENmodel *gen_model; - int res; + int res = (OK); int error; CKTnode *tmp; GENinstance *gen_inst; @@ -304,7 +304,7 @@ extern int OSDItemp(GENmodel *inModel, CKTcircuit *ckt) { OsdiInitInfo init_info; OsdiNgspiceHandle handle; GENmodel *gen_model; - int res; + int res = (OK); GENinstance *gen_inst; OsdiRegistryEntry *entry = osdi_reg_entry_model(inModel); From f5279c0ef5507833cf69d2555a67015ffc175885 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 18 Apr 2023 10:48:08 +0200 Subject: [PATCH 17/72] Suppress (rare) crashes during setiup if device or model lists are missing. --- src/spicelib/analysis/cktsetup.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/spicelib/analysis/cktsetup.c b/src/spicelib/analysis/cktsetup.c index 3242944e1..902f9a356 100644 --- a/src/spicelib/analysis/cktsetup.c +++ b/src/spicelib/analysis/cktsetup.c @@ -14,6 +14,7 @@ Author: 1985 Thomas L. Quarles #include "ngspice/cktdefs.h" #include "ngspice/devdefs.h" #include "ngspice/sperror.h" +#include "ngspice/fteext.h" #ifdef XSPICE #include "ngspice/enh.h" @@ -43,6 +44,20 @@ CKTsetup(CKTcircuit *ckt) /* gtri - end - Setup for adding rshunt option resistors */ #endif SMPmatrix *matrix; + + if (!ckt->CKThead) { + fprintf(stderr, "Error: No model list found, device setup not possible!\n"); + if (ft_stricterror) + controlled_exit(EXIT_BAD); + return E_PANIC; + } + if (!DEVices) { + fprintf(stderr, "Error: No device list found, device setup not possible!\n"); + if (ft_stricterror) + controlled_exit(EXIT_BAD); + return E_PANIC; + } + ckt->CKTnumStates=0; #ifdef WANT_SENSE2 @@ -57,7 +72,9 @@ CKTsetup(CKTcircuit *ckt) return E_NOCHANGE; error = NIinit(ckt); - if (error) return(error); + if (error) + return(error); + ckt->CKTisSetup = 1; matrix = ckt->CKTmatrix; From 5bd0346b64f477d4479757643cc19a6360bbe9a7 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 22 Apr 2023 14:55:23 +0200 Subject: [PATCH 18/72] Line concatenation: use dstring instead of tprintf: Parsing time of Skywater libs reduced by more than 35%. --- src/frontend/inpcom.c | 138 ++++++++++++++++++++---------------------- 1 file changed, 67 insertions(+), 71 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 9fa67d8e8..d3d1f87d6 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -615,16 +615,19 @@ static char *cat2strings(char *s1, char *s2, bool spa) /* line1 + line2 ----> - line1 line 2 + line1 line2 Proccedure: store regular card in prev, skip comment lines (*..) and some - others + others, add tokens from + lines to prev using dstring. */ -static void inp_stitch_continuation_lines(struct card *working) +static void inp_stitch_continuation_lines(struct card* working) { - struct card *prev = NULL; + struct card* prev = NULL; + bool firsttime = TRUE; + + DS_CREATE(newline, 200); while (working) { - char *s, c, *buffer; + char* s, c; for (s = working->line; (c = *s) != '\0' && c <= ' '; s++) ; @@ -632,82 +635,75 @@ static void inp_stitch_continuation_lines(struct card *working) #ifdef TRACE /* SDB debug statement */ printf("In inp_read, processing linked list element line = %d, s = " - "%s . . . \n", - working->linenum, s); + "%s . . . \n", + working->linenum, s); #endif switch (c) { - case '#': - case '$': - case '*': - case '\0': - /* skip these cards, and keep prev as the last regular card */ - working = working->nextcard; /* for these chars, go to next - card */ - break; + case '#': + case '$': + case '*': + case '\0': + /* skip these cards, and keep prev as the last regular card */ + working = working->nextcard; /* for these chars, go to next + card */ + break; - case '+': /* handle continuation */ - if (!prev) { - working->error = - copy("Illegal continuation line: ignored."); - working = working->nextcard; - break; - } - - /* We now may have lept over some comment lines, which are - located among the continuation lines. We have to delete them - here to prevent a memory leak */ - while (prev->nextcard != working) { - struct card *tmpl = prev->nextcard->nextcard; - line_free_x(prev->nextcard, FALSE); - prev->nextcard = tmpl; - } - - /* create buffer and write last and current line into it. - When reading a PDK, the following may be called more than 1e6 times. */ -#if defined (_MSC_VER) - /* vsnprintf (used by tprintf) in Windows is efficient, VS2019 arb. referencevalue 7, - cat2strings() yields ref. speed value 12 only, CYGWIN is 12 in both cases, - MINGW is 36. */ - buffer = tprintf("%s %s", prev->line, s + 1); -#else - /* vsnprintf in Linux is very inefficient, ref. value 24 - cat2strings() is efficient with ref. speed value 6, - MINGW is 12 */ - buffer = cat2strings(prev->line, s + 1, TRUE); -#endif - /* replace prev->line by buffer */ - s = prev->line; - prev->line = buffer; - prev->nextcard = working->nextcard; - working->nextcard = NULL; - /* add original line to prev->actualLine */ - if (prev->actualLine) { - struct card *end; - for (end = prev->actualLine; end->nextcard; - end = end->nextcard) - ; - end->nextcard = working; - tfree(s); - } - else { - prev->actualLine = - insert_new_line(NULL, s, prev->linenum, 0); - prev->actualLine->level = prev->level; - prev->actualLine->nextcard = working; - } - working = prev->nextcard; - break; - - default: /* regular one-line card */ - prev = working; + case '+': /* handle continuation */ + if (!prev) { + working->error = + copy("Illegal continuation line: ignored."); working = working->nextcard; break; + } + + /* We now may have lept over some comment lines, which are + located among the continuation lines. We have to delete them + here to prevent a memory leak */ + while (prev->nextcard != working) { + struct card* tmpl = prev->nextcard->nextcard; + line_free_x(prev->nextcard, FALSE); + prev->nextcard = tmpl; + } + + if (firsttime) { + sadd(&newline, prev->line); + firsttime = FALSE; + } + else { + /* replace '+' by space */ + *s = ' '; + sadd(&newline, s); + /* mark for later removal */ + *s = '*'; + } + + break; + + default: /* regular one-line card */ + if (!firsttime) { + tfree(prev->line); + prev->line = copy(ds_get_buf(&newline)); + ds_clear(&newline); + firsttime = TRUE; + /* remove final used '+' line, if regular line is following */ + struct card* tmpl = prev->nextcard->nextcard; + line_free_x(prev->nextcard, FALSE); + prev->nextcard = tmpl; + } + prev = working; + working = working->nextcard; + break; } } + /* remove final used '+' line when no regular line is following */ + if (!firsttime) { + tfree(prev->line); + prev->line = copy(ds_get_buf(&newline)); + } + ds_free(&newline); } - /* * search for `=' assignment operator * take care of `!=' `<=' `==' and `>=' From 9c71db3a728d59c901a08afc3870b65095adb1b0 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Mon, 3 Apr 2023 19:12:51 +0100 Subject: [PATCH 19/72] Fix Bug #607 - "DC Source with Pulse stops pulsing half way through simulation". Do not require breakpoints to be hit almost exactly before scheduling the next one. That may cause the next breakpoint to be lost. --- src/spicelib/devices/vsrc/vsrcacct.c | 274 +++++++++++++-------------- src/spicelib/devices/vsrc/vsrcdefs.h | 1 + src/spicelib/devices/vsrc/vsrcload.c | 65 +++---- src/spicelib/devices/vsrc/vsrcset.c | 1 + 4 files changed, 165 insertions(+), 176 deletions(-) diff --git a/src/spicelib/devices/vsrc/vsrcacct.c b/src/spicelib/devices/vsrc/vsrcacct.c index 1ec386681..0be45f8e2 100644 --- a/src/spicelib/devices/vsrc/vsrcacct.c +++ b/src/spicelib/devices/vsrc/vsrcacct.c @@ -19,9 +19,6 @@ extern void fftFree(void); extern bool ft_ngdebug; /* some additional debug info printed */ -#define SAMETIME(a,b) (fabs((a)-(b))<= TIMETOL * PW) -#define TIMETOL 1e-7 - int VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) /* set up the breakpoint table. */ @@ -51,7 +48,6 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) case PULSE: { double TD, TR, TF, PW, PER; - double tshift; double time = 0.; double basetime = 0; double tmax = 1e99; @@ -79,7 +75,6 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) /* offset time by delay */ time = ckt->CKTtime - TD; - tshift = TD; if (newcompat.xs) { /* normalize phase to 0 - 360° */ @@ -90,71 +85,55 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) while (deltat > 0) deltat -= PER; time += deltat; - tshift = TD - deltat; - } - else if (PHASE > 0.0) { + } else if (PHASE > 0.0) { tmax = PHASE * PER; + if (time > tmax) + break; } - if (!newcompat.xs && time > tmax) { - /* Do nothing */ - } - else { + if (ckt->CKTtime >= here->VSRCbreak_time) { + double wait; + if (time >= PER) { - /* repeating signal - figure out where we are */ - /* in period */ + /* Repeating signal: where in period are we? */ + basetime = PER * floor(time / PER); time -= basetime; } - if (time <= 0.0 || time >= TR + PW + TF) { - if (ckt->CKTbreak && SAMETIME(time, 0.0)) { - error = CKTsetBreak(ckt, basetime + TR + tshift); - if (error) return(error); - } - else if (ckt->CKTbreak && SAMETIME(TR + PW + TF, time)) { - error = CKTsetBreak(ckt, basetime + PER + tshift); - if (error) return(error); - } - else if (ckt->CKTbreak && (time == -tshift)) { - error = CKTsetBreak(ckt, basetime + tshift); - if (error) return(error); - } - else if (ckt->CKTbreak && SAMETIME(PER, time)) { - error = CKTsetBreak(ckt, basetime + tshift + TR + PER); - if (error) return(error); - } - } - else if (time >= TR && time <= TR + PW) { - if (ckt->CKTbreak && SAMETIME(time, TR)) { - error = CKTsetBreak(ckt, basetime + tshift + TR + PW); - if (error) return(error); - } - else if (ckt->CKTbreak && SAMETIME(TR + PW, time)) { - error = CKTsetBreak(ckt, basetime + tshift + TR + PW + TF); - if (error) return(error); - } - } - else if (time > 0 && time < TR) { - if (ckt->CKTbreak && SAMETIME(time, 0)) { - error = CKTsetBreak(ckt, basetime + tshift + TR); - if (error) return(error); - } - else if (ckt->CKTbreak && SAMETIME(time, TR)) { - error = CKTsetBreak(ckt, basetime + tshift + TR + PW); - if (error) return(error); - } - } - else { /* time > TR + PW && < TR + PW + TF */ - if (ckt->CKTbreak && SAMETIME(time, TR + PW)) { - error = CKTsetBreak(ckt, basetime + tshift + TR + PW + TF); - if (error) return(error); - } - else if (ckt->CKTbreak && SAMETIME(time, TR + PW + TF)) { - error = CKTsetBreak(ckt, basetime + tshift + PER); - if (error) return(error); - } + /* Set next breakpoint. */ + + if (time < 0.0) { + /* Await first pulse */ + + wait = -time; + } else if (time < TR) { + /* Wait for end of rise. */ + + wait = TR - time; + } else if (time < TR + PW) { + /* Wait for fall. */ + + wait = TR + PW - time; + } else if (time < TR + PW + TF) { + /* Wait for end of fall. */ + + wait = TR + PW + TF - time; + } else { + /* Wait for next pulse. */ + wait = PER - time; } + here->VSRCbreak_time = ckt->CKTtime + wait; + error = CKTsetBreak(ckt, here->VSRCbreak_time); + if (error) + return error; + + /* If a timestep ends just before the break time, + * the break request may be ignored. + * Set threshold for requesting following break. + */ + + here->VSRCbreak_time -= ckt->CKTminBreak; } } break; @@ -179,25 +158,46 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) } break; - case PWL: { - int i; - if(ckt->CKTtime < *(here->VSRCcoeffs)) { - if(ckt->CKTbreak) { - error = CKTsetBreak(ckt,*(here->VSRCcoeffs)); - break; + case PWL: + if (ckt->CKTtime >= here->VSRCbreak_time) { + double time, end, period; + int i; + + time = ckt->CKTtime - here->VSRCrdelay; + end = + here->VSRCcoeffs[here->VSRCfunctionOrder - 2]; + if (time > end) { + if (here->VSRCrGiven) { + /* Repeating. */ + + period = end - + here->VSRCcoeffs[here->VSRCrBreakpt]; + time -= period * floor(time / period); + } else { + here->VSRCbreak_time = ckt->CKTfinalTime; + break; + } } - } - for(i=0;i<(here->VSRCfunctionOrder/2)-1;i++) { - if ( ckt->CKTbreak && AlmostEqualUlps(*(here->VSRCcoeffs+2*i), ckt->CKTtime, 3 ) ) { - error = CKTsetBreak(ckt, *(here->VSRCcoeffs+2*i+2)); - if(error) return(error); - goto bkptset; + + for (i = 0; + i < here->VSRCfunctionOrder; + i += 2) { + if (here->VSRCcoeffs[i] > time) { + here->VSRCbreak_time = + ckt->CKTtime + + here->VSRCcoeffs[i] - time; + error = CKTsetBreak(ckt, + here->VSRCbreak_time); + if (error) + return error; + here->VSRCbreak_time -= ckt->CKTminBreak; + break; + } } } break; - } - /**** tansient noise routines: + /**** transient noise routines: VNoi2 2 0 DC 0 TRNOISE(10n 0.5n 0 0n) : generate gaussian distributed noise rms value, time step, 0 0 VNoi1 1 0 DC 0 TRNOISE(0n 0.5n 1 10n) : generate 1/f noise @@ -205,6 +205,7 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) */ case TRNOISE: { + struct trnoise_state *state = here -> VSRCtrnoise_state; double TS = state -> TS; double RTSAM = state ->RTSAM; @@ -220,61 +221,55 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) fftFree(); } #endif - - if(ckt->CKTbreak) { - - int n = (int) floor(ckt->CKTtime / TS + 0.5); - volatile double nearest = n * TS; - - if(AlmostEqualUlps(nearest, ckt->CKTtime, 3)) { - /* carefull calculate `next' - * make sure it is really identical - * with the next calculated `nearest' value - */ - volatile double next = (n+1) * TS; - error = CKTsetBreak(ckt, next); - if(error) - return(error); - } + if (TS > 0 && ckt->CKTtime >= here->VSRCbreak_time) { + if (here->VSRCbreak_time < 0.0) + here->VSRCbreak_time = TS; + else + here->VSRCbreak_time += TS; + error = CKTsetBreak(ckt, here->VSRCbreak_time); + if (error) + return(error); + here->VSRCbreak_time -= ckt->CKTminBreak; } - if (RTSAM > 0) { - double RTScapTime = state->RTScapTime; - double RTSemTime = state->RTSemTime; - double RTSCAPT = state->RTSCAPT; - double RTSEMT = state->RTSEMT; + if (RTSAM <= 0) + break; /* No shot noise. */ - if (ckt->CKTtime == 0) { - /* initialzing here again needed for repeated calls to tran command */ - state->RTScapTime = RTScapTime = exprand(RTSCAPT); - state->RTSemTime = RTSemTime = RTScapTime + exprand(RTSEMT); + if (ckt->CKTtime == 0) { + /* initialzing here again needed for repeated calls to tran command */ + state->RTScapTime = exprand(state->RTSCAPT); + state->RTSemTime = + state->RTScapTime + exprand(state->RTSEMT); + error = CKTsetBreak(ckt, state->RTScapTime); + if(error) + return(error); + break; + } - if (ckt->CKTbreak) { - error = CKTsetBreak(ckt, RTScapTime); - if(error) - return(error); - } - } + /* Break handling code ends a timestep close to + * the requested time. + */ - if(AlmostEqualUlps(RTScapTime, ckt->CKTtime, 3)) { - if (ckt->CKTbreak) { - error = CKTsetBreak(ckt, RTSemTime); - if(error) - return(error); - } - } + if (ckt->CKTtime >= + state->RTScapTime - ckt->CKTminBreak && + ckt->CKTtime <= + state->RTScapTime + ckt->CKTminBreak) { + error = CKTsetBreak(ckt, state->RTSemTime); + if(error) + return(error); + } - if(AlmostEqualUlps(RTSemTime, ckt->CKTtime, 3)) { - /* new values */ - RTScapTime = here -> VSRCtrnoise_state ->RTScapTime = ckt->CKTtime + exprand(RTSCAPT); - here -> VSRCtrnoise_state ->RTSemTime = RTScapTime + exprand(RTSEMT); + if (ckt->CKTtime >= + state->RTSemTime - ckt->CKTminBreak) { + /* new values */ - if (ckt->CKTbreak) { - error = CKTsetBreak(ckt, RTScapTime); - if(error) - return(error); - } - } + state->RTScapTime = + ckt->CKTtime + exprand(state->RTSCAPT); + state->RTSemTime = + state->RTScapTime + exprand(state->RTSEMT); + error = CKTsetBreak(ckt, state->RTScapTime); + if(error) + return(error); } } break; @@ -286,30 +281,22 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) if (ckt->CKTtime == 0 && TD > 0) { error = CKTsetBreak(ckt, TD); + here->VSRCbreak_time = TD; if (error) return(error); + break; } - double time = ckt->CKTtime - TD; - - if (time < 0) break; - - if(ckt->CKTbreak) { - - int n = (int) floor(time / TS + 0.5); - volatile double nearest = n * TS; - - if(AlmostEqualUlps(nearest, time, 10)) { - /* carefully calculate `next' - * make sure it is really identical - * with the next calculated `nearest' value - */ - volatile double next = (n+1) * TS + TD; - error = CKTsetBreak(ckt, next); - if(error) - return(error); - state->value = trrandom_state_get(state); - } + if (ckt->CKTtime >= here->VSRCbreak_time) { + if (here->VSRCbreak_time < 0.0) + here->VSRCbreak_time = TS; + else + here->VSRCbreak_time += TS; + error = CKTsetBreak(ckt, here->VSRCbreak_time); + if (error) + return(error); + here->VSRCbreak_time -= ckt->CKTminBreak; + state->value = trrandom_state_get(state); } } break; @@ -323,7 +310,6 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) } // switch } // if ... else -bkptset: ; } // for } // for diff --git a/src/spicelib/devices/vsrc/vsrcdefs.h b/src/spicelib/devices/vsrc/vsrcdefs.h index 15c8b6951..346e75552 100644 --- a/src/spicelib/devices/vsrc/vsrcdefs.h +++ b/src/spicelib/devices/vsrc/vsrcdefs.h @@ -50,6 +50,7 @@ typedef struct sVSRCinstance { int VSRCfunctionType; /* code number of function type for source */ int VSRCfunctionOrder; /* order of the function for the source */ int VSRCrBreakpt; /* pwl repeat breakpoint index */ + double VSRCbreak_time; /* time of most-recent breakpoint */ double *VSRCcoeffs; /* pointer to array of coefficients */ double VSRCdcValue; /* DC and TRANSIENT value of source */ diff --git a/src/spicelib/devices/vsrc/vsrcload.c b/src/spicelib/devices/vsrc/vsrcload.c index beee1c99c..a4d4f73c6 100644 --- a/src/spicelib/devices/vsrc/vsrcload.c +++ b/src/spicelib/devices/vsrc/vsrcload.c @@ -298,43 +298,45 @@ VSRCload(GENmodel *inModel, CKTcircuit *ckt) break; case PWL: { - int i = 0, num_repeat = 0, ii = 0; - double foo, repeat_time = 0, end_time, breakpt_time, itime; + int i; + double end_time, itime; time -= here->VSRCrdelay; - - if(time < *(here->VSRCcoeffs)) { - foo = *(here->VSRCcoeffs + 1) ; - value = foo; - goto loadDone; + if (time < here->VSRCcoeffs[0]) { + value = here->VSRCcoeffs[1]; + value = value; + break; } - do { - for(i=ii ; i<(here->VSRCfunctionOrder/2)-1; i++ ) { - itime = *(here->VSRCcoeffs+2*i); - if ( AlmostEqualUlps(itime+repeat_time, time, 3 )) { - foo = *(here->VSRCcoeffs+2*i+1); - value = foo; - goto loadDone; - } else if ( (*(here->VSRCcoeffs+2*i)+repeat_time < time) - && (*(here->VSRCcoeffs+2*(i+1))+repeat_time > time) ) { - foo = *(here->VSRCcoeffs+2*i+1) + (((time-(*(here->VSRCcoeffs+2*i)+repeat_time))/ - (*(here->VSRCcoeffs+2*(i+1)) - *(here->VSRCcoeffs+2*i))) * - (*(here->VSRCcoeffs+2*i+3) - *(here->VSRCcoeffs+2*i+1))); - value = foo; - goto loadDone; - } + end_time = + here->VSRCcoeffs[here->VSRCfunctionOrder - 2]; + if (time > end_time) { + double period; + + if (here->VSRCrGiven) { + /* Repeating. */ + + period = end_time - + here->VSRCcoeffs[here->VSRCrBreakpt]; + time -= period * floor(time / period); + } else { + break; } - foo = *(here->VSRCcoeffs+ here->VSRCfunctionOrder-1) ; - value = foo; + } - if ( !here->VSRCrGiven ) goto loadDone; - - end_time = *(here->VSRCcoeffs + here->VSRCfunctionOrder-2); - breakpt_time = *(here->VSRCcoeffs + here->VSRCrBreakpt); - repeat_time = end_time + (end_time - breakpt_time)*num_repeat++ - breakpt_time; - ii = here->VSRCrBreakpt/2; - } while ( here->VSRCrGiven ); + for (i = 2; i < here->VSRCfunctionOrder; i += 2) { + itime = here->VSRCcoeffs[i]; + if (itime >= time) { + time -= here->VSRCcoeffs[i - 2]; + time /= here->VSRCcoeffs[i] - + here->VSRCcoeffs[i - 2]; + value = here->VSRCcoeffs[i - 1]; + value += time * + ( here->VSRCcoeffs[i + 1] - + here->VSRCcoeffs[i - 1]); + break; + } + } break; } @@ -418,7 +420,6 @@ VNoi3 3 0 DC 0 TRNOISE(0 0 0 0 15m 22u 50u) : generate RTS noise } // switch } // else (line 48) -loadDone: /* gtri - begin - wbk - modify for supply ramping option */ #ifdef XSPICE_EXP diff --git a/src/spicelib/devices/vsrc/vsrcset.c b/src/spicelib/devices/vsrc/vsrcset.c index 18d7764b7..3659e9755 100644 --- a/src/spicelib/devices/vsrc/vsrcset.c +++ b/src/spicelib/devices/vsrc/vsrcset.c @@ -31,6 +31,7 @@ VSRCsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *state) for (here = VSRCinstances(model); here != NULL ; here=VSRCnextInstance(here)) { + here->VSRCbreak_time = -1.0; // To set initial breakpoint if(here->VSRCposNode == here->VSRCnegNode) { SPfrontEnd->IFerrorf (ERR_FATAL, "instance %s is a shorted VSRC", here->VSRCname); From 28a3413dd29ff9c62308f47f13ab189e9e58ffae Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 25 Apr 2023 14:34:51 +0200 Subject: [PATCH 20/72] Send 'refernce value' to stdout, not to stderr --- src/frontend/outitf.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/frontend/outitf.c b/src/frontend/outitf.c index 6bae09b34..2ed33d5d4 100644 --- a/src/frontend/outitf.c +++ b/src/frontend/outitf.c @@ -627,7 +627,7 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr) if (!orflag && !ft_norefprint) { currclock = clock(); if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) { - fprintf(stderr, " Reference value : % 12.5e\r", + fprintf(stdout, " Reference value : % 12.5e\r", refValue->cValue.real); lastclock = currclock; } @@ -640,7 +640,7 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr) if (!orflag && !ft_norefprint) { currclock = clock(); if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) { - fprintf(stderr, " Reference value : % 12.5e\r", + fprintf(stdout, " Reference value : % 12.5e\r", refValue->rValue); lastclock = currclock; } @@ -735,10 +735,10 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr) currclock = clock(); if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) { if (run->isComplex) { - fprintf(stderr, " Reference value : % 12.5e\r", + fprintf(stdout, " Reference value : % 12.5e\r", refValue ? refValue->cValue.real : NAN); } else { - fprintf(stderr, " Reference value : % 12.5e\r", + fprintf(stdout, " Reference value : % 12.5e\r", refValue ? refValue->rValue : NAN); } lastclock = currclock; @@ -1506,7 +1506,7 @@ InterpFileAdd(runDesc *run, IFvalue *refValue, IFvalue *valuePtr) if (!orflag && !ft_norefprint) { currclock = clock(); if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) { - fprintf(stderr, " Reference value : % 12.5e\r", + fprintf(stdout, " Reference value : % 12.5e\r", refValue->rValue); lastclock = currclock; } @@ -1670,7 +1670,7 @@ InterpPlotAdd(runDesc *run, IFvalue *refValue, IFvalue *valuePtr) if (!orflag && !ft_norefprint) { currclock = clock(); if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) { - fprintf(stderr, " Reference value : % 12.5e\r", + fprintf(stdout, " Reference value : % 12.5e\r", refValue->rValue); lastclock = currclock; } From 81012de4d09fa4fee1b21af2c1875808045fcece Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 25 Apr 2023 14:37:00 +0200 Subject: [PATCH 21/72] Add another error qualifier to decribe the current policy when a doubling token exists (or is created) in the netlist. --- src/include/ngspice/iferrmsg.h | 3 ++- src/spicelib/devices/cktcrte.c | 2 +- src/spicelib/parser/sperror.c | 5 ++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/include/ngspice/iferrmsg.h b/src/include/ngspice/iferrmsg.h index c5532bdd4..1d5a53adb 100644 --- a/src/include/ngspice/iferrmsg.h +++ b/src/include/ngspice/iferrmsg.h @@ -34,7 +34,8 @@ Author: 1986 Thomas L. Quarles #define E_NOCHANGE 13 /* simulator can't tolerate any more topology changes */ #define E_NOTFOUND 14 /* simulator can't find something it was looking for */ #define E_BAD_DOMAIN 15 /* output interface begin/end domain calls mismatched */ - +#define E_EXISTS_BAD 16 /* error - attempt to create duplicate */ + /* instance or model. Bail out. */ #define E_PRIVATE 100 /* messages above this number are private to */ /* the simulator and MUST be accompanied by */ diff --git a/src/spicelib/devices/cktcrte.c b/src/spicelib/devices/cktcrte.c index 1f5b9578d..77715604b 100644 --- a/src/spicelib/devices/cktcrte.c +++ b/src/spicelib/devices/cktcrte.c @@ -32,7 +32,7 @@ CKTcrtElt(CKTcircuit *ckt, GENmodel *modPtr, GENinstance **inInstPtr, IFuid name if (instPtr) { if (inInstPtr) *inInstPtr = instPtr; - return E_EXISTS; + return E_EXISTS_BAD; } type = modPtr->GENmodType; diff --git a/src/spicelib/parser/sperror.c b/src/spicelib/parser/sperror.c index 1ada7e7d7..915afc79c 100644 --- a/src/spicelib/parser/sperror.c +++ b/src/spicelib/parser/sperror.c @@ -29,7 +29,10 @@ const char *SPerror(int type) case E_EXISTS: msg = "device already exists, existing one being used"; break; - case E_NODEV: + case E_EXISTS_BAD: + msg = "device already exists, bail out"; + break; + case E_NODEV: msg = "no such device"; break; case E_NOMOD: From ff9ff266137cb8ec36737e5353a495df0b7dec2f Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 25 Apr 2023 15:39:00 +0200 Subject: [PATCH 22/72] .libsave: Print to file the expanded library read by .lib --- src/frontend/inpcom.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index d3d1f87d6..c8369dea3 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -175,6 +175,7 @@ static struct modellist *inp_find_model( struct nscope *scope, const char *name); void tprint(struct card *deck); +static char* libprint(struct card* t, const char *dir); static void inp_repair_dc_ps(struct card* oldcard); static void inp_get_w_l_x(struct card* oldcard); @@ -3292,13 +3293,23 @@ static struct card *expand_section_ref(struct card *c, const char *dir_name) * every library section reference (when the given section_name_ === NULL) * or * just those references occuring in the given library section definition + * + * Command .libsave saves the loaded and parsed lib, to be read by .include */ static void expand_section_references(struct card *c, const char *dir_name) { - for (; c; c = c->nextcard) - if (ciprefix(".lib", c->line)) + for (; c; c = c->nextcard) { + struct card* p = c; + if (ciprefix(".libsave", c->line)) { c = expand_section_ref(c, dir_name); + char *filename = libprint(p, dir_name); + fprintf(stdout, "\nLibrary\n%s\nsaved to %s\n", p->line + 9, filename); + tfree(filename); + } + else if (ciprefix(".lib", c->line)) + c = expand_section_ref(c, dir_name); + } } @@ -6913,6 +6924,24 @@ static void inp_poly_err(struct card *card) #endif +/* Print the parsed library to lib_out?.lib, with ? a growing number + if multiple libs are saved in a single run. */ +static char* libprint(struct card* t, const char *dir_name) +{ + struct card* tmp; + static int npr = 1; + char *outfile = tprintf("%s/lib_out%d.lib", dir_name, npr); + npr++; + FILE* fd = fopen(outfile, "w"); + if (fd) { + for (tmp = t; tmp; tmp = tmp->nextcard) + if (*(tmp->line) != '*') + fprintf(fd, "%s\n", tmp->line); + fclose(fd); + } + return outfile; +} + /* Used for debugging. You may add * tprint(working); From dfb53459dcaa76033d5a96a8a6d4096ff3db78a4 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 26 Apr 2023 09:46:22 +0200 Subject: [PATCH 23/72] .libsave: don't save the command itself, improve messaging --- src/frontend/inpcom.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index c8369dea3..1f4994c7b 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -6925,7 +6925,7 @@ static void inp_poly_err(struct card *card) #endif /* Print the parsed library to lib_out?.lib, with ? a growing number - if multiple libs are saved in a single run. */ + if multiple libs are saved in a single run. Don't save the .libsave line.*/ static char* libprint(struct card* t, const char *dir_name) { struct card* tmp; @@ -6935,10 +6935,13 @@ static char* libprint(struct card* t, const char *dir_name) FILE* fd = fopen(outfile, "w"); if (fd) { for (tmp = t; tmp; tmp = tmp->nextcard) - if (*(tmp->line) != '*') + if (*(tmp->line) != '*' && !ciprefix(".libsave", tmp->line)) fprintf(fd, "%s\n", tmp->line); fclose(fd); } + else { + fprintf(stderr, "Warning: Can't open file %s \n command .libsave ignored!\n", outfile); + } return outfile; } From 7e4f420788484561c390a95af93d990217ac1ca2 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 26 Apr 2023 15:09:48 +0200 Subject: [PATCH 24/72] Remove obsolete adms, add OSDI --- compile_linux.sh | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/compile_linux.sh b/compile_linux.sh index 06c0d5b6d..91c1b7314 100755 --- a/compile_linux.sh +++ b/compile_linux.sh @@ -9,10 +9,13 @@ # for details please see the ngspice manual, chapt. 32.1. # Declare 'compile_linux.sh' executable and start compiling with # './compile_linux.sh' or './compile_linux.sh d' from the ngspice directory. +# Centos users may need to add -std=c99 to the CFLAGS in the ../configure +# statement. # Options: -# --adms and --enable-adms will install extra HICUM, EKV and MEXTRAM models via the -# adms interface. You need to download and install the *.va files via ng-adms-va.tgz -# Please see the ngspice manual, chapt. 13, for more info on adms. +# --enable-osdi will enable the OSDI interface, which, in conjuction with the +# external OpenVAF Verilig-A compiler, will allow access to advanced compact +# device models writen in Verilog-A. +# Please see the ngspice manual, chapt. 13, for more info on using OSDI/OpenVAF. # CIDER, XSPICE, and OpenMP may be selected at will. # --disable-debug will give O2 optimization (versus O0 for debug) and removes all debugging info. @@ -39,26 +42,18 @@ fi ./autogen.sh if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi -# Alternatively, if compiling sources from git, and want to add adms created devices, -# you may need to uncomment the following two lines (and don't forget to add adms option -# to the ../configure statement): -#./autogen.sh --adms -#if [ $? -ne 0 ]; then echo "./autogen.sh failed"; exit 1 ; fi - echo if test "$1" = "d"; then cd debug if [ $? -ne 0 ]; then echo "cd debug failed"; exit 1 ; fi echo "configuring for 64 bit debug" echo -# You may add --enable-adms to the following command for adding adms generated devices ../configure --with-x --enable-xspice --enable-cider --enable-predictor --enable-osdi --with-readline=yes --enable-openmp CFLAGS="-g -m64 -O0 -Wall -Wno-unused-but-set-variable" LDFLAGS="-m64 -g" else cd release if [ $? -ne 0 ]; then echo "cd release failed"; exit 1 ; fi echo "configuring for 64 bit release" echo -# You may add --enable-adms to the following command for adding adms generated devices ../configure --with-x --enable-xspice --enable-cider --enable-predictor --enable-osdi --with-readline=yes --enable-openmp --disable-debug CFLAGS="-m64 -O2" LDFLAGS="-m64 -s" fi if [ $? -ne 0 ]; then echo "../configure failed"; exit 1 ; fi From d72d07beae7d04d6e69b8fc69e1ef0b759f9138d Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 26 Apr 2023 15:20:37 +0200 Subject: [PATCH 25/72] Update to ngspice-40, remove adms, recoomend using compile_linux.sh, hints for Centos, compile scripts for macOS. --- INSTALL | 69 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/INSTALL b/INSTALL index 8555ceea3..ea42a02e2 100644 --- a/INSTALL +++ b/INSTALL @@ -67,32 +67,40 @@ This file describes the procedures to install ngspice from sources. If libfftw is detected on your system, it will be used instead of the internal fft algorithms. - If you want to compile the source from the git repository you need - additional software: autoconf, automake, libtool. + If you want to compile the source from the git repository, or if you want to + use the compile script ./compile_linux.sh, you will need additional software: + autoconf, automake, libtool. The following software may be needed when enabling additional features: - editline, tcl/tk, adms. + editline, tcl/tk. - Please have a look at the actual ngspice manual, downloadable at + Please have a look at the current ngspice manual, downloadable at http://ngspice.sourceforge.net/docs.html, which gives you much more information on ngspice and its usage. For compiling ngspice as a shared library, see section 1.4. -1.2 Install from tarball (e.g. ngspice-36.tar.gz) +1.2 Install from tarball (e.g. ngspice-40.tar.gz) This covers installation from a release distribution (for example - ngspice-36.tar.gz, the so called tar ball). + ngspice-40.tar.gz, the so called tar ball). - After downloading the tar ball to a local directory unpack it using: + After downloading the tar ball to a local directory, unpack it by command: - $ tar -zxvf ngspice-36.tar.gz + $ tar -zxvf ngspice-40.tar.gz Now change directories in to the top-level source directory (where this INSTALL file can be found). - You should be able to do: + The most comfortable way to compile ngspice is running the compile script + compile_linux.sh within the terminal window by ./compile_linux.sh. Admin + rights are required to allow the installation included in the script. + + Centos users may need to add -std=c99 to the CFLAGS in the ../configure + statement. + + If you want to compile ngspice manually, you should be able to do: $ mkdir release $ cd release @@ -105,18 +113,15 @@ This file describes the procedures to install ngspice from sources. A simple ../configure might be sufficient for a basic ngspice, but the preferred arguments to ../configure are --with-x --with-readline=yes and --disable-debug - providing you with a comfortably working ngspice (see section 1.4 for details). + providing you with a comfortably working ngspice. - See the section titled 'Advanced Install' for instructions about additional arguments + See the section 1.5 titled 'Advanced Install' for instructions about additional arguments that can be passed to ../configure to customise the build and installation. - Do not use the script ./autogen.sh, because it is not required for - compiling and installing ngspice from the tarball. - A fully featured ngspice on LINUX may be obtained with the following commands: $ mkdir release $ cd release - $ ../configure --with-x --enable-xspice --disable-debug --enable-cider --with-readline=yes --enable-openmp + $ ../configure --with-x --enable-xspice --disable-debug --enable-cider --with-readline=yes --enable-osdi --enable-openmp $ make 2>&1 | tee make.log $ sudo make install @@ -141,6 +146,12 @@ This file describes the procedures to install ngspice from sources. The project uses the GNU build process. The compile output should go into a separate directory, so to e.g. maintain separate debug and release versions. + The most comfortable way to compile ngspice is running the compile script + compile_linux.sh within the terminal window by ./compile_linux.sh. Admin + rights are required to allow the installation included in the script. + + If you want to copile ngspice manually, you may run + $ ./autogen.sh $ mkdir debug $ cd debug @@ -148,7 +159,7 @@ This file describes the procedures to install ngspice from sources. $ make $ sudo make install - See the section titled 'Advanced Install' for instructions about arguments + See the section 1.5 titled 'Advanced Install' for instructions about arguments that can be passed to ./configure to customize the build and installation. Preferred arguments to ./configure to obtain a comfortably working ngspice may be @@ -156,21 +167,21 @@ This file describes the procedures to install ngspice from sources. executable). A fully featured ngspice on LINUX may be obtained with the following commands: - $ ./autogen.sh --adms + $ ./autogen.sh $ mkdir release $ cd release - $ ../configure --with-x --enable-xspice --disable-debug --enable-cider --with-readline=yes --enable-openmp --enable-adms + $ ../configure --with-x --enable-xspice --disable-debug --enable-cider --with-readline=yes --enable-openmp --enable-osdi $ make 2>&1 | tee make.log $ sudo make install - A bash script compile_linux.sh is available including all useful options, + The bash script compile_linux.sh includes all the useful options, compiling and installation procedures. 1.4 ngspice as a shared library The relevant configure options for the ngspice shared library are: - $ --with-ngshared --enable-xspice --disable-debug --enable-cider --enable-openmp + $ --with-ngshared --enable-xspice --disable-debug --enable-cider --enable-osdi --enable-openmp Typically the two aliases libngspice.so, libngspice.so.0 and the compiled library libngspice.so.0.0.1 are made. The install locations depend on @@ -314,11 +325,15 @@ This file describes the procedures to install ngspice from sources. 1.6 Installation on Red Hat, Oracle or Centos - These OSs, widely distributed among commercial users, require some + These OSs, widely distributed among commercial users, but offering + only an old gcc compiler, e.g. version 4.8, will require some special considerations. There is an extra document, "NGSPICE on Red Hat Like Distributions.pdf", provided by Justin Fisher, available with the ngspice distribution. + Centos users may need to add -std=c99 to the CFLAGS in their ../configure + statement. + 2 Compilers and Options ===================== @@ -502,10 +517,10 @@ This file describes the procedures to install ngspice from sources. --disable-debug (-O2 optimization, no debug information) A fully featured ngspice on Windows may be obtained with the following commands: - $ ./autogen.sh --adms + $ ./autogen.sh $ mkdir release $ cd release - $ ../configure --with-wingui --enable-cider --disable-debug --enable-openmp --enable-xspice --enable-adms + $ ../configure --with-wingui --enable-cider --disable-debug --enable-openmp --enable-xspice --enable-osdi $ make install However, to compile code extracted from the git repository the procedure is @@ -523,7 +538,7 @@ This file describes the procedures to install ngspice from sources. Go to directory ngspice $ cd /d/Spice/ngspice Start compiling, e.g. by calling - $ ./autogen.sh --adms + $ ./autogen.sh $ ./compile_min.sh Update the ngspice files: @@ -680,7 +695,7 @@ This file describes the procedures to install ngspice from sources. You then will not have any graphics interface. In CYGWIN you may add --with-x for the X11 graphics (not available in mingw). A typical configure command may look like - ./configure --enable-adms --enable-xspice --enable-cider --enable-openmp + ./configure --enable-osdi --enable-xspice --enable-cider --enable-openmp --disable-debug CFLAGS=-m64 LDFLAGS=-m64 prefix=C:/Spice64 @@ -708,7 +723,9 @@ cross-compile-shared.sh. 3. Execute this command: sudo port install autoconf automake libtool bison flex ncurses readline fontconfig freetype libomp xorg-libXaw - 4. Use one of the scripts provided: compile_macos.sh or build-for-mac-os.sh + 4. Use one of the scripts provided: compile_macos_clang.sh or compile_macos_gcc.sh + gcc may be installed from Homebre at https://formulae.brew.sh/formula/gcc, with the + advantage that it supports OpenMP. 5. Or run the commands manually: Configure NGSPICE invoking "./configure". A complete set of features is: ./configure --enable-cider --enable-xspice --enable-openmp --enable-pss --enable-debug=no From 783c4324673d3f8c14852e25873103a785dd13d4 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 26 Apr 2023 15:33:07 +0200 Subject: [PATCH 26/72] typo --- INSTALL | 8 ++++---- compile_linux.sh | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/INSTALL b/INSTALL index ea42a02e2..3a67481b8 100644 --- a/INSTALL +++ b/INSTALL @@ -18,7 +18,7 @@ Table of contents 1.5.1 Most useful options 1.5.2 Options Specific to Enable Ngspice as a shared library 1.5.3 Options Useful for Debugging Ngspice - 1.6 Installation on Red Hat, Oracle or Centos Linux + 1.6 Installation on Red Hat, Oracle or CentOS Linux 2 Compilers and Options 3 Compiling For Multiple Architectures 4 Installation Names @@ -97,7 +97,7 @@ This file describes the procedures to install ngspice from sources. compile_linux.sh within the terminal window by ./compile_linux.sh. Admin rights are required to allow the installation included in the script. - Centos users may need to add -std=c99 to the CFLAGS in the ../configure + CentOS users may need to add -std=c99 to the CFLAGS in the ../configure statement. If you want to compile ngspice manually, you should be able to do: @@ -323,7 +323,7 @@ This file describes the procedures to install ngspice from sources. problem yourself, then the development team will love to hear from you. -1.6 Installation on Red Hat, Oracle or Centos +1.6 Installation on Red Hat, Oracle or CentOS These OSs, widely distributed among commercial users, but offering only an old gcc compiler, e.g. version 4.8, will require some @@ -331,7 +331,7 @@ This file describes the procedures to install ngspice from sources. Hat Like Distributions.pdf", provided by Justin Fisher, available with the ngspice distribution. - Centos users may need to add -std=c99 to the CFLAGS in their ../configure + CentOS users may need to add -std=c99 to the CFLAGS in their ../configure statement. diff --git a/compile_linux.sh b/compile_linux.sh index 91c1b7314..5454ba0ec 100755 --- a/compile_linux.sh +++ b/compile_linux.sh @@ -9,7 +9,7 @@ # for details please see the ngspice manual, chapt. 32.1. # Declare 'compile_linux.sh' executable and start compiling with # './compile_linux.sh' or './compile_linux.sh d' from the ngspice directory. -# Centos users may need to add -std=c99 to the CFLAGS in the ../configure +# CentOS users may need to add -std=c99 to the CFLAGS in the ../configure # statement. # Options: # --enable-osdi will enable the OSDI interface, which, in conjuction with the From 675b9e6fa251f8886a4a3ebd617101784e64d832 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 26 Apr 2023 17:06:39 +0200 Subject: [PATCH 27/72] Prevent crash (seg fault), if measure statement is incomplete --- src/frontend/measure.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/frontend/measure.c b/src/frontend/measure.c index 9ca735a3f..c91715a11 100644 --- a/src/frontend/measure.c +++ b/src/frontend/measure.c @@ -283,6 +283,22 @@ do_measure( resname = gettok(&line); meastype = gettok(&line); + if (!an_type){ + fprintf(cp_err, "\nWarning: Incomplete measurement statement in line\n %s\nignored!\n", meas_card->line); + continue; + } + if (!resname){ + fprintf(cp_err, "\nWarning: Incomplete measurement statement in line\n %s\nignored!\n", meas_card->line); + tfree(an_type); + continue; + } + if (!meastype) { + fprintf(cp_err, "\nWarning: Incomplete measurement statement in line\n %s\nignored!\n", meas_card->line); + tfree(an_type); + tfree(resname); + continue; + } + if (chkAnalysisType(an_type) != TRUE) { if (!chk_only) { fprintf(cp_err, "Error: unrecognized analysis type '%s' for the following .meas statement on line %d:\n", an_type, meas_card->linenum); @@ -399,6 +415,20 @@ do_measure( resname = gettok(&line); meastype = gettok(&line); + if (!an_type) { + /* Warnings have already been issued in first pass */ + continue; + } + if (!resname) { + tfree(an_type); + continue; + } + if (!meastype) { + tfree(an_type); + tfree(resname); + continue; + } + if (chkAnalysisType(an_type) != TRUE) { if (!chk_only) { fprintf(cp_err, "Error: unrecognized analysis type '%s' for the following .meas statement on line %d:\n", an_type, meas_card->linenum); From 79c69e064435f6b6f8950804e0f5d3fbbe0cd708 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Wed, 26 Apr 2023 21:34:37 +0100 Subject: [PATCH 28/72] Fix error in previous fix for Bug #607 - "DC Source with Pulse stops pulsing half way through simulation". Non-periodic PWL waveforms reverted to zero on termination. --- src/spicelib/devices/vsrc/vsrcload.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/spicelib/devices/vsrc/vsrcload.c b/src/spicelib/devices/vsrc/vsrcload.c index a4d4f73c6..099daac4f 100644 --- a/src/spicelib/devices/vsrc/vsrcload.c +++ b/src/spicelib/devices/vsrc/vsrcload.c @@ -320,6 +320,8 @@ VSRCload(GENmodel *inModel, CKTcircuit *ckt) here->VSRCcoeffs[here->VSRCrBreakpt]; time -= period * floor(time / period); } else { + value = + here->VSRCcoeffs[here->VSRCfunctionOrder - 1]; break; } } From 81e07e8eced5df89ef2749fb55aac320e519ff53 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Thu, 27 Apr 2023 15:42:15 +0100 Subject: [PATCH 29/72] In graf.c change local function set() to do what you might expect, rather than the opposite. Also fix a debug message. --- src/frontend/plotting/graf.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/frontend/plotting/graf.c b/src/frontend/plotting/graf.c index 929a6e5fb..3df20b1d0 100644 --- a/src/frontend/plotting/graf.c +++ b/src/frontend/plotting/graf.c @@ -33,7 +33,7 @@ Author: 1988 Jeffrey M. Hsu static void gr_start_internal(struct dvec *dv, bool copyvec); static int iplot(struct plot *pl, int id); -static void set(struct plot *plot, struct dbcomm *db, bool unset, short mode); +static void set(struct plot *plot, struct dbcomm *db, bool value, short mode); static char *getitright(char *buf, double num); /* for legends, set in gr_start, reset in gr_iplot and gr_init */ @@ -918,7 +918,8 @@ static int iplot(struct plot *pl, int id) if (ft_grdb) { fprintf(cp_err, - "iplot: after 5, xlims = %G, %G, ylims = %G, %G\n", + "iplot: after" #IPOINTMIN + ", xlims = %G, %G, ylims = %G, %G\n", xlims[0], xlims[1], ylims[0], ylims[1]); } @@ -1094,17 +1095,17 @@ static int iplot(struct plot *pl, int id) } -static void set(struct plot *plot, struct dbcomm *db, bool unset, short mode) +static void set(struct plot *plot, struct dbcomm *db, bool value, short mode) { struct dvec *v; struct dbcomm *dc; if (db->db_type == DB_IPLOTALL || db->db_type == DB_TRACEALL) { for (v = plot->pl_dvecs; v; v = v->v_next) - if (unset) - v->v_flags &= (short) ~mode; - else + if (value) v->v_flags |= mode; + else + v->v_flags &= (short) ~mode; return; } @@ -1113,17 +1114,17 @@ static void set(struct plot *plot, struct dbcomm *db, bool unset, short mode) continue; v = vec_fromplot(dc->db_nodename1, plot); if (!v || v->v_plot != plot) { - if (!eq(dc->db_nodename1, "0") && !unset) { + if (!eq(dc->db_nodename1, "0") && value) { fprintf(cp_err, "Warning: node %s non-existent in %s.\n", dc->db_nodename1, plot->pl_name); /* note: XXX remove it from dbs, so won't get further errors */ } continue; } - if (unset) - v->v_flags &= (short) ~mode; - else + if (value) v->v_flags |= mode; + else + v->v_flags &= (short) ~mode; } } @@ -1176,7 +1177,9 @@ void gr_iplot(struct plot *plot) PushGraphContext(gr); } - set(plot, db, FALSE, VF_PLOT); + /* Temporarily set plot flag on matching vector. */ + + set(plot, db, TRUE, VF_PLOT); dontpop = 0; if (iplot(plot, db->db_graphid)) { @@ -1185,7 +1188,7 @@ void gr_iplot(struct plot *plot) dontpop = 1; } - set(plot, db, TRUE, VF_PLOT); + set(plot, db, FALSE, VF_PLOT); if (!dontpop && db->db_graphid) PopGraphContext(); @@ -1195,7 +1198,7 @@ void gr_iplot(struct plot *plot) struct dvec *v, *u; int len; - set(plot, db, FALSE, VF_PRINT); + set(plot, db, TRUE, VF_PRINT); len = plot->pl_scale->v_length; @@ -1251,7 +1254,7 @@ void gr_iplot(struct plot *plot) printf("\n"); } } - set(plot, db, TRUE, VF_PRINT); + set(plot, db, FALSE, VF_PRINT); } } } From fdb8ee380688061296b9e2054d2d805d43a0c760 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Tue, 2 May 2023 13:13:02 +0100 Subject: [PATCH 30/72] Add a "-w" option to the iplot command. It sets a width for the window (in the current scale units) so that it does not re-scale on overflow, but instead plots recently-generated data on a fixed scale. --- src/frontend/breakp.c | 22 ++++++- src/frontend/commands.c | 2 +- src/frontend/plotting/graf.c | 110 ++++++++++++++++++++++------------- 3 files changed, 92 insertions(+), 42 deletions(-) diff --git a/src/frontend/breakp.c b/src/frontend/breakp.c index f420a938a..190e91730 100644 --- a/src/frontend/breakp.c +++ b/src/frontend/breakp.c @@ -205,7 +205,26 @@ com_iplot(wordlist *wl) /* settrace(wl, VF_PLOT); */ struct dbcomm *d, *td, *currentdb = NULL; - char *s; + double window; + char *s; + + /* Look for "-w window-size" at the front, indicating a windowed iplot. */ + + if (wl->wl_next && !strcmp("-w", wl->wl_word)) { + char *cp; + int error; + + wl = wl->wl_next; + cp = wl->wl_word; + window = INPevaluate(&cp, &error, 0); + if (error || window <= 0) { + fprintf(cp_err, "Incremental plot width must be positive.\n"); + return; + } + wl = wl->wl_next; + } else { + window = 0.0; + } /* We use a modified ad-hoc algorithm here where db_also denotes vectors on the same command line and db_next denotes @@ -215,6 +234,7 @@ com_iplot(wordlist *wl) d = TMALLOC(struct dbcomm, 1); d->db_analysis = NULL; d->db_number = debugnumber++; + d->db_value1 = window; // Field re-use if (eq(s, "all")) { d->db_type = DB_IPLOTALL; } else { diff --git a/src/frontend/commands.c b/src/frontend/commands.c index 028f24071..225dbf884 100644 --- a/src/frontend/commands.c +++ b/src/frontend/commands.c @@ -426,7 +426,7 @@ struct comm spcp_coms[] = { { "iplot", com_iplot, TRUE, TRUE, { 0200, 0200, 0200, 0200 }, E_DEFHMASK, 0, LOTS, NULL, - "[all] [node ...] : Incrementally plot a node." } , + "[-w width] [all] [node ...] : Incrementally plot nodes." } , { "status", com_sttus, TRUE, FALSE, { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, NULL, diff --git a/src/frontend/plotting/graf.c b/src/frontend/plotting/graf.c index 3df20b1d0..33e7187ae 100644 --- a/src/frontend/plotting/graf.c +++ b/src/frontend/plotting/graf.c @@ -32,7 +32,6 @@ Author: 1988 Jeffrey M. Hsu static void gr_start_internal(struct dvec *dv, bool copyvec); -static int iplot(struct plot *pl, int id); static void set(struct plot *plot, struct dbcomm *db, bool value, short mode); static char *getitright(char *buf, double num); @@ -844,28 +843,31 @@ void gr_restoretext(GRAPH *graph) * XXX Or maybe even something more drastic ?? * It would be better to associate a color with an instance using a * vector than the vector itself, for which color is something artificial. */ -static int iplot(struct plot *pl, int id) +static int iplot(struct plot *pl, struct dbcomm *db) { - int len = pl->pl_scale->v_length; + double window; + int len = pl->pl_scale->v_length; if (ft_grdb) { fprintf(cp_err, "Entering iplot, len = %d\n", len); } /* Do simple check for exit first */ - if (len < IPOINTMIN) { /* Nothing yet */ + + window = db->db_value1; + if (len < 2 || (window == 0.0 && len < IPOINTMIN)) { /* Nothing yet */ return 0; } - struct dvec *v, *xs = pl->pl_scale; - double *lims, dy; - double start, stop, step; - bool changed = FALSE; - int yt; - double xlims[2], ylims[2]; + struct dvec *v, *xs = pl->pl_scale; + double *lims, dy; + double start, stop, step; + bool changed = FALSE; + int id, yt; + double xlims[2], ylims[2]; static REQUEST reqst = { checkup_option, NULL }; - int inited = 0; - int n_vec_plot = 0; + int inited = 0; + int n_vec_plot = 0; /* Exit if nothing is being plotted */ for (v = pl->pl_dvecs; v; v = v->v_next) { @@ -878,7 +880,8 @@ static int iplot(struct plot *pl, int id) return 0; } - if (len == IPOINTMIN || !id) { /* Do initialization */ + id = db->db_graphid; + if (!id) { /* Do initialization */ unsigned int index, node_len; char commandline[4196]; @@ -889,6 +892,14 @@ static int iplot(struct plot *pl, int id) lims = ft_minmax(xs, TRUE); xlims[0] = lims[0]; xlims[1] = lims[1]; + if (window) { + if (xlims[1] - xlims[0] > window) { + xlims[1] += window / 3.0; // Assume increasing scale. + xlims[0] = xlims[1] - window; + } else { + xlims[1] = xlims[0] + window; + } + } ylims[0] = HUGE; ylims[1] = -ylims[0]; for (v = pl->pl_dvecs; v; v = v->v_next) { @@ -918,8 +929,7 @@ static int iplot(struct plot *pl, int id) if (ft_grdb) { fprintf(cp_err, - "iplot: after" #IPOINTMIN - ", xlims = %G, %G, ylims = %G, %G\n", + "iplot: at start xlims = %G, %G, ylims = %G, %G\n", xlims[0], xlims[1], ylims[0], ylims[1]); } @@ -944,9 +954,9 @@ static int iplot(struct plot *pl, int id) } inited = 1; - } - else { + } else { /* plot the last points and resize if needed */ + Input(&reqst, NULL); /* Window was closed? */ @@ -955,6 +965,7 @@ static int iplot(struct plot *pl, int id) return 0; /* First see if we have to make the screen bigger */ + dy = (isreal(xs) ? xs->v_realdata[len - 1] : realpart(xs->v_compdata[len - 1])); if (ft_grdb) { @@ -965,8 +976,10 @@ static int iplot(struct plot *pl, int id) stop = HUGE; start = - stop; } + /* checking for x lo */ - while (dy < currentgraph->data.xmin) { + + if (dy < currentgraph->data.xmin) { changed = TRUE; if (ft_grdb) { fprintf(cp_err, "resize: xlo %G -> %G\n", @@ -975,20 +988,25 @@ static int iplot(struct plot *pl, int id) (currentgraph->data.xmax - currentgraph->data.xmin) * XFACTOR); } + /* set the new x lo value */ - currentgraph->data.xmin -= - (currentgraph->data.xmax - currentgraph->data.xmin) - * XFACTOR; - if (currentgraph->data.xmin < start) { - currentgraph->data.xmin = start; - break; + + if (window) { + currentgraph->data.xmin = dy - (window / 3.0); + } else { + currentgraph->data.xmin -= + (currentgraph->data.xmax - currentgraph->data.xmin) * + XFACTOR; } + if (currentgraph->data.xmin < start) + currentgraph->data.xmin = start; } - if (currentgraph->data.xmax < currentgraph->data.xmin) { - currentgraph->data.xmax = currentgraph->data.xmin; - } + /* checking for x hi */ - while (dy > currentgraph->data.xmax) { + + if (window && changed) { + currentgraph->data.xmax = currentgraph->data.xmin + window; + } else if (dy > currentgraph->data.xmax) { changed = TRUE; if (ft_grdb) { fprintf(cp_err, "resize: xhi %G -> %G\n", @@ -997,16 +1015,26 @@ static int iplot(struct plot *pl, int id) (currentgraph->data.xmax - currentgraph->data.xmin) * XFACTOR); } + /* set the new x hi value */ - currentgraph->data.xmax += - (currentgraph->data.xmax - currentgraph->data.xmin) * - XFACTOR; - if (currentgraph->data.xmax > stop) { - currentgraph->data.xmax = stop; - break; + + if (window) { + currentgraph->data.xmax = dy + (window / 3.0); + currentgraph->data.xmin = currentgraph->data.xmax - window; + } else { + currentgraph->data.xmax += + (currentgraph->data.xmax - currentgraph->data.xmin) * + XFACTOR; } + if (currentgraph->data.xmax > stop) + currentgraph->data.xmax = stop; } + + if (currentgraph->data.xmax < currentgraph->data.xmin) + currentgraph->data.xmax = currentgraph->data.xmin; + /* checking for all y values */ + for (v = pl->pl_dvecs; v; v = v->v_next) { if (!(v->v_flags & VF_PLOT)) { continue; @@ -1035,10 +1063,9 @@ static int iplot(struct plot *pl, int id) /* currentgraph->data.ymin = dy; currentgraph->data.ymin *= (1 + YFACTOR); */ } - if (currentgraph->data.ymax < currentgraph->data.ymin) { - currentgraph->data.ymax = currentgraph->data.ymin; - } + /* checking for y hi */ + while (dy > currentgraph->data.ymax) { changed = TRUE; if (ft_grdb) { @@ -1050,8 +1077,8 @@ static int iplot(struct plot *pl, int id) } /* set the new y hi value */ currentgraph->data.ymax += - (currentgraph->data.ymax - currentgraph->data.ymin) - * YFACTOR; + (currentgraph->data.ymax - currentgraph->data.ymin) * + YFACTOR; /* currentgraph->data.ymax += (dy - currentgraph->data.ymax) * YFACTOR;*/ /* currentgraph->data.ymax = dy; @@ -1059,6 +1086,9 @@ static int iplot(struct plot *pl, int id) } } + if (currentgraph->data.ymax < currentgraph->data.ymin) + currentgraph->data.ymax = currentgraph->data.ymin; + if (changed) { /* Redraw everything. */ gr_pmsg("Resizing screen"); @@ -1182,7 +1212,7 @@ void gr_iplot(struct plot *plot) set(plot, db, TRUE, VF_PLOT); dontpop = 0; - if (iplot(plot, db->db_graphid)) { + if (iplot(plot, db)) { /* graph just assigned */ db->db_graphid = currentgraph->graphid; dontpop = 1; From d4d576d69599b6857162fc1a770f441a8b3f7ff1 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 2 May 2023 18:15:22 +0200 Subject: [PATCH 31/72] Example input file for 'iplot -w' option --- examples/xspice/pll/pll-xspice-fstep.cir | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/xspice/pll/pll-xspice-fstep.cir b/examples/xspice/pll/pll-xspice-fstep.cir index d66a96061..0bb2fb17f 100644 --- a/examples/xspice/pll/pll-xspice-fstep.cir +++ b/examples/xspice/pll/pll-xspice-fstep.cir @@ -66,9 +66,10 @@ abridge-w1 [d_divout d_ref d_Un d_D] [s1 s2 u1 d1] dac1 ; change to d_u or d_Un .control save cont s1 s2 u1 d1 +set xbrushwidth=2 let isbmode = $?batchmode if isbmode = 0 - iplot cont + iplot -w $&simtime cont endif * calculate breakpoint for switching frequency let t1_3 = simtime/3 From 48668c7d6e8e2d5322f72250597b6490677234ec Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Tue, 2 May 2023 23:32:22 +0200 Subject: [PATCH 32/72] make accessible --- src/include/ngspice/osdiitf.h | 1 + src/osdi/osdiinit.c | 26 ++++++++++++++++++++------ src/osdi/osdiregistry.c | 6 +++++- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/include/ngspice/osdiitf.h b/src/include/ngspice/osdiitf.h index 5c84ed0ad..4f93d6c28 100644 --- a/src/include/ngspice/osdiitf.h +++ b/src/include/ngspice/osdiitf.h @@ -19,6 +19,7 @@ typedef struct OsdiRegistryEntry { uint32_t inst_offset; uint32_t dt; uint32_t temp; + bool has_m; } OsdiRegistryEntry; typedef struct OsdiObjectFile { diff --git a/src/osdi/osdiinit.c b/src/osdi/osdiinit.c index 7d83b5dfe..f74867d74 100644 --- a/src/osdi/osdiinit.c +++ b/src/osdi/osdiinit.c @@ -32,7 +32,7 @@ * descr->param_opvar to the internal ngspice representation (IFparm). */ static int write_param_info(IFparm **dst, const OsdiDescriptor *descr, - uint32_t start, uint32_t end) { + uint32_t start, uint32_t end, bool has_m) { for (uint32_t i = start; i < end; i++) { OsdiParamOpvar *para = &descr->param_opvar[i]; uint32_t num_names = para->num_alias + 1; @@ -68,12 +68,23 @@ static int write_param_info(IFparm **dst, const OsdiDescriptor *descr, dataType |= IF_UNINTERESTING; } char *para_name = copy(para->name[j]); + if (para_name[0] == '$') { + para_name[0] = '_'; + } strtolower(para_name); (*dst)[j] = (IFparm){.keyword = para_name, .id = (int)i, .description = para->description, .dataType = dataType}; } + if (!has_m && !strcmp(para->name[0], "$mfactor")) { + (*dst)[num_names] = (IFparm){.keyword = "m", + .id = (int)i, + .description = para->description, + .dataType = dataType}; + *dst += 1; + } + *dst += num_names; } @@ -110,6 +121,10 @@ extern SPICEdev *osdi_create_spicedev(const OsdiRegistryEntry *entry) { *num_instance_para_names += 1; } + if (!entry->has_m) { + *num_instance_para_names += 1; + } + IFparm *instance_para_names = TMALLOC(IFparm, *num_instance_para_names); IFparm *dst = instance_para_names; @@ -124,9 +139,9 @@ extern SPICEdev *osdi_create_spicedev(const OsdiRegistryEntry *entry) { "Instance temperature"}; dst += 1; } - write_param_info(&dst, descr, 0, descr->num_instance_params); + write_param_info(&dst, descr, 0, descr->num_instance_params, entry->has_m); write_param_info(&dst, descr, descr->num_params, - descr->num_params + descr->num_opvars); + descr->num_params + descr->num_opvars, true); // allocate and fill model params int *num_model_para_names = TMALLOC(int, 1); @@ -135,7 +150,8 @@ extern SPICEdev *osdi_create_spicedev(const OsdiRegistryEntry *entry) { } IFparm *model_para_names = TMALLOC(IFparm, *num_model_para_names); dst = model_para_names; - write_param_info(&dst, descr, descr->num_instance_params, descr->num_params); + write_param_info(&dst, descr, descr->num_instance_params, descr->num_params, + true); // Allocate SPICE device SPICEdev *OSDIinfo = TMALLOC(SPICEdev, 1); @@ -181,7 +197,5 @@ extern SPICEdev *osdi_create_spicedev(const OsdiRegistryEntry *entry) { OSDIinfo->DEVpzLoad = OSDIpzLoad; OSDIinfo->DEVtrunc = OSDItrunc; - - return OSDIinfo; } diff --git a/src/osdi/osdiregistry.c b/src/osdi/osdiregistry.c index e3362fa38..36d989b3e 100644 --- a/src/osdi/osdiregistry.c +++ b/src/osdi/osdiregistry.c @@ -358,12 +358,15 @@ extern OsdiObjectFile load_object_file(const char *input) { const OsdiDescriptor *descr = &OSDI_DESCRIPTORS[i]; uint32_t dt = descr->num_params + descr->num_opvars; + bool has_m = false; uint32_t temp = descr->num_params + descr->num_opvars + 1; for (uint32_t param_id = 0; param_id < descr->num_params; param_id++) { OsdiParamOpvar *param = &descr->param_opvar[param_id]; for (uint32_t j = 0; j < 1 + param->num_alias; j++) { char *name = param->name[j]; - if (!strcmp(name, "dt")) { + if (!strcmp(name, "m")) { + has_m = true; + } else if (!strcmp(name, "dt")) { dt = UINT32_MAX; } else if (!strcasecmp(name, "dtemp") || !strcasecmp(name, "dt")) { dt = param_id; @@ -382,6 +385,7 @@ extern OsdiObjectFile load_object_file(const char *input) { .inst_offset = (uint32_t)inst_off, .dt = dt, .temp = temp, + .has_m = has_m, }; } From 5047a191129cf6c8d0ed36f6fcab14ab7f01232f Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 7 May 2023 15:48:06 +0200 Subject: [PATCH 33/72] Enable history substitution of interactive commands only when variable 'histsubst' is set. This feature is in conflict with ! (logic inversion) in .control language logic expressions. --- src/frontend/init.c | 5 +++++ src/frontend/parser/cshpar.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/frontend/init.c b/src/frontend/init.c index 6c3a77513..a19d2f4db 100644 --- a/src/frontend/init.c +++ b/src/frontend/init.c @@ -20,6 +20,7 @@ cp_init(void) cp_chars[128] cp_maxhistlength (set to 10000 in com_history.c) cp_curin, cp_curout, cp_curerr (defined in streams.c) + cp_no_histsubst */ { cp_vset("history", CP_NUM, &cp_maxhistlength); @@ -28,6 +29,10 @@ cp_init(void) cp_curout = stdout; cp_curerr = stderr; + /* Enable history substitution */ + if (cp_getvar("histsubst", CP_BOOL, NULL, 0)) + cp_no_histsubst = FALSE; + /* io redirection in streams.c: cp_in set to cp_curin etc. */ cp_ioreset(); diff --git a/src/frontend/parser/cshpar.c b/src/frontend/parser/cshpar.c index 35a31c9e9..b4cfa7fc8 100644 --- a/src/frontend/parser/cshpar.c +++ b/src/frontend/parser/cshpar.c @@ -37,8 +37,8 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group #include #endif - -bool cp_no_histsubst = FALSE; /* perform history substitution by default */ +/* perform history substitution only when variable 'histsubst' is set */ +bool cp_no_histsubst = TRUE; /* Things go as follows: * (1) Read the line and do some initial quoting (by setting the 8th bit), From 465a64661c2997f14bba624ba4b33e2a3a74cb1b Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 8 May 2023 10:56:10 +0200 Subject: [PATCH 34/72] Add vto model parameter (the default has changed!), add .ic to ease op and immediately start oscillation. --- examples/vdmos/ro_11_vdmos.sp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/vdmos/ro_11_vdmos.sp b/examples/vdmos/ro_11_vdmos.sp index f277dc49a..23b2b7cc9 100644 --- a/examples/vdmos/ro_11_vdmos.sp +++ b/examples/vdmos/ro_11_vdmos.sp @@ -18,17 +18,18 @@ xinv7 9 8 1 0 inv xinv8 10 9 1 0 inv xinv9 2 10 1 0 inv -.model N1 vdmos cgdmin=0.05p cgdmax=0.2p a=1.2 cgs=0.15p rg=10 kp=1e-5 rb=1e7 cjo=1n ksubthres=0.2 -.model P1 vdmos cgdmin=0.05p cgdmax=0.2p a=1.2 cgs=0.15p rg=10 kp=1e-5 rb=1e7 cjo=1n pchan ksubthres=0.2 +.model N1 vdmos vto=1 cgdmin=0.05p cgdmax=0.2p a=1.2 cgs=0.15p rg=10 kp=1e-5 rb=1e7 cjo=1n ksubthres=0.2 +.model P1 vdmos vto=-1 cgdmin=0.05p cgdmax=0.2p a=1.2 cgs=0.15p rg=10 kp=1e-5 rb=1e7 cjo=1n pchan ksubthres=0.2 -.tran 0.1n 5u +.tran 0.1n 10u +.ic v(6)=2.5 .control run rusage * current and output in a single plot -plot v(6) 1000*(-I(vdd)) ylimit -1 6 +plot v(6) 50000*(-I(vdd)) ylimit -1 6 .endc .end From 1f58cd761836054e83225cd874637cbf95ed993d Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 8 May 2023 20:18:55 +0200 Subject: [PATCH 35/72] Plug a memory leak --- src/spicelib/analysis/noisean.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/spicelib/analysis/noisean.c b/src/spicelib/analysis/noisean.c index ec5d0c281..3032858ee 100644 --- a/src/spicelib/analysis/noisean.c +++ b/src/spicelib/analysis/noisean.c @@ -232,16 +232,16 @@ NOISEan(CKTcircuit* ckt, int restart) error = CKTload(ckt); if (error) return(error); - error = CKTnames(ckt, &numNames, &nameList); - if (error) return(error); - if (ckt->CKTkeepOpInfo) { + error = CKTnames(ckt, &numNames, &nameList); + if (error) return(error); /* Dump operating point. */ error = SPfrontEnd->OUTpBeginPlot(ckt, ckt->CKTcurJob, "NOISE Operating Point", NULL, IF_REAL, numNames, nameList, IF_REAL, &plot); + txfree(nameList); if (error) return(error); CKTdump(ckt, 0.0, plot); SPfrontEnd->OUTendPlot(plot); From 4356a631be8be9496c1a282c7de1f94b06f36303 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 10 May 2023 14:06:07 +0200 Subject: [PATCH 36/72] Add rusage to measure simulation time. --- examples/p-to-n-examples/555-timer-2.cir | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/p-to-n-examples/555-timer-2.cir b/examples/p-to-n-examples/555-timer-2.cir index c34619948..1ea194c71 100644 --- a/examples/p-to-n-examples/555-timer-2.cir +++ b/examples/p-to-n-examples/555-timer-2.cir @@ -86,6 +86,7 @@ if $?batchmode else run + rusage time plot v(16) v(13) v(17) v(1)+6 v(4)+6 v(3)+6 end .endc From 8b8200df8800db18191040e67fa3b2cd7448d6cc Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 12 May 2023 16:59:27 +0200 Subject: [PATCH 37/72] Improve error messages --- src/spicelib/analysis/optran.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/spicelib/analysis/optran.c b/src/spicelib/analysis/optran.c index 3f32263d2..6ec76128f 100644 --- a/src/spicelib/analysis/optran.c +++ b/src/spicelib/analysis/optran.c @@ -164,14 +164,14 @@ void com_optran(wordlist* wl) { if (err || (*stpstr != '\0')) goto bugquit; if (opstepsize > opfinaltime) { - fprintf(stderr, "Error: Step size larger than final time.\n"); + fprintf(stderr, "Error: Optran step size larger than final time.\n"); goto bugquit; } if (opstepsize > opfinaltime/50.) { - fprintf(stderr, "Warning: Step size potentially too small.\n"); + fprintf(stderr, "Warning: Optran step size potentially too small.\n"); } if (opramptime > opfinaltime) { - fprintf(stderr, "Error: Ramp time larger than final time.\n"); + fprintf(stderr, "Error: Optran ramp time larger than final time.\n"); goto bugquit; } /* optran deselected by setting opstepsize to 0 */ From b97c2738053764370c063a14e1a00aaef18accc0 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 12 May 2023 17:00:08 +0200 Subject: [PATCH 38/72] Prevent a crash when number of nodes differs in subckt and X call. --- src/frontend/inpc_probe.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/frontend/inpc_probe.c b/src/frontend/inpc_probe.c index 7ef70ce93..825eef914 100644 --- a/src/frontend/inpc_probe.c +++ b/src/frontend/inpc_probe.c @@ -895,6 +895,9 @@ void inp_probe(struct card* deck) else if (err == 2) { fprintf(stderr, "Warning: Zero voltage sources already set,\n .probe %s will be ignored\n", wltmp->wl_word); } + else if (err == 3) { + fprintf(stderr, "Warning: Number of nodes mismatch,\n .probe %s will be ignored\n", wltmp->wl_word); + } continue; } else if (!haveall) { @@ -1358,6 +1361,15 @@ static int setallvsources(struct card *tmpcard, NGHASHPTR instances, char *instn char nodenumstr[3]; char *nodename1 = get_terminal_name(instname, itoa10(nodenum, nodenumstr), instances); + if (!nodename1) { + tfree(begstr); + tfree(strnode1); + ds_free(&BVrefline); + ds_free(&Bpowerline); + ds_free(&Bpowersave); + return 3; + } + newline = tprintf("%s %s %s", begstr, newnode, instline); char* vline = tprintf("vcurr_%s:probe_int_%s:%s_%s %s %s 0", instname, nodename1, nodenumstr, strnode1, strnode1, newnode); From 73e3e7f9521c11c480d8c82c78be5766964a9094 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 12 May 2023 20:02:31 +0200 Subject: [PATCH 39/72] Correct the warning message --- src/spicelib/analysis/optran.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spicelib/analysis/optran.c b/src/spicelib/analysis/optran.c index 6ec76128f..6f454931f 100644 --- a/src/spicelib/analysis/optran.c +++ b/src/spicelib/analysis/optran.c @@ -168,7 +168,7 @@ void com_optran(wordlist* wl) { goto bugquit; } if (opstepsize > opfinaltime/50.) { - fprintf(stderr, "Warning: Optran step size potentially too small.\n"); + fprintf(stderr, "Warning: Optran step size potentially too large.\n"); } if (opramptime > opfinaltime) { fprintf(stderr, "Error: Optran ramp time larger than final time.\n"); From 2206956bc1cfb5fec33bd93c1eb6368e3c918f30 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 13 May 2023 23:43:44 +0200 Subject: [PATCH 40/72] Make error message more verbose and useful --- src/frontend/numparam/xpressn.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/frontend/numparam/xpressn.c b/src/frontend/numparam/xpressn.c index a8ac9b6f5..7df535340 100644 --- a/src/frontend/numparam/xpressn.c +++ b/src/frontend/numparam/xpressn.c @@ -1611,8 +1611,12 @@ nupa_subcktcall(dico_t *dico, const char *s, const char *x, jp = getexpress(dico, NULL, &ustr, jp); } else { jp++; - if ((unsigned char) (*kp) > ' ') - message(dico, "Subckt call, symbol %c not understood\n", *kp); + if ((unsigned char)(*kp) > ' ') { + fprintf(stderr, "Error in line: %s\n", x); + fprintf(stderr, " near %s\n", kp); + message(dico, "Subckt call, symbol %c not understood\n\n", *kp); + + } } /* Substitute the parameter for one of the '$' characters From b271b6d9e3e76c742dcadefe76b568dbcd16af58 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 17 May 2023 09:32:23 +0200 Subject: [PATCH 41/72] safeguard against crash upon buggy input --- src/frontend/inpcom.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 1f4994c7b..dd83a62f4 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -4483,7 +4483,8 @@ static int inp_get_param_level( return level; } - +/* Return the number of terminals for a given device, characterized by + the first letter of its instance line. Returns 0 upon error. */ int get_number_terminals(char *c) { int i, j, k; @@ -4491,6 +4492,9 @@ int get_number_terminals(char *c) char nam_buf[128]; bool area_found = FALSE; + if (!c) + return 0; + switch (*c) { case 'r': case 'c': From edf2c625e15acaaa13738d464845b5af23fd5097 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 17 May 2023 10:08:38 +0200 Subject: [PATCH 42/72] Safeguard against bad arguments (no crash upon NULL) --- src/spicelib/parser/inpptree.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/spicelib/parser/inpptree.c b/src/spicelib/parser/inpptree.c index 4828c8fd4..398771048 100644 --- a/src/spicelib/parser/inpptree.c +++ b/src/spicelib/parser/inpptree.c @@ -1112,6 +1112,11 @@ INPparseNode *PT_mkfnode(const char *fname, INPparseNode * arg) return mkfirst(NULL, arg); } + if (!arg) { + fprintf(stderr, "Error: bad function arguments \n"); + return mkfirst(NULL, arg); + } + /* Make sure the case is ok. */ (void)strncpy(buf, fname, 127); buf[127] = 0; From 8f2d311062db776723616798965c887f84c83fd4 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 21 May 2023 12:16:13 +0200 Subject: [PATCH 43/72] More info --- examples/osdi/psp103/c7552_ann_psp.net | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/osdi/psp103/c7552_ann_psp.net b/examples/osdi/psp103/c7552_ann_psp.net index 526240a58..78c0a5fc7 100644 --- a/examples/osdi/psp103/c7552_ann_psp.net +++ b/examples/osdi/psp103/c7552_ann_psp.net @@ -1,6 +1,7 @@ -* ISCAS85 benchmark circuit SPICE netlist +* ISCAS85 benchmark circuit SPICE netlist, PSP103 * generated by spicegen.pl 1.0 * by Jingye Xu @ VLSI group, Dept of ECE, UIC +* Modified for PSP103 model via OSDI/OpenVAF by Holger Vogt * Path to the models .include Modelcards/psp103_nmos-2.mod From ba2facc718860c2afa7ee0797a26261878952dc9 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 21 May 2023 12:16:33 +0200 Subject: [PATCH 44/72] remove unused header file --- visualc/vngspice-fftw.vcxproj | 1 - visualc/vngspice.vcxproj | 1 - 2 files changed, 2 deletions(-) diff --git a/visualc/vngspice-fftw.vcxproj b/visualc/vngspice-fftw.vcxproj index d44b3c013..10bb37c03 100644 --- a/visualc/vngspice-fftw.vcxproj +++ b/visualc/vngspice-fftw.vcxproj @@ -935,7 +935,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 f767965c8..3d14b4ed2 100644 --- a/visualc/vngspice.vcxproj +++ b/visualc/vngspice.vcxproj @@ -942,7 +942,6 @@ - From 3071cdd2d533133b279260caf59f2703e76d9ca3 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 22 May 2023 14:46:17 +0200 Subject: [PATCH 45/72] .csparam: Add some safeguarding against wrong input and crash, allow multiple parameters in a .csparam row (like .param). --- src/frontend/inp.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/frontend/inp.c b/src/frontend/inp.c index aca467a86..21a5dc86a 100644 --- a/src/frontend/inp.c +++ b/src/frontend/inp.c @@ -890,23 +890,35 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) /* handle .if ... .elseif ... .else ... .endif statements. */ dotifeval(deck); + /* get csparams and create vectors, available + in plot 'const' of a .control section */ for (dd = deck; dd; dd = dd->nextcard) { - /* get csparams and create vectors, being - available in .control section, in plot 'const' */ if (ciprefix(".csparam", dd->line)) { wordlist *wlist = NULL; char *cstoken[3]; int i; dd->line[0] = '*'; s = skip_ws(dd->line + 8); - cstoken[0] = gettok_char(&s, '=', FALSE, FALSE); - cstoken[1] = gettok_char(&s, '=', TRUE, FALSE); - cstoken[2] = gettok(&s); - for (i = 3; --i >= 0; ) { - wlist = wl_cons(cstoken[i], wlist); + while (s && *s) { + cstoken[0] = gettok_char(&s, '=', FALSE, FALSE); + cstoken[1] = gettok_char(&s, '=', TRUE, FALSE); + cstoken[2] = gettok(&s); + /* guard against buggy input line */ + if (!cstoken[0] || !cstoken[1] || !cstoken[2] || strchr(cstoken[2],'=')) { + tfree(cstoken[0]); + tfree(cstoken[1]); + tfree(cstoken[2]); + fprintf(stderr, "Warning: bad csparam definition, skipped!\n"); + fprintf(stderr, " in line %d, .%s\n\n", dd->linenum, dd->line + 1); + continue; + } + for (i = 3; --i >= 0; ) { + wlist = wl_cons(cstoken[i], wlist); + } + com_let(wlist); + wl_free(wlist); + wlist = NULL; } - com_let(wlist); - wl_free(wlist); } } From 61f7188ef0853b361f469cb378dce4d34248c96d Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 22 May 2023 15:18:39 +0200 Subject: [PATCH 46/72] Slightly improve error handling and warning message --- src/frontend/inp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/frontend/inp.c b/src/frontend/inp.c index 21a5dc86a..ed9415156 100644 --- a/src/frontend/inp.c +++ b/src/frontend/inp.c @@ -900,17 +900,18 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) dd->line[0] = '*'; s = skip_ws(dd->line + 8); while (s && *s) { + char* nexttoken = s; cstoken[0] = gettok_char(&s, '=', FALSE, FALSE); cstoken[1] = gettok_char(&s, '=', TRUE, FALSE); cstoken[2] = gettok(&s); /* guard against buggy input line */ if (!cstoken[0] || !cstoken[1] || !cstoken[2] || strchr(cstoken[2],'=')) { + fprintf(stderr, "Warning: bad csparam definition, %s skipped!\n", nexttoken); + fprintf(stderr, " See line %d, .%s\n\n", dd->linenum, dd->line + 1); tfree(cstoken[0]); tfree(cstoken[1]); tfree(cstoken[2]); - fprintf(stderr, "Warning: bad csparam definition, skipped!\n"); - fprintf(stderr, " in line %d, .%s\n\n", dd->linenum, dd->line + 1); - continue; + break; } for (i = 3; --i >= 0; ) { wlist = wl_cons(cstoken[i], wlist); From 5f39fd80fb1def534afbe4e6da17b8cc75043e8f Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 26 May 2023 12:16:55 +0200 Subject: [PATCH 47/72] re-formatting the code --- src/spicelib/devices/ltra/ltraacct.c | 492 +++++++++++++-------------- 1 file changed, 245 insertions(+), 247 deletions(-) diff --git a/src/spicelib/devices/ltra/ltraacct.c b/src/spicelib/devices/ltra/ltraacct.c index 2615100e7..f8dcd0801 100644 --- a/src/spicelib/devices/ltra/ltraacct.c +++ b/src/spicelib/devices/ltra/ltraacct.c @@ -10,285 +10,283 @@ Author: 1990 Jaijeet S. Roychowdhury #include "ngspice/suffix.h" int -LTRAaccept(CKTcircuit *ckt, GENmodel *inModel) +LTRAaccept(CKTcircuit* ckt, GENmodel* inModel) { - LTRAmodel *model = (LTRAmodel *) inModel; - LTRAinstance *here; - double v1, v2, v3, v4; - double v5, v6, d1, d2, d3, d4; - int tmp_test; - int error; - int compact = 1; + LTRAmodel* model = (LTRAmodel*)inModel; + LTRAinstance* here; + double v1, v2, v3, v4; + double v5, v6, d1, d2, d3, d4; + int tmp_test; + int error; + int compact = 1; - /* loop through all the transmission line models */ - for (; model != NULL; model = LTRAnextModel(model)) { + /* loop through all the transmission line models */ + for (; model != NULL; model = LTRAnextModel(model)) { - if (ckt->CKTmode & MODEINITTRAN) { + if (ckt->CKTmode & MODEINITTRAN) { #define LTRAmemMANAGE(a,b) \ - if ( a != NULL) FREE(a);\ - a = TMALLOC(double, b); + if ( a != NULL) FREE(a);\ + a = TMALLOC(double, b); - model->LTRAmodelListSize = 10; + model->LTRAmodelListSize = 10; + LTRAmemMANAGE(model->LTRAh1dashCoeffs, model->LTRAmodelListSize) + LTRAmemMANAGE(model->LTRAh2Coeffs, model->LTRAmodelListSize) + LTRAmemMANAGE(model->LTRAh3dashCoeffs, model->LTRAmodelListSize) + } + if (ckt->CKTtimeIndex >= model->LTRAmodelListSize) { /* need more space */ + model->LTRAmodelListSize += ckt->CKTsizeIncr; - LTRAmemMANAGE(model->LTRAh1dashCoeffs, model->LTRAmodelListSize) - LTRAmemMANAGE(model->LTRAh2Coeffs, model->LTRAmodelListSize) - LTRAmemMANAGE(model->LTRAh3dashCoeffs, model->LTRAmodelListSize) - } - if (ckt->CKTtimeIndex >= model->LTRAmodelListSize) { /* need more space */ - model->LTRAmodelListSize += ckt->CKTsizeIncr; + model->LTRAh1dashCoeffs = TREALLOC(double, model->LTRAh1dashCoeffs, model->LTRAmodelListSize); + model->LTRAh2Coeffs = TREALLOC(double, model->LTRAh2Coeffs, model->LTRAmodelListSize); + model->LTRAh3dashCoeffs = TREALLOC(double, model->LTRAh3dashCoeffs, model->LTRAmodelListSize); + } + /* loop through all the instances of the model */ + for (here = LTRAinstances(model); here != NULL; + here = LTRAnextInstance(here)) { + if (ckt->CKTmode & MODEINITTRAN) { + here->LTRAinstListSize = 10; - model->LTRAh1dashCoeffs = TREALLOC(double, model->LTRAh1dashCoeffs, model->LTRAmodelListSize); - model->LTRAh2Coeffs = TREALLOC(double, model->LTRAh2Coeffs, model->LTRAmodelListSize); - model->LTRAh3dashCoeffs = TREALLOC(double, model->LTRAh3dashCoeffs, model->LTRAmodelListSize); - } - /* loop through all the instances of the model */ - for (here = LTRAinstances(model); here != NULL; - here = LTRAnextInstance(here)) { + LTRAmemMANAGE(here->LTRAv1, here->LTRAinstListSize) + LTRAmemMANAGE(here->LTRAi1, here->LTRAinstListSize) + LTRAmemMANAGE(here->LTRAv2, here->LTRAinstListSize) + LTRAmemMANAGE(here->LTRAi2, here->LTRAinstListSize) + } + /* + * why is this here? ask TQ + * + * if (ckt->CKTtimeIndex == 0? 1: (ckt->CKTtime- + * (ckt->CKTtimePoints+ckt->CKTtimeIndex-1) > ckt->CKTminBreak)) { + * + */ + if (ckt->CKTtimeIndex >= here->LTRAinstListSize) { /* need more space */ + here->LTRAinstListSize += ckt->CKTsizeIncr; - if (ckt->CKTmode & MODEINITTRAN) { - here->LTRAinstListSize = 10; + here->LTRAv1 = TREALLOC(double, here->LTRAv1, here->LTRAinstListSize); + here->LTRAi1 = TREALLOC(double, here->LTRAi1, here->LTRAinstListSize); + here->LTRAi2 = TREALLOC(double, here->LTRAi2, here->LTRAinstListSize); + here->LTRAv2 = TREALLOC(double, here->LTRAv2, here->LTRAinstListSize); + } + *(here->LTRAv1 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + + here->LTRAposNode1) - *(ckt->CKTrhsOld + + here->LTRAnegNode1); + *(here->LTRAv2 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + + here->LTRAposNode2) - *(ckt->CKTrhsOld + + here->LTRAnegNode2); + *(here->LTRAi1 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + + here->LTRAbrEq1); + *(here->LTRAi2 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + + here->LTRAbrEq2); - LTRAmemMANAGE(here->LTRAv1, here->LTRAinstListSize) - LTRAmemMANAGE(here->LTRAi1, here->LTRAinstListSize) - LTRAmemMANAGE(here->LTRAv2, here->LTRAinstListSize) - LTRAmemMANAGE(here->LTRAi2, here->LTRAinstListSize) - } - /* - * why is this here? ask TQ - * - * if (ckt->CKTtimeIndex == 0? 1: (ckt->CKTtime- - * (ckt->CKTtimePoints+ckt->CKTtimeIndex-1) > ckt->CKTminBreak)) { - * - */ - if (ckt->CKTtimeIndex >= here->LTRAinstListSize) { /* need more space */ - here->LTRAinstListSize += ckt->CKTsizeIncr; + if (ckt->CKTtryToCompact && (ckt->CKTtimeIndex >= 2)) { - here->LTRAv1 = TREALLOC(double, here->LTRAv1, here->LTRAinstListSize); - here->LTRAi1 = TREALLOC(double, here->LTRAi1, here->LTRAinstListSize); - here->LTRAi2 = TREALLOC(double, here->LTRAi2, here->LTRAinstListSize); - here->LTRAv2 = TREALLOC(double, here->LTRAv2, here->LTRAinstListSize); - } - *(here->LTRAv1 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + - here->LTRAposNode1) - *(ckt->CKTrhsOld + - here->LTRAnegNode1); - *(here->LTRAv2 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + - here->LTRAposNode2) - *(ckt->CKTrhsOld + - here->LTRAnegNode2); - *(here->LTRAi1 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + - here->LTRAbrEq1); - *(here->LTRAi2 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + - here->LTRAbrEq2); + /* + * figure out if the last 3 points lie on a st. line for all the + * terminal variables + */ + { + double t1, t2, t3; - if (ckt->CKTtryToCompact && (ckt->CKTtimeIndex >= 2)) { + t1 = *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 2); + t2 = *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1); + t3 = *(ckt->CKTtimePoints + ckt->CKTtimeIndex); - /* - * figure out if the last 3 points lie on a st. line for all the - * terminal variables - */ - { - double t1, t2, t3; - - t1 = *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 2); - t2 = *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1); - t3 = *(ckt->CKTtimePoints + ckt->CKTtimeIndex); - - if (compact) { - compact = LTRAstraightLineCheck(t1, - *(here->LTRAv1 + ckt->CKTtimeIndex - 2), - t2, *(here->LTRAv1 + ckt->CKTtimeIndex - 1), - t3, *(here->LTRAv1 + ckt->CKTtimeIndex), - model->LTRAstLineReltol, model->LTRAstLineAbstol); - } - if (compact) { - compact = LTRAstraightLineCheck(t1, - *(here->LTRAv2 + ckt->CKTtimeIndex - 2), - t2, *(here->LTRAv2 + ckt->CKTtimeIndex - 1), - t3, *(here->LTRAv2 + ckt->CKTtimeIndex), - model->LTRAstLineReltol, model->LTRAstLineAbstol); - } - if (compact) { - compact = LTRAstraightLineCheck(t1, - *(here->LTRAi1 + ckt->CKTtimeIndex - 2), - t2, *(here->LTRAi1 + ckt->CKTtimeIndex - 1), - t3, *(here->LTRAi1 + ckt->CKTtimeIndex), - model->LTRAstLineReltol, model->LTRAstLineAbstol); - } - if (compact) { - compact = LTRAstraightLineCheck(t1, - *(here->LTRAi2 + ckt->CKTtimeIndex - 2), - t2, *(here->LTRAi2 + ckt->CKTtimeIndex - 1), - t3, *(here->LTRAi2 + ckt->CKTtimeIndex), - model->LTRAstLineReltol, model->LTRAstLineAbstol); - } - } - } - if (ckt->CKTtimeIndex > 0) { + if (compact) { + compact = LTRAstraightLineCheck(t1, + *(here->LTRAv1 + ckt->CKTtimeIndex - 2), + t2, *(here->LTRAv1 + ckt->CKTtimeIndex - 1), + t3, *(here->LTRAv1 + ckt->CKTtimeIndex), + model->LTRAstLineReltol, model->LTRAstLineAbstol); + } + if (compact) { + compact = LTRAstraightLineCheck(t1, + *(here->LTRAv2 + ckt->CKTtimeIndex - 2), + t2, *(here->LTRAv2 + ckt->CKTtimeIndex - 1), + t3, *(here->LTRAv2 + ckt->CKTtimeIndex), + model->LTRAstLineReltol, model->LTRAstLineAbstol); + } + if (compact) { + compact = LTRAstraightLineCheck(t1, + *(here->LTRAi1 + ckt->CKTtimeIndex - 2), + t2, *(here->LTRAi1 + ckt->CKTtimeIndex - 1), + t3, *(here->LTRAi1 + ckt->CKTtimeIndex), + model->LTRAstLineReltol, model->LTRAstLineAbstol); + } + if (compact) { + compact = LTRAstraightLineCheck(t1, + *(here->LTRAi2 + ckt->CKTtimeIndex - 2), + t2, *(here->LTRAi2 + ckt->CKTtimeIndex - 1), + t3, *(here->LTRAi2 + ckt->CKTtimeIndex), + model->LTRAstLineReltol, model->LTRAstLineAbstol); + } + } + } + if (ckt->CKTtimeIndex > 0) { #ifdef NOTDEF - v1 = (*(here->LTRAv1 + ckt->CKTtimeIndex) + - *(here->LTRAi1 + ckt->CKTtimeIndex) * - model->LTRAimped) * model->LTRAattenuation; - v2 = (*(here->LTRAv1 + ckt->CKTtimeIndex - 1) + - *(here->LTRAi1 + ckt->CKTtimeIndex - 1) - * model->LTRAimped) * model->LTRAattenuation; - v3 = (*(here->LTRAv2 + ckt->CKTtimeIndex) + - *(here->LTRAi2 + ckt->CKTtimeIndex) * - model->LTRAimped) * model->LTRAattenuation; - v4 = (*(here->LTRAv2 + ckt->CKTtimeIndex - 1) + - *(here->LTRAi2 + ckt->CKTtimeIndex - 1) * - model->LTRAimped) * model->LTRAattenuation; - if ((fabs(v1 - v2) >= 50 * ckt->CKTreltol * - MAX(fabs(v1), fabs(v2)) + 50 * ckt->CKTvoltTol) || - (fabs(v3 - v4) >= 50 * ckt->CKTreltol * - MAX(fabs(v3), fabs(v4)) + 50 * ckt->CKTvoltTol)) { - /* changing - need to schedule after delay */ - /* - * don't really need this error = - * CKTsetBreak(ckt,ckt->CKTtime+model->LTRAtd); if(error) - * return(error); - */ - /* the PREVIOUS point is the real breakpoint */ - error = CKTsetBreak(ckt, - *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) + - model->LTRAtd); - CKTbreakDump(ckt); - if (error) - return (error); - } + v1 = (*(here->LTRAv1 + ckt->CKTtimeIndex) + + *(here->LTRAi1 + ckt->CKTtimeIndex) * + model->LTRAimped) * model->LTRAattenuation; + v2 = (*(here->LTRAv1 + ckt->CKTtimeIndex - 1) + + *(here->LTRAi1 + ckt->CKTtimeIndex - 1) + * model->LTRAimped) * model->LTRAattenuation; + v3 = (*(here->LTRAv2 + ckt->CKTtimeIndex) + + *(here->LTRAi2 + ckt->CKTtimeIndex) * + model->LTRAimped) * model->LTRAattenuation; + v4 = (*(here->LTRAv2 + ckt->CKTtimeIndex - 1) + + *(here->LTRAi2 + ckt->CKTtimeIndex - 1) * + model->LTRAimped) * model->LTRAattenuation; + if ((fabs(v1 - v2) >= 50 * ckt->CKTreltol * + MAX(fabs(v1), fabs(v2)) + 50 * ckt->CKTvoltTol) || + (fabs(v3 - v4) >= 50 * ckt->CKTreltol * + MAX(fabs(v3), fabs(v4)) + 50 * ckt->CKTvoltTol)) { + /* changing - need to schedule after delay */ + /* + * don't really need this error = + * CKTsetBreak(ckt,ckt->CKTtime+model->LTRAtd); if(error) + * return(error); + */ + /* the PREVIOUS point is the real breakpoint */ + error = CKTsetBreak(ckt, + *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) + + model->LTRAtd); + CKTbreakDump(ckt); + if (error) + return (error); + } #else - /* - * remove the hack here - store the total inputs for the last 2 or 3 - * timesteps - */ + /* + * remove the hack here - store the total inputs for the last 2 or 3 + * timesteps + */ - v1 = (*(here->LTRAv1 + ckt->CKTtimeIndex) + - *(here->LTRAi1 + ckt->CKTtimeIndex) * - model->LTRAimped) * model->LTRAattenuation; - v2 = (*(here->LTRAv1 + ckt->CKTtimeIndex - 1) + - *(here->LTRAi1 + ckt->CKTtimeIndex - 1) * - model->LTRAimped) * model->LTRAattenuation; - v3 = ckt->CKTtimeIndex < 2 ? v2 : (*(here->LTRAv1 + ckt->CKTtimeIndex - 2) + - *(here->LTRAi1 + ckt->CKTtimeIndex - 2) * - model->LTRAimped) * model->LTRAattenuation; - v4 = (*(here->LTRAv2 + ckt->CKTtimeIndex) + - *(here->LTRAi2 + ckt->CKTtimeIndex) * - model->LTRAimped) * model->LTRAattenuation; - v5 = (*(here->LTRAv2 + ckt->CKTtimeIndex - 1) + - *(here->LTRAi2 + ckt->CKTtimeIndex - 1) * - model->LTRAimped) * model->LTRAattenuation; - v6 = ckt->CKTtimeIndex < 2 ? v5 : (*(here->LTRAv2 + ckt->CKTtimeIndex - 2) + - *(here->LTRAi2 + ckt->CKTtimeIndex - 2) * - model->LTRAimped) * model->LTRAattenuation; + v1 = (*(here->LTRAv1 + ckt->CKTtimeIndex) + + *(here->LTRAi1 + ckt->CKTtimeIndex) * + model->LTRAimped) * model->LTRAattenuation; + v2 = (*(here->LTRAv1 + ckt->CKTtimeIndex - 1) + + *(here->LTRAi1 + ckt->CKTtimeIndex - 1) * + model->LTRAimped) * model->LTRAattenuation; + v3 = ckt->CKTtimeIndex < 2 ? v2 : (*(here->LTRAv1 + ckt->CKTtimeIndex - 2) + + *(here->LTRAi1 + ckt->CKTtimeIndex - 2) * + model->LTRAimped) * model->LTRAattenuation; + v4 = (*(here->LTRAv2 + ckt->CKTtimeIndex) + + *(here->LTRAi2 + ckt->CKTtimeIndex) * + model->LTRAimped) * model->LTRAattenuation; + v5 = (*(here->LTRAv2 + ckt->CKTtimeIndex - 1) + + *(here->LTRAi2 + ckt->CKTtimeIndex - 1) * + model->LTRAimped) * model->LTRAattenuation; + v6 = ckt->CKTtimeIndex < 2 ? v5 : (*(here->LTRAv2 + ckt->CKTtimeIndex - 2) + + *(here->LTRAi2 + ckt->CKTtimeIndex - 2) * + model->LTRAimped) * model->LTRAattenuation; - d1 = (v1 - v2) / (*(ckt->CKTtimePoints + ckt->CKTtimeIndex) - - *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1)); - d2 = (ckt->CKTtimeIndex < 2) - ? 0 - : (v2 - v3) / (*(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) - - *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 2)); - d3 = (v4 - v5) / (*(ckt->CKTtimePoints + ckt->CKTtimeIndex) - - *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1)); - d4 = (ckt->CKTtimeIndex < 2) - ? 0 - : (v5 - v6) / (*(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) - - *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 2)); + d1 = (v1 - v2) / (*(ckt->CKTtimePoints + ckt->CKTtimeIndex) - + *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1)); + d2 = (ckt->CKTtimeIndex < 2) + ? 0 + : (v2 - v3) / (*(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) - + *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 2)); + d3 = (v4 - v5) / (*(ckt->CKTtimePoints + ckt->CKTtimeIndex) - + *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1)); + d4 = (ckt->CKTtimeIndex < 2) + ? 0 + : (v5 - v6) / (*(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) - + *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 2)); - /* - * here we have a big problem with the scheme boxed by the *s below. - * Note the following: if LTRAreltol == 1, (assuming LTRAabstol==0) - * then breakpoints are set if and only if d1 and d2 have opposite - * signs or one is zero. If LTRAreltol > 2, breakpoints are never - * set. The problem is that when the waveform is steady at a value, - * small random numerical inaccuracies may produce derivatives of - * opposite sign, and breakpoints get set. This can, in practice, get - * quite killing... To alleviate this, we try to determine if the - * waveform is actually steady using the following tests: 1. Check if - * the maximum difference between v1,v2 and v3 is less than - * 50*CKTreltol*(the average of v1,v2,and v3) + 50*ckt->CKTabstol - * (the 50 has been taken from the NOTDEF section above, reason - * unknown - hopefully there is a good reason for it - ask TQ) - * - * 2. Criterion 1 may be satisfied by a legitimate breakpoint. To - * further check, find one more derivative one timepoint ago and see - * if that is close to d2. If not, then the likelihood of numerical - * inaccuracies is greater... - */ + /* + * here we have a big problem with the scheme boxed by the *s below. + * Note the following: if LTRAreltol == 1, (assuming LTRAabstol==0) + * then breakpoints are set if and only if d1 and d2 have opposite + * signs or one is zero. If LTRAreltol > 2, breakpoints are never + * set. The problem is that when the waveform is steady at a value, + * small random numerical inaccuracies may produce derivatives of + * opposite sign, and breakpoints get set. This can, in practice, get + * quite killing... To alleviate this, we try to determine if the + * waveform is actually steady using the following tests: 1. Check if + * the maximum difference between v1,v2 and v3 is less than + * 50*CKTreltol*(the average of v1,v2,and v3) + 50*ckt->CKTabstol + * (the 50 has been taken from the NOTDEF section above, reason + * unknown - hopefully there is a good reason for it - ask TQ) + * + * 2. Criterion 1 may be satisfied by a legitimate breakpoint. To + * further check, find one more derivative one timepoint ago and see + * if that is close to d2. If not, then the likelihood of numerical + * inaccuracies is greater... + */ - /********************************************************************* - if( (fabs(d1-d2) >= model->LTRAreltol*MAX(fabs(d1),fabs(d2))+ - model->LTRAabstol) || - (fabs(d3-d4) >= model->LTRAreltol*MAX(fabs(d3),fabs(d4))+ - model->LTRAabstol) ) { - *********************************************************************/ + /********************************************************************* + if( (fabs(d1-d2) >= model->LTRAreltol*MAX(fabs(d1),fabs(d2))+ + model->LTRAabstol) || + (fabs(d3-d4) >= model->LTRAreltol*MAX(fabs(d3),fabs(d4))+ + model->LTRAabstol) ) { + *********************************************************************/ #define CHECK(a,b,c) (MAX(MAX(a,b),c)-MIN(MIN(a,b),c) >= \ - fabs(50.0*(ckt->CKTreltol/3.0*(a+b+c) +\ - ckt->CKTabstol))) + fabs(50.0*(ckt->CKTreltol/3.0*(a+b+c) +\ + ckt->CKTabstol))) - tmp_test = (fabs(d1 - d2) - >= model->LTRAreltol * MAX(fabs(d1), fabs(d2)) + - model->LTRAabstol) - && CHECK(v1, v2, v3); - if (tmp_test || ((fabs(d3 - d4) - >= model->LTRAreltol * MAX(fabs(d3), fabs(d4)) + - model->LTRAabstol) - && CHECK(v4, v5, v6))) { - /* criterion 2 not implemented yet... */ - error = CKTsetBreak(ckt, - *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) + - model->LTRAtd); - /* - * this is not necessary - the previous timepoint was the - * breakpoint error = CKTsetBreak(ckt, ckt->CKTtime + - * model->LTRAtd); - */ + tmp_test = (fabs(d1 - d2) + >= model->LTRAreltol * MAX(fabs(d1), fabs(d2)) + + model->LTRAabstol) + && CHECK(v1, v2, v3); + if (tmp_test || ((fabs(d3 - d4) + >= model->LTRAreltol * MAX(fabs(d3), fabs(d4)) + + model->LTRAabstol) + && CHECK(v4, v5, v6))) { + /* criterion 2 not implemented yet... */ + error = CKTsetBreak(ckt, + *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) + + model->LTRAtd); + /* + * this is not necessary - the previous timepoint was the + * breakpoint error = CKTsetBreak(ckt, ckt->CKTtime + + * model->LTRAtd); + */ #ifdef LTRADEBUG - fprintf(stdout, "\nbreakpoints set at %14.14g at %14.14g at time %14.14g\n", ckt->CKTtime + model->LTRAtd, *(ckt->CKTtimePoints + ckt->CKTtimeIndex - - 1) + model->LTRAtd, ckt->CKTtime); - fprintf(stdout, "d1 through d4 are %14.14g %14.14g %14.14g %14.14g\n\n", d1, d2, d3, d4); + fprintf(stdout, "\nbreakpoints set at %14.14g at %14.14g at time %14.14g\n", ckt->CKTtime + model->LTRAtd, *(ckt->CKTtimePoints + ckt->CKTtimeIndex + - 1) + model->LTRAtd, ckt->CKTtime); + fprintf(stdout, "d1 through d4 are %14.14g %14.14g %14.14g %14.14g\n\n", d1, d2, d3, d4); #endif - if (error) - return (error); - } - /* } */ + if (error) + return (error); + } + /* } */ #endif /* NOTDEF */ - } - /* ask TQ } */ + } + /* ask TQ } */ - } /* instance */ - } /* model */ + } /* instance */ + } /* model */ - if (ckt->CKTtryToCompact && compact && (ckt->CKTtimeIndex >= 2)) { + if (ckt->CKTtryToCompact && compact && (ckt->CKTtimeIndex >= 2)) { - /* - * last three timepoints have variables lying on a straight line, do a - * compaction - */ + /* + * last three timepoints have variables lying on a straight line, do a + * compaction + */ - model = (LTRAmodel *) inModel; - for (; model != NULL; model = LTRAnextModel(model)) { - for (here = LTRAinstances(model); here != NULL; - here = LTRAnextInstance(here)) { - *(here->LTRAv1 + ckt->CKTtimeIndex - 1) = *(here->LTRAv1 + - ckt->CKTtimeIndex); - *(here->LTRAv2 + ckt->CKTtimeIndex - 1) = *(here->LTRAv2 + - ckt->CKTtimeIndex); - *(here->LTRAi1 + ckt->CKTtimeIndex - 1) = *(here->LTRAi1 + - ckt->CKTtimeIndex); - *(here->LTRAi2 + ckt->CKTtimeIndex - 1) = *(here->LTRAi2 + - ckt->CKTtimeIndex); - } - } - *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) = - *(ckt->CKTtimePoints + ckt->CKTtimeIndex); - ckt->CKTtimeIndex--; + model = (LTRAmodel*)inModel; + for (; model != NULL; model = LTRAnextModel(model)) { + for (here = LTRAinstances(model); here != NULL; + here = LTRAnextInstance(here)) { + *(here->LTRAv1 + ckt->CKTtimeIndex - 1) = *(here->LTRAv1 + + ckt->CKTtimeIndex); + *(here->LTRAv2 + ckt->CKTtimeIndex - 1) = *(here->LTRAv2 + + ckt->CKTtimeIndex); + *(here->LTRAi1 + ckt->CKTtimeIndex - 1) = *(here->LTRAi1 + + ckt->CKTtimeIndex); + *(here->LTRAi2 + ckt->CKTtimeIndex - 1) = *(here->LTRAi2 + + ckt->CKTtimeIndex); + } + } + *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) = + *(ckt->CKTtimePoints + ckt->CKTtimeIndex); + ckt->CKTtimeIndex--; #ifdef LTRADEBUG - fprintf(stdout, "compacted at time=%g\n", *(ckt->CKTtimePoints + ckt->CKTtimeIndex)); - fflush(stdout); + fprintf(stdout, "compacted at time=%g\n", *(ckt->CKTtimePoints + ckt->CKTtimeIndex)); + fflush(stdout); #endif - } - return (OK); + } + return (OK); } From 6c64d463c8ee22b4ae8a71ac47e890c1f41d3e00 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 26 May 2023 13:31:08 +0200 Subject: [PATCH 48/72] Reduce excessive use of TREALLOC --- src/spicelib/devices/ltra/ltraacct.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/spicelib/devices/ltra/ltraacct.c b/src/spicelib/devices/ltra/ltraacct.c index f8dcd0801..50115cdcd 100644 --- a/src/spicelib/devices/ltra/ltraacct.c +++ b/src/spicelib/devices/ltra/ltraacct.c @@ -48,7 +48,7 @@ LTRAaccept(CKTcircuit* ckt, GENmodel* inModel) here = LTRAnextInstance(here)) { if (ckt->CKTmode & MODEINITTRAN) { - here->LTRAinstListSize = 10; + here->LTRAinstListSize = (int)max(10, ckt->CKTtimeListSize); LTRAmemMANAGE(here->LTRAv1, here->LTRAinstListSize) LTRAmemMANAGE(here->LTRAi1, here->LTRAinstListSize) @@ -64,6 +64,7 @@ LTRAaccept(CKTcircuit* ckt, GENmodel* inModel) */ if (ckt->CKTtimeIndex >= here->LTRAinstListSize) { /* need more space */ here->LTRAinstListSize += ckt->CKTsizeIncr; + ckt->CKTsizeIncr = (int)ceil(1.4 * ckt->CKTsizeIncr); here->LTRAv1 = TREALLOC(double, here->LTRAv1, here->LTRAinstListSize); here->LTRAi1 = TREALLOC(double, here->LTRAi1, here->LTRAinstListSize); From a56b8b21908208dac8a62b1f243e2c765915b486 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 27 May 2023 16:17:23 +0200 Subject: [PATCH 49/72] Revert "Reduce excessive use of TREALLOC" This reverts commit 6c64d463c8ee22b4ae8a71ac47e890c1f41d3e00. --- src/spicelib/devices/ltra/ltraacct.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/spicelib/devices/ltra/ltraacct.c b/src/spicelib/devices/ltra/ltraacct.c index 50115cdcd..f8dcd0801 100644 --- a/src/spicelib/devices/ltra/ltraacct.c +++ b/src/spicelib/devices/ltra/ltraacct.c @@ -48,7 +48,7 @@ LTRAaccept(CKTcircuit* ckt, GENmodel* inModel) here = LTRAnextInstance(here)) { if (ckt->CKTmode & MODEINITTRAN) { - here->LTRAinstListSize = (int)max(10, ckt->CKTtimeListSize); + here->LTRAinstListSize = 10; LTRAmemMANAGE(here->LTRAv1, here->LTRAinstListSize) LTRAmemMANAGE(here->LTRAi1, here->LTRAinstListSize) @@ -64,7 +64,6 @@ LTRAaccept(CKTcircuit* ckt, GENmodel* inModel) */ if (ckt->CKTtimeIndex >= here->LTRAinstListSize) { /* need more space */ here->LTRAinstListSize += ckt->CKTsizeIncr; - ckt->CKTsizeIncr = (int)ceil(1.4 * ckt->CKTsizeIncr); here->LTRAv1 = TREALLOC(double, here->LTRAv1, here->LTRAinstListSize); here->LTRAi1 = TREALLOC(double, here->LTRAi1, here->LTRAinstListSize); From fb0696107e23666e6ef85a4f2336c048f23ef637 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 27 May 2023 16:43:35 +0200 Subject: [PATCH 50/72] Better visibility of the results --- examples/TransmissionLines/ltra1_1_line.sp | 9 +++++---- examples/TransmissionLines/ltra1_4_line.sp | 2 ++ examples/TransmissionLines/ltra2_2_line.sp | 12 +++++++----- examples/TransmissionLines/ltra3_2_line.sp | 3 +++ examples/TransmissionLines/ltra4_1_line.sp | 3 +++ examples/TransmissionLines/ltra5_1_line.sp | 3 +++ examples/TransmissionLines/ltra6_2_line.sp | 3 +++ examples/TransmissionLines/ltra7_4_line.sp | 6 +++++- 8 files changed, 31 insertions(+), 10 deletions(-) diff --git a/examples/TransmissionLines/ltra1_1_line.sp b/examples/TransmissionLines/ltra1_1_line.sp index 2d9c93bb5..959efa3db 100644 --- a/examples/TransmissionLines/ltra1_1_line.sp +++ b/examples/TransmissionLines/ltra1_1_line.sp @@ -1,6 +1,6 @@ MOSdriver -- lossy line LTRA model -- C load -m5 0 168 2 0 mn0p9 w = 18.0u l=0.9u -m6 1 168 2 1 mp1p0 w = 36.0u l=1.0u +m5 2 168 0 0 mn0p9 w = 18.0u l=0.9u +m6 2 168 1 1 mp1p0 w = 36.0u l=1.0u CN2 2 0 0.025398e-12 CN3 3 0 0.007398e-12 o1 2 0 3 0 lline @@ -8,12 +8,13 @@ vdd 1 0 dc 5.0 VS 168 0 PULSE (0 5 15.9NS 0.2NS 0.2NS 15.8NS 32NS ) .control TRAN 0.2N 47N 0 0.1N +rusage plot v(2) v(3) ylimit -0.5 5 .endc .MODEL mn0p9 NMOS VTO=0.8 KP=48U GAMMA=0.30 PHI=0.55 -+LAMBDA=0.00 CGSO=0 CGDO=0 CJ=0 CJSW=0 TOX=18000N LD=0.0U ++LAMBDA=0.00 CGSO=0 CGDO=0 CJ=0 CJSW=0 TOX=18N LD=0.0U .MODEL mp1p0 PMOS VTO=-0.8 KP=21U GAMMA=0.45 PHI=0.61 -+LAMBDA=0.00 CGSO=0 CGDO=0 CJ=0 CJSW=0 TOX=18000N LD=0.0U ++LAMBDA=0.00 CGSO=0 CGDO=0 CJ=0 CJSW=0 TOX=18N LD=0.0U .model lline ltra rel=1 r=12.45 g=0 l=8.972e-9 c=0.468e-12 +len=16 steplimit compactrel=1.0e-3 compactabs=1.0e-14 .end diff --git a/examples/TransmissionLines/ltra1_4_line.sp b/examples/TransmissionLines/ltra1_4_line.sp index 8d30a7578..f946454e0 100644 --- a/examples/TransmissionLines/ltra1_4_line.sp +++ b/examples/TransmissionLines/ltra1_4_line.sp @@ -135,7 +135,9 @@ VS1 2 0 PULSE (0 5 15.9Ns 0.2Ns 0.2Ns 15.8Ns 32Ns) VS2 4 0 PULSE (0 5 15.9Ns 0.2Ns 0.2Ns 15.8Ns 32Ns) .control +option noinit TRAN 0.1N 47.9N +rusage plot v(5) v(6) v(7) v(8) v(9) v(10) v(11) v(12) .endc * diff --git a/examples/TransmissionLines/ltra2_2_line.sp b/examples/TransmissionLines/ltra2_2_line.sp index 2a4ceaa7f..ac331a1ab 100644 --- a/examples/TransmissionLines/ltra2_2_line.sp +++ b/examples/TransmissionLines/ltra2_2_line.sp @@ -1,8 +1,8 @@ MOSdriver -- 2 lossy lines LTRA model -- C load -m5 0 168 2 0 mn0p9 w = 18.0u l=0.9u -m6 1 168 2 1 mp1p0 w = 36.0u l=1.0u -m1 0 3 4 0 mn0p9 w = 18.0u l=0.9u -m2 1 3 4 1 mp1p0 w = 36.0u l=1.0u +m5 2 168 0 0 mn0p9 w = 18.0u l=0.9u +m6 2 168 1 1 mp1p0 w = 36.0u l=1.0u +m1 4 3 0 0 mn0p9 w = 18.0u l=0.9u +m2 4 3 1 1 mp1p0 w = 36.0u l=1.0u CN2 2 0 0.025398e-12 CN3 3 0 0.007398e-12 CN4 4 0 0.025398e-12 @@ -13,7 +13,9 @@ vdd 1 0 dc 5.0 VS 168 0 PULSE (0 5 15.9NS 0.2NS 0.2NS 15.8NS 32NS ) .control TRAN 0.2N 47N 0 0.1N -plot v(2) v(3) v(4) v(5) +rusage +set xbrushwidth=3 +plot v(168) v(2) v(3) v(4) v(5) .endc .MODEL mn0p9 NMOS VTO=0.8 KP=48U GAMMA=0.30 PHI=0.55 +LAMBDA=0.00 CGSO=0 CGDO=0 CJ=0 CJSW=0 TOX=18000N LD=0.0U diff --git a/examples/TransmissionLines/ltra3_2_line.sp b/examples/TransmissionLines/ltra3_2_line.sp index 1a756520e..7d25d2969 100644 --- a/examples/TransmissionLines/ltra3_2_line.sp +++ b/examples/TransmissionLines/ltra3_2_line.sp @@ -84,6 +84,9 @@ VS2 268 0 PULSE (0 5 15.9N 0.2N 0.2N 15.8N 60N) * .control TRAN 0.2N 47.9NS +rusage +set color0=white +set xbrushwidth=3 PLOT v(648) v(651) v(751) .endc * diff --git a/examples/TransmissionLines/ltra4_1_line.sp b/examples/TransmissionLines/ltra4_1_line.sp index 8dc8ada61..ef7aca7b1 100644 --- a/examples/TransmissionLines/ltra4_1_line.sp +++ b/examples/TransmissionLines/ltra4_1_line.sp @@ -53,6 +53,9 @@ x3 3 4 10 dioload +reltol=1e-3 abstol=1e-14 .control tran 0.1ns 60ns +rusage +set color0=white +set xbrushwidth=3 plot v(1) v(2) v(3) .endc diff --git a/examples/TransmissionLines/ltra5_1_line.sp b/examples/TransmissionLines/ltra5_1_line.sp index f8a1c5ffa..90944e742 100644 --- a/examples/TransmissionLines/ltra5_1_line.sp +++ b/examples/TransmissionLines/ltra5_1_line.sp @@ -60,6 +60,9 @@ x1 2 3 xonecm tran 0.001ns 10ns 0 0.1ns * onecm10 *tran 0.001ns 10ns 0 0.01ns +rusage +set color0=white +set xbrushwidth=3 plot v(1) v(2) v(3) .endc diff --git a/examples/TransmissionLines/ltra6_2_line.sp b/examples/TransmissionLines/ltra6_2_line.sp index 452791297..ab06028e1 100644 --- a/examples/TransmissionLines/ltra6_2_line.sp +++ b/examples/TransmissionLines/ltra6_2_line.sp @@ -75,6 +75,9 @@ rt2 5 0 50 .options acct reltol=1e-3 abstol=1e-12 .control tran 0.1ns 60ns +rusage +*set color0=white +set xbrushwidth=3 plot v(2) v(4) v(5) .endc diff --git a/examples/TransmissionLines/ltra7_4_line.sp b/examples/TransmissionLines/ltra7_4_line.sp index 7be4615a0..b7733d9a1 100644 --- a/examples/TransmissionLines/ltra7_4_line.sp +++ b/examples/TransmissionLines/ltra7_4_line.sp @@ -106,7 +106,11 @@ x1 2 3 4 5 6 7 8 9 test VS1 1 0 PWL(15.9NS 0.0 16.1Ns 5.0 31.9Ns 5.0 32.1Ns 0.0) .control -TRAN 0.2NS 50NS +option noinit +TRAN 0.2NS 50NS +rusage +*set color0=white +set xbrushwidth=3 plot v(1) v(2) v(6) v(7) v(8) v(9) .endc * From 1cd15e382ea6a0c379856d50153aaa4792bc629d Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 27 May 2023 16:44:30 +0200 Subject: [PATCH 51/72] Reduce excessive use of TREALLOC --- src/spicelib/analysis/dcpss.c | 2 +- src/spicelib/analysis/dctran.c | 2 +- src/spicelib/analysis/optran.c | 2 +- src/spicelib/devices/ltra/ltraacct.c | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/spicelib/analysis/dcpss.c b/src/spicelib/analysis/dcpss.c index d20fbf3db..61350383c 100644 --- a/src/spicelib/analysis/dcpss.c +++ b/src/spicelib/analysis/dcpss.c @@ -194,7 +194,7 @@ DCpss(CKTcircuit *ckt, else maxstepsize = ckt->CKTmaxStep; - ckt->CKTsizeIncr = 10; + ckt->CKTsizeIncr = 100; ckt->CKTtimeIndex = -1; /* before the DC soln has been stored */ ckt->CKTtimeListSize = (int)(1 / ckt->CKTguessedFreq / maxstepsize + 0.5); ltra_num = CKTtypelook("LTRA"); diff --git a/src/spicelib/analysis/dctran.c b/src/spicelib/analysis/dctran.c index 5f63a80f9..5f7d66c60 100644 --- a/src/spicelib/analysis/dctran.c +++ b/src/spicelib/analysis/dctran.c @@ -123,7 +123,7 @@ DCtran(CKTcircuit *ckt, else maxstepsize = ckt->CKTmaxStep; - ckt->CKTsizeIncr = 10; + ckt->CKTsizeIncr = 100; ckt->CKTtimeIndex = -1; /* before the DC soln has been stored */ ckt->CKTtimeListSize = (int) ceil( ckt->CKTfinalTime / maxstepsize ); ltra_num = CKTtypelook("LTRA"); diff --git a/src/spicelib/analysis/optran.c b/src/spicelib/analysis/optran.c index 6f454931f..8aba4e1a9 100644 --- a/src/spicelib/analysis/optran.c +++ b/src/spicelib/analysis/optran.c @@ -367,7 +367,7 @@ OPtran(CKTcircuit *ckt, int oldconverged) else maxstepsize = ckt->CKTmaxStep; - ckt->CKTsizeIncr = 10; + ckt->CKTsizeIncr = 100; ckt->CKTtimeIndex = -1; /* before the DC soln has been stored */ ckt->CKTtimeListSize = (int) ceil( opfinaltime / maxstepsize ); ltra_num = CKTtypelook("LTRA"); diff --git a/src/spicelib/devices/ltra/ltraacct.c b/src/spicelib/devices/ltra/ltraacct.c index f8dcd0801..6a169b0d6 100644 --- a/src/spicelib/devices/ltra/ltraacct.c +++ b/src/spicelib/devices/ltra/ltraacct.c @@ -30,7 +30,7 @@ LTRAaccept(CKTcircuit* ckt, GENmodel* inModel) if ( a != NULL) FREE(a);\ a = TMALLOC(double, b); - model->LTRAmodelListSize = 10; + model->LTRAmodelListSize = 100; LTRAmemMANAGE(model->LTRAh1dashCoeffs, model->LTRAmodelListSize) LTRAmemMANAGE(model->LTRAh2Coeffs, model->LTRAmodelListSize) @@ -48,7 +48,7 @@ LTRAaccept(CKTcircuit* ckt, GENmodel* inModel) here = LTRAnextInstance(here)) { if (ckt->CKTmode & MODEINITTRAN) { - here->LTRAinstListSize = 10; + here->LTRAinstListSize = (int)MAX(10, ckt->CKTtimeListSize); LTRAmemMANAGE(here->LTRAv1, here->LTRAinstListSize) LTRAmemMANAGE(here->LTRAi1, here->LTRAinstListSize) From 6c420525d0e37811f23985d4b8d6dcac37f53e4e Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Sun, 7 May 2023 18:27:32 +0100 Subject: [PATCH 52/72] Apply a patch from Aleksey Morozov to fix a bug that he identified and reproduced. It is the same as Bug #331 - "XSpice skips digital output point" except that it applies to the instance queue, not the event queue. --- src/xspice/evt/evtbackup.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/xspice/evt/evtbackup.c b/src/xspice/evt/evtbackup.c index f857c6816..52ce11b97 100644 --- a/src/xspice/evt/evtbackup.c +++ b/src/xspice/evt/evtbackup.c @@ -479,17 +479,26 @@ static void EVTbackup_inst_queue( } inst_queue->next_time = next_time; - /* Update the modified list by looking for any queued events */ - /* with posted time > last_time */ + /* Update the modified list by looking for events that were processed + * or queued in the current timestep. + */ + for(i = 0, j = 0; i < num_modified; i++) { inst_index = inst_queue->modified_index[i]; inst = *(inst_queue->last_step[inst_index]); - while(inst) { - if(inst->posted_time > inst_queue->last_time) - break; - inst = inst->next; + if (inst_queue->current[inst_index] == + inst_queue->last_step[inst_index]) { + /* Nothing now removed from the queue, + * but it may have been modified by an addition. + */ + + while (inst) { + if (inst->posted_time > inst_queue->last_time) + break; + inst = inst->next; + } } if(! inst) { From 9c75367cfb0d5e8c6eec1ca2e84ebdaac286cd51 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Sun, 14 May 2023 17:16:24 +0100 Subject: [PATCH 53/72] Fix another error in 9c71db3a728d59c901a08afc3870b65095adb1b0. --- src/spicelib/devices/vsrc/vsrcload.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/spicelib/devices/vsrc/vsrcload.c b/src/spicelib/devices/vsrc/vsrcload.c index 099daac4f..a24bacc31 100644 --- a/src/spicelib/devices/vsrc/vsrcload.c +++ b/src/spicelib/devices/vsrc/vsrcload.c @@ -319,6 +319,7 @@ VSRCload(GENmodel *inModel, CKTcircuit *ckt) period = end_time - here->VSRCcoeffs[here->VSRCrBreakpt]; time -= period * floor(time / period); + time += here->VSRCcoeffs[here->VSRCrBreakpt]; } else { value = here->VSRCcoeffs[here->VSRCfunctionOrder - 1]; From 0616965a6795ee8ac4ec7628a2685f4eee5bc55e Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Sun, 14 May 2023 17:18:26 +0100 Subject: [PATCH 54/72] Fix Bug #630 - "pwl if r=last time, simulation never ends". Allowing a PWL repeat to start at the last time-point makes no sense. --- src/spicelib/devices/vsrc/vsrcpar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spicelib/devices/vsrc/vsrcpar.c b/src/spicelib/devices/vsrc/vsrcpar.c index 19686293f..72738cd31 100644 --- a/src/spicelib/devices/vsrc/vsrcpar.c +++ b/src/spicelib/devices/vsrc/vsrcpar.c @@ -140,7 +140,7 @@ VSRCparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select) } end_time = *(here->VSRCcoeffs + here->VSRCfunctionOrder-2); - if ( here->VSRCr > end_time ) { + if ( here->VSRCr >= end_time ) { fprintf(stderr, "ERROR: repeat start time value %g for pwl voltage source must be smaller than final time point given!\n", here->VSRCr ); return ( E_PARMVAL ); } From d55143edca9e57026c4fe422312f2250fff496e8 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Mon, 1 May 2023 14:37:38 +0100 Subject: [PATCH 55/72] When creating a plot vector from XSPICE event history, add a final point at the end of the vector, so that a plotted line does not end at the last event, leaving an odd spike. --- src/xspice/evt/evtplot.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/xspice/evt/evtplot.c b/src/xspice/evt/evtplot.c index 7b1106f5f..af5c50792 100644 --- a/src/xspice/evt/evtplot.c +++ b/src/xspice/evt/evtplot.c @@ -88,11 +88,13 @@ struct dvec *EVTfindvec( int udn_index; int num_events; - Mif_Boolean_t found; + Mif_Boolean_t found; + Evt_Ckt_Data_t *evt; + CKTcircuit *ckt; Evt_Node_Info_t **node_table; - Evt_Node_t *head; - Evt_Node_t *event; - + Evt_Node_t *head; + Evt_Node_t *event; + double *anal_point_vec; double *value_vec; double value = 0; @@ -102,13 +104,16 @@ struct dvec *EVTfindvec( /* Exit immediately if event-driven stuff not allocated yet, */ /* or if number of event nodes is zero. */ - if(! g_mif_info.ckt) + + ckt = g_mif_info.ckt; + if(! ckt) return(NULL); - if(! g_mif_info.ckt->evt) + evt = ckt->evt; + if(! evt) return(NULL); - if(! g_mif_info.ckt->evt->info.node_table) + if(! evt->info.node_table) return(NULL); - if(g_mif_info.ckt->evt->counts.num_nodes == 0) + if(evt->counts.num_nodes == 0) return(NULL); /* Make a copy of the node name. */ @@ -134,8 +139,8 @@ struct dvec *EVTfindvec( } /* Look for node name in the event-driven node list */ - num_nodes = g_mif_info.ckt->evt->counts.num_nodes; - node_table = g_mif_info.ckt->evt->info.node_table; + num_nodes = evt->counts.num_nodes; + node_table = evt->info.node_table; for(i = 0, found = MIF_FALSE; i < num_nodes; i++) { if(cieq(name, node_table[i]->name)) { @@ -152,14 +157,14 @@ struct dvec *EVTfindvec( /* Get the UDN type index */ udn_index = node_table[i]->udn_index; - if (!g_mif_info.ckt->evt->data.node) { + if (!evt->data.node) { // fprintf(stderr, "Warning: No event data available! \n Simulation not yet run?\n"); tfree(name); return(NULL); } /* Count the number of events */ - head = g_mif_info.ckt->evt->data.node->head[i]; + head = evt->data.node->head[i]; for(event = head, num_events = 0; event; event = event->next) num_events++; @@ -170,8 +175,7 @@ struct dvec *EVTfindvec( /* Iterate through the events and fill the arrays. */ /* Note that we create vertical segments every time an event occurs. */ - /* Need to modify this in the future to complete the vector out to the */ - /* last analysis point... */ + for(i = 0, event = head; event; event = event->next) { /* If not first point, put the second value of the horizontal line in the vectors */ @@ -194,6 +198,11 @@ struct dvec *EVTfindvec( } + /* Add one more point so that the line will extend to the end of the plot. */ + + anal_point_vec[i] = ckt->CKTtime; + value_vec[i++] = value; + /* Allocate dvec structures and assign the vectors into them. */ /* See FTE/OUTinterface.c:plotInit() for initialization example. */ From 94da54bceaa566cf92931151a485a2d6f638858e Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Tue, 2 May 2023 12:08:21 +0100 Subject: [PATCH 56/72] Always propgate any individual scale for a vector that appears in an expression, resolving conflicts by matching length and warning only when making an arbitary choice. One effect of this is that it is now possible to mix analog nodes with offset digital nodes (an expression like dvalue+6) without a warning and get a correct plot. --- src/frontend/evaluate.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/frontend/evaluate.c b/src/frontend/evaluate.c index f38aff246..ee9bec045 100644 --- a/src/frontend/evaluate.c +++ b/src/frontend/evaluate.c @@ -191,7 +191,7 @@ doop(char what, struct dvec *v1, *v2, *res; ngcomplex_t *c1 = NULL, *c2 = NULL, lc; double *d1 = NULL, *d2 = NULL, ld; - int length = 0, i; + int length = 0, i, longer; void *data; bool free1 = FALSE, free2 = FALSE, relflag = FALSE; @@ -253,6 +253,7 @@ doop(char what, /* Make sure we have data of the same length. */ length = ((v1->v_length > v2->v_length) ? v1->v_length : v2->v_length); if (v1->v_length < length) { + longer = 2; free1 = TRUE; if (isreal(v1)) { ld = 0.0; @@ -275,6 +276,7 @@ doop(char what, c1[i] = lc; } } else { + longer = 0; if (isreal(v1)) d1 = v1->v_realdata; else @@ -282,6 +284,7 @@ doop(char what, } if (v2->v_length < length) { + longer = 1; free2 = TRUE; if (isreal(v2)) { ld = 0.0; @@ -335,10 +338,27 @@ doop(char what, } /* This is a non-obvious thing */ + if (v1->v_scale != v2->v_scale) { - fprintf(cp_err, "Warning: scales of %s and %s are different.\n", - v1->v_name, v2->v_name); - res->v_scale = NULL; + switch (longer) { + case 0: + if (!v1->v_scale) + res->v_scale = v2->v_scale; + else if (!v2->v_scale) + res->v_scale = v1->v_scale; + else + fprintf(cp_err, + "Warning: scales of %s and %s are different.\n", + v1->v_name, v2->v_name); + res->v_scale = v1->v_scale; // Do something! + break; + case 1: + res->v_scale = v1->v_scale; + break; + case 2: + res->v_scale = v2->v_scale; + break; + } } else { res->v_scale = v1->v_scale; } From 37453db34d643069219f47820fb0c32aad798bbe Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Tue, 2 May 2023 12:24:39 +0100 Subject: [PATCH 57/72] Fix Bug #623 - "Parser warning for voltage source". Do not warn when a single-element vector lacks parentheses. --- src/spicelib/parser/inpgval.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/spicelib/parser/inpgval.c b/src/spicelib/parser/inpgval.c index 1f5d9acaa..f9f84ad14 100644 --- a/src/spicelib/parser/inpgval.c +++ b/src/spicelib/parser/inpgval.c @@ -53,7 +53,8 @@ INPgetValue(CKTcircuit *ckt, char **line, int type, INPtables *tab) list[temp.v.numValue - 1] = tmp; tmp = INPevaluate(line, &error, 1); } - if (error && ft_ngdebug && !eq(*line, "") && !prefix(")", *line)) { + if (error && ft_ngdebug && !eq(*line, "") && !prefix(")", *line) && + temp.v.numValue > 1) { fprintf(stderr, "\nWarning: Reading a vector without limiting parens may be dangerous\n%s\nat\n", compline); fprintf(stderr, "%*s%s\n", (int)(*line - compline)," ", *line); } @@ -76,7 +77,8 @@ INPgetValue(CKTcircuit *ckt, char **line, int type, INPtables *tab) ilist[temp.v.numValue - 1] = (int) floor(0.5 + tmp); tmp = INPevaluate(line, &error, 1); } - if (error && ft_ngdebug && !eq(*line, "") && !prefix(")", *line)) { + if (error && ft_ngdebug && !eq(*line, "") && !prefix(")", *line) && + temp.v.numValue > 1) { fprintf(stderr, "\nWarning: Reading a vector without limiting parens may be dangerous\n%s\nat\n", compline); fprintf(stderr, "%*s%s\n", (int)(*line - compline), " ", *line); } From e61db1d2cdf31bcdeab3090376ea94a747316c1a Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Tue, 23 May 2023 07:48:54 +0100 Subject: [PATCH 58/72] Add parsing and translation of the FREQ form of E-source devices, integrated with the existing parsing of AND/NAND/OR/NOR forms (inpcom.c). For the implementation, add a new analog XSPICE code model, xfer. Add an example to examples/sp. --- examples/sp/filter.lib | 185 ++++++++++ examples/sp/filter.sp | 91 +++++ src/frontend/inpcom.c | 474 ++++++++++++++++++-------- src/xspice/icm/analog/modpath.lst | 1 + src/xspice/icm/analog/xfer/cfunc.mod | 130 +++++++ src/xspice/icm/analog/xfer/ifspec.ifs | 91 +++++ 6 files changed, 836 insertions(+), 136 deletions(-) create mode 100644 examples/sp/filter.lib create mode 100644 examples/sp/filter.sp create mode 100644 src/xspice/icm/analog/xfer/cfunc.mod create mode 100644 src/xspice/icm/analog/xfer/ifspec.ifs diff --git a/examples/sp/filter.lib b/examples/sp/filter.lib new file mode 100644 index 000000000..173d853dc --- /dev/null +++ b/examples/sp/filter.lib @@ -0,0 +1,185 @@ +.SUBCKT filter 1 2 3 +*2-port S-parameter file +*Title: * simple test for xfer code model: comparison +*Generated by ngspice at Tue May 23 06:49:31 2023 +* Hz S RI R +* Z1=50.000000 Z2=50.000000 + +R1N 1 10 -5.000000e+01 +R1P 10 11 1.000000e+02 +R2N 2 20 -5.000000e+01 +R2P 20 21 1.000000e+02 + +*S11 FREQ DB PHASE +E11 11 12 FREQ {V(10,3)}= DB ++( 1.000000e+07Hz, 3.654967e-07, -7.619541e+01) ++( 1.487179e+07Hz, 1.964030e-07, -1.157703e+02) ++( 1.974359e+07Hz, -1.084219e-07, -1.569277e+02) ++( 2.461538e+07Hz, -5.321598e-06, -1.985756e+02) ++( 2.948718e+07Hz, -1.265047e-05, -2.395114e+02) ++( 3.435897e+07Hz, -2.727603e-05, -2.792878e+02) ++( 3.923077e+07Hz, -6.620604e-05, -3.184596e+02) ++( 4.410256e+07Hz, -1.624082e-04, -3.582070e+02) ++( 4.897436e+07Hz, -3.755273e-04, -3.996839e+02) ++( 5.384615e+07Hz, -7.725656e-04, -4.432805e+02) ++( 5.871795e+07Hz, -1.320643e-03, -4.881884e+02) ++( 6.358974e+07Hz, -1.599290e-03, -5.330311e+02) ++( 6.846154e+07Hz, -4.631092e-04, -5.776220e+02) ++( 7.333333e+07Hz, -1.388239e-02, -6.262936e+02) ++( 7.820513e+07Hz, -1.245578e+01, -8.015034e+02) ++( 8.307692e+07Hz, -1.142468e+00, -6.888087e+02) ++( 8.794872e+07Hz, -1.292324e+00, -7.542062e+02) ++( 9.282051e+07Hz, -2.163078e+00, -8.283885e+02) ++( 9.769231e+07Hz, -3.764829e+00, -9.213357e+02) ++( 1.025641e+08Hz, -4.165673e+00, -1.041098e+03) ++( 1.074359e+08Hz, -2.143343e+00, -1.139856e+03) ++( 1.123077e+08Hz, -1.084156e+00, -1.201868e+03) ++( 1.171795e+08Hz, -7.962690e-01, -1.249480e+03) ++( 1.220513e+08Hz, -1.204024e+00, -1.318959e+03) ++( 1.269231e+08Hz, -4.148462e-01, -1.169292e+03) ++( 1.317949e+08Hz, -1.026085e-02, -1.240330e+03) ++( 1.366667e+08Hz, -1.360661e-04, -1.265793e+03) ++( 1.415385e+08Hz, -2.410965e-03, -1.281511e+03) ++( 1.464103e+08Hz, -3.787891e-03, -1.293132e+03) ++( 1.512821e+08Hz, -3.602264e-03, -1.302433e+03) ++( 1.561538e+08Hz, -2.547410e-03, -1.310211e+03) ++( 1.610256e+08Hz, -1.530232e-03, -1.316893e+03) ++( 1.658974e+08Hz, -8.667728e-04, -1.322741e+03) ++( 1.707692e+08Hz, -4.905888e-04, -1.327928e+03) ++( 1.756410e+08Hz, -2.840626e-04, -1.332578e+03) ++( 1.805128e+08Hz, -1.688713e-04, -1.336783e+03) ++( 1.853846e+08Hz, -1.041703e-04, -1.340612e+03) ++( 1.902564e+08Hz, -6.546576e-05, -1.344121e+03) ++( 1.951282e+08Hz, -4.228835e-05, -1.347353e+03) ++( 2.000000e+08Hz, -2.867354e-05, -1.350343e+03) + +*S12 FREQ DB PHASE +E12 12 3 FREQ {V(20,3)}= DB ++( 1.000000e+07Hz, -1.248758e+02, -1.373971e+02) ++( 1.487179e+07Hz, -9.831399e+01, -1.647281e+02) ++( 1.974359e+07Hz, -7.673566e+01, -2.026127e+02) ++( 2.461538e+07Hz, -5.898226e+01, -2.906518e+02) ++( 2.948718e+07Hz, -5.542440e+01, -3.666485e+02) ++( 3.435897e+07Hz, -5.204910e+01, -4.009490e+02) ++( 3.923077e+07Hz, -4.814977e+01, -4.271950e+02) ++( 4.410256e+07Hz, -4.426072e+01, -4.514100e+02) ++( 4.897436e+07Hz, -4.063346e+01, -4.755494e+02) ++( 5.384615e+07Hz, -3.749934e+01, -5.003303e+02) ++( 5.871795e+07Hz, -3.516924e+01, -5.256223e+02) ++( 6.358974e+07Hz, -3.433887e+01, -5.509590e+02) ++( 6.846154e+07Hz, -3.971774e+01, -5.765977e+02) ++( 7.333333e+07Hz, -2.496027e+01, -4.260244e+02) ++( 7.820513e+07Hz, -2.540060e-01, -5.317362e+02) ++( 8.307692e+07Hz, -6.358120e+00, -6.335796e+02) ++( 8.794872e+07Hz, -5.894279e+00, -6.719727e+02) ++( 9.282051e+07Hz, -4.063864e+00, -7.129969e+02) ++( 9.769231e+07Hz, -2.367660e+00, -7.603597e+02) ++( 1.025641e+08Hz, -2.098602e+00, -8.143919e+02) ++( 1.074359e+08Hz, -4.094614e+00, -8.636479e+02) ++( 1.123077e+08Hz, -6.557734e+00, -8.998592e+02) ++( 1.171795e+08Hz, -7.759301e+00, -9.295624e+02) ++( 1.220513e+08Hz, -6.159604e+00, -9.703161e+02) ++( 1.269231e+08Hz, -1.040475e+01, -1.077742e+03) ++( 1.317949e+08Hz, -2.627115e+01, -1.123641e+03) ++( 1.366667e+08Hz, -4.503397e+01, -9.675219e+02) ++( 1.415385e+08Hz, -3.255698e+01, -9.893598e+02) ++( 1.464103e+08Hz, -3.059532e+01, -1.012566e+03) ++( 1.512821e+08Hz, -3.081422e+01, -1.036661e+03) ++( 1.561538e+08Hz, -3.231825e+01, -1.058931e+03) ++( 1.610256e+08Hz, -3.453111e+01, -1.077318e+03) ++( 1.658974e+08Hz, -3.699828e+01, -1.091740e+03) ++( 1.707692e+08Hz, -3.947129e+01, -1.103061e+03) ++( 1.756410e+08Hz, -4.184769e+01, -1.112161e+03) ++( 1.805128e+08Hz, -4.409577e+01, -1.119694e+03) ++( 1.853846e+08Hz, -4.621280e+01, -1.126103e+03) ++( 1.902564e+08Hz, -4.820666e+01, -1.131686e+03) ++( 1.951282e+08Hz, -5.008836e+01, -1.136645e+03) ++( 2.000000e+08Hz, -5.186916e+01, -1.141123e+03) + +*S21 FREQ DB PHASE +E21 21 22 FREQ {V(10,3)}= DB ++( 1.000000e+07Hz, -1.248758e+02, -1.373971e+02) ++( 1.487179e+07Hz, -9.831399e+01, -1.647281e+02) ++( 1.974359e+07Hz, -7.673566e+01, -2.026127e+02) ++( 2.461538e+07Hz, -5.898226e+01, -2.906518e+02) ++( 2.948718e+07Hz, -5.542440e+01, -3.666485e+02) ++( 3.435897e+07Hz, -5.204910e+01, -4.009490e+02) ++( 3.923077e+07Hz, -4.814977e+01, -4.271950e+02) ++( 4.410256e+07Hz, -4.426072e+01, -4.514100e+02) ++( 4.897436e+07Hz, -4.063346e+01, -4.755494e+02) ++( 5.384615e+07Hz, -3.749934e+01, -5.003303e+02) ++( 5.871795e+07Hz, -3.516924e+01, -5.256223e+02) ++( 6.358974e+07Hz, -3.433887e+01, -5.509590e+02) ++( 6.846154e+07Hz, -3.971774e+01, -5.765977e+02) ++( 7.333333e+07Hz, -2.496027e+01, -4.260244e+02) ++( 7.820513e+07Hz, -2.540060e-01, -5.317362e+02) ++( 8.307692e+07Hz, -6.358120e+00, -6.335796e+02) ++( 8.794872e+07Hz, -5.894279e+00, -6.719727e+02) ++( 9.282051e+07Hz, -4.063864e+00, -7.129969e+02) ++( 9.769231e+07Hz, -2.367660e+00, -7.603597e+02) ++( 1.025641e+08Hz, -2.098602e+00, -8.143919e+02) ++( 1.074359e+08Hz, -4.094614e+00, -8.636479e+02) ++( 1.123077e+08Hz, -6.557734e+00, -8.998592e+02) ++( 1.171795e+08Hz, -7.759301e+00, -9.295624e+02) ++( 1.220513e+08Hz, -6.159604e+00, -9.703161e+02) ++( 1.269231e+08Hz, -1.040475e+01, -1.077742e+03) ++( 1.317949e+08Hz, -2.627115e+01, -1.123641e+03) ++( 1.366667e+08Hz, -4.503397e+01, -9.675219e+02) ++( 1.415385e+08Hz, -3.255698e+01, -9.893598e+02) ++( 1.464103e+08Hz, -3.059532e+01, -1.012566e+03) ++( 1.512821e+08Hz, -3.081422e+01, -1.036661e+03) ++( 1.561538e+08Hz, -3.231825e+01, -1.058931e+03) ++( 1.610256e+08Hz, -3.453111e+01, -1.077318e+03) ++( 1.658974e+08Hz, -3.699828e+01, -1.091740e+03) ++( 1.707692e+08Hz, -3.947129e+01, -1.103061e+03) ++( 1.756410e+08Hz, -4.184769e+01, -1.112161e+03) ++( 1.805128e+08Hz, -4.409577e+01, -1.119694e+03) ++( 1.853846e+08Hz, -4.621280e+01, -1.126103e+03) ++( 1.902564e+08Hz, -4.820666e+01, -1.131686e+03) ++( 1.951282e+08Hz, -5.008836e+01, -1.136645e+03) ++( 2.000000e+08Hz, -5.186916e+01, -1.141123e+03) + +*S22 FREQ DB PHASE +E22 22 3 FREQ {V(20,3)}= DB ++( 1.000000e+07Hz, 1.633257e-07, -1.859873e+01) ++( 1.487179e+07Hz, -1.597472e-07, -3.368599e+01) ++( 1.974359e+07Hz, -9.840549e-08, -6.829764e+01) ++( 2.461538e+07Hz, -5.748843e-06, -2.027281e+02) ++( 2.948718e+07Hz, -1.209271e-05, -3.137855e+02) ++( 3.435897e+07Hz, -2.686288e-05, -3.426102e+02) ++( 3.923077e+07Hz, -6.619051e-05, -3.559304e+02) ++( 4.410256e+07Hz, -1.626503e-04, -3.646130e+02) ++( 4.897436e+07Hz, -3.750315e-04, -3.714149e+02) ++( 5.384615e+07Hz, -7.720713e-04, -3.773802e+02) ++( 5.871795e+07Hz, -1.321131e-03, -3.830562e+02) ++( 6.358974e+07Hz, -1.599127e-03, -3.888868e+02) ++( 6.846154e+07Hz, -4.639695e-04, -3.955734e+02) ++( 7.333333e+07Hz, -1.388161e-02, -4.057551e+02) ++( 7.820513e+07Hz, -1.245578e+01, -4.419690e+02) ++( 8.307692e+07Hz, -1.142468e+00, -3.983505e+02) ++( 8.794872e+07Hz, -1.292324e+00, -4.097393e+02) ++( 9.282051e+07Hz, -2.163078e+00, -4.176053e+02) ++( 9.769231e+07Hz, -3.764828e+00, -4.193838e+02) ++( 1.025641e+08Hz, -4.165672e+00, -4.076855e+02) ++( 1.074359e+08Hz, -2.143343e+00, -4.074397e+02) ++( 1.123077e+08Hz, -1.084156e+00, -4.178506e+02) ++( 1.171795e+08Hz, -7.962687e-01, -4.296447e+02) ++( 1.220513e+08Hz, -1.204024e+00, -4.416736e+02) ++( 1.269231e+08Hz, -4.148459e-01, -4.461929e+02) ++( 1.317949e+08Hz, -1.026073e-02, -4.669521e+02) ++( 1.366667e+08Hz, -1.361528e-04, -4.892508e+02) ++( 1.415385e+08Hz, -2.411138e-03, -5.172082e+02) ++( 1.464103e+08Hz, -3.788042e-03, -5.519999e+02) ++( 1.512821e+08Hz, -3.601989e-03, -5.908887e+02) ++( 1.561538e+08Hz, -2.547212e-03, -6.276516e+02) ++( 1.610256e+08Hz, -1.529976e-03, -6.577430e+02) ++( 1.658974e+08Hz, -8.674572e-04, -6.807399e+02) ++( 1.707692e+08Hz, -4.901623e-04, -6.981937e+02) ++( 1.756410e+08Hz, -2.836349e-04, -7.117446e+02) ++( 1.805128e+08Hz, -1.694495e-04, -7.226059e+02) ++( 1.853846e+08Hz, -1.034247e-04, -7.315943e+02) ++( 1.902564e+08Hz, -6.587183e-05, -7.392507e+02) ++( 1.951282e+08Hz, -4.251059e-05, -7.459375e+02) ++( 2.000000e+08Hz, -2.798303e-05, -7.519027e+02) + +.ENDS diff --git a/examples/sp/filter.sp b/examples/sp/filter.sp new file mode 100644 index 000000000..5851bcf6e --- /dev/null +++ b/examples/sp/filter.sp @@ -0,0 +1,91 @@ +* Simple test for xfer code model: comparison +* +* This circuit compares the results of an AC analysis of a filter (node out) +* with those from a behavioural model controlled by measured S-parameters +* of that circuit (node xout). The AC analysis has more data points than +* that used to measure the S-parameters, to prevent the results from matching +* exactly. + +* The use of S-parameters to create a behavioural simulation of a component +* was discussed here: +* https://sourceforge.net/p/ngspice/discussion/120973/thread/51228e0b01/ + +* Circuit from: +* Novarianti, Dini. (2019). +* Design and Implementation of Chebyshev Band Pass Filter with +* M-Derived Section in Frequency Band 88 - 108 MHz. +* Jurnal Jartel: Jurnal Jaringan Telekomunikasi. 8. 7-11. +* 10.33795/jartel.v8i1.147. +* +* https://www.researchgate.net/publication/352822864_Design_and_Implementation_of_Chebyshev_Band_Pass_Filter_with_M-Derived_Section_in_Frequency_Band_88_-_108_MHz + +* Set this parameter to 1 to generate a Touchstone file that can be used +* to generate the behavioural part of the circuit, filter.lib + +.param do_sp=0 +.csparam do_sp=do_sp + +.if (do_sp) + +.csparam Rbase=50 ; This is required by "wrs2p", below. +vgen 1 0 dc 0 ac 1 portnum 1 + +.else + +vgen in 0 dc 0 ac 1 +rs in 1 50 + +.endif + +l1 1 2 0.058u +c2 2 0 40.84p +l3 2 3 0.128u +c4 3 0 47.91p +l5 3 4 0.128u +c6 4 0 40.48p +l7 4 5 0.058u + +la 5 6 0.044u +lb 6 a 0.078u +cb a 0 17.61p +lc 6 b 0.151u +cc b 0 34.12p +c7 6 7 26.035p + +l8 7 0 0.0653u +c8 7 8 20.8p +l9 8 0 0.055u +c9 8 9 20.8p +l10 9 0 0.653u + +c10 9 out 45.64p + +.if (do_sp) + +vl out 0 dc 0 ac 0 portnum 2 + +.else + +rl out 0 50 + +* Behavioural circuit, for comparison. + +.inc filter.lib +R1 in port1 50 +xsp port1 xout 0 filter +R2 xout 0 50 + +.endif + +.control +if $&do_sp + sp lin 40 10meg 200meg + wrs2p filter.s2p + plot S_1_1 S_2_2 polar +else + ac lin 400 10meg 200meg + plot db(mag(out)) 5*unwrap(ph(out)) db(mag(xout)) 5*unwrap(ph(xout)) +end + +.endc +.end diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index dd83a62f4..d0314d41a 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -152,7 +152,7 @@ static char inp_get_elem_ident(char *type); static void rem_mfg_from_models(struct card *start_card); static void inp_fix_macro_param_func_paren_io(struct card *begin_card); static void inp_fix_gnd_name(struct card *deck); -static void inp_chk_for_multi_in_vcvs(struct card *deck, int *line_number); +static void inp_chk_for_e_source_to_xspice(struct card *deck, int *line_number); static void inp_add_control_section(struct card *deck, int *line_number); static char *get_quoted_token(char *string, char **token); static void replace_token(char *string, char *token, int where, int total); @@ -985,7 +985,7 @@ struct card *inp_readall(FILE *fp, const char *dir_name, subckt_w_params = NULL; if (!cp_getvar("no_auto_gnd", CP_BOOL, NULL, 0)) inp_fix_gnd_name(working); - inp_chk_for_multi_in_vcvs(working, &rv.line_number); + inp_chk_for_e_source_to_xspice(working, &rv.line_number); /* "addcontrol" variable is set if "ngspice -a file" was used. */ @@ -1899,7 +1899,6 @@ static void inp_fix_gnd_name(struct card *c) } } - /* * transform a VCVS "gate" instance into a XSPICE instance * @@ -1917,7 +1916,336 @@ static void inp_fix_gnd_name(struct card *c) * the x,y list is fixed to length 2 */ -static void inp_chk_for_multi_in_vcvs(struct card *c, int *line_number) +static int inp_chk_for_multi_in_vcvs(struct card *c, int *line_number) +{ + char *fcn_b, *line; + + line = c->line; + if (((fcn_b = strstr(line, "nand(")) != NULL || + (fcn_b = strstr(line, "and(")) != NULL || + (fcn_b = strstr(line, "nor(")) != NULL || + (fcn_b = strstr(line, "or(")) != NULL) && + isspace_c(fcn_b[-1])) { +#ifndef XSPICE + fprintf(stderr, + "\n" + "Error: XSPICE is required to run the 'multi-input " + "pwl' option in line %d\n" + " %s\n" + "\n" + "See manual chapt. 31 for installation " + "instructions\n", + *line_number, line); + controlled_exit(EXIT_BAD); +#else + char keep, *comma_ptr, *xy_values1[5], *xy_values2[5]; + char *out_str, *ctrl_nodes_str, + *xy_values1_b = NULL, *ref_str, *fcn_name, + *fcn_e = NULL, *out_b, *out_e, *ref_e; + char *m_instance, *m_model; + char *xy_values2_b = NULL, *xy_values1_e = NULL, + *ctrl_nodes_b = NULL, *ctrl_nodes_e = NULL; + int xy_count1, xy_count2; + bool ok = FALSE; + + do { + ref_e = skip_non_ws(line); + + out_b = skip_ws(ref_e); + + out_e = skip_back_ws(fcn_b, out_b); + if (out_e <= out_b) + break; + + fcn_e = strchr(fcn_b, '('); + + ctrl_nodes_b = strchr(fcn_e, ')'); + if (!ctrl_nodes_b) + break; + ctrl_nodes_b = skip_ws(ctrl_nodes_b + 1); + + comma_ptr = strchr(ctrl_nodes_b, ','); + if (!comma_ptr) + break; + + xy_values1_b = skip_back_ws(comma_ptr, ctrl_nodes_b); + if (xy_values1_b[-1] == '}') { + while (--xy_values1_b >= ctrl_nodes_b) + if (*xy_values1_b == '{') + break; + } else { + xy_values1_b = skip_back_non_ws(xy_values1_b, ctrl_nodes_b); + } + if (xy_values1_b <= ctrl_nodes_b) + break; + + ctrl_nodes_e = skip_back_ws(xy_values1_b, ctrl_nodes_b); + if (ctrl_nodes_e <= ctrl_nodes_b) + break; + + xy_values1_e = skip_ws(comma_ptr + 1); + if (*xy_values1_e == '{') { + xy_values1_e = inp_spawn_brace(xy_values1_e); + } else { + xy_values1_e = skip_non_ws(xy_values1_e); + } + if (!xy_values1_e) + break; + + xy_values2_b = skip_ws(xy_values1_e); + + ok = TRUE; + } while (0); + + if (!ok) { + fprintf(stderr, "ERROR: malformed line: %s\n", line); + controlled_exit(EXIT_FAILURE); + } + + ref_str = copy_substring(line, ref_e); + out_str = copy_substring(out_b, out_e); + fcn_name = copy_substring(fcn_b, fcn_e); + ctrl_nodes_str = copy_substring(ctrl_nodes_b, ctrl_nodes_e); + + keep = *xy_values1_e; + *xy_values1_e = '\0'; + xy_count1 = + get_comma_separated_values(xy_values1, xy_values1_b); + *xy_values1_e = keep; + + xy_count2 = get_comma_separated_values(xy_values2, xy_values2_b); + + // place restrictions on only having 2 point values; this can + // change later + if (xy_count1 != 2 && xy_count2 != 2) + fprintf(stderr, + "ERROR: only expecting 2 pair values for " + "multi-input vcvs!\n"); + + m_instance = tprintf("%s %%vd[ %s ] %%vd( %s ) %s", ref_str, + ctrl_nodes_str, out_str, ref_str); + m_instance[0] = 'a'; + + m_model = tprintf(".model %s multi_input_pwl ( x = [%s %s] y " + "= [%s %s] model = \"%s\" )", + ref_str, xy_values1[0], xy_values2[0], xy_values1[1], + xy_values2[1], fcn_name); + + tfree(ref_str); + tfree(out_str); + tfree(fcn_name); + tfree(ctrl_nodes_str); + tfree(xy_values1[0]); + tfree(xy_values1[1]); + tfree(xy_values2[0]); + tfree(xy_values2[1]); + + *c->line = '*'; + c = insert_new_line(c, m_instance, (*line_number)++, c->linenum_orig); + c = insert_new_line(c, m_model, (*line_number)++, c->linenum_orig); +#endif + return 1; + } else { + return 0; // No keyword match. */ + } +} + +/* replace the E and G source FREQ function by an XSPICE xfer instance + * (used by Touchstone to netlist converter programs). + * E1 n1 n2 FREQ {expression} = DB values ... + * will become + * B1_gen 1_gen 0 v = expression + * A1_gen 1_gen %d(n1 n2) 1_gen + * .model 1_gen xfer db=true table=[ values ] + */ + +static void replace_freq(struct card *c, int *line_number) +{ +#ifdef XSPICE + char *line, *e, *e_e, *n1, *n1_e, *n2, *n2_e, *freq; + char *expr, *expr_e, *in, *in_e, *keywd, *cp, *list, *list_e; + int db, ri, rad, got_key, diff; + char pt, key[4]; + + line = c->line; + + /* First token is a node name. */ + + e = line + 1; + e_e = skip_non_ws(e); + n1 = skip_ws(e_e); + n1_e = skip_non_ws(n1); + freq = strstr(n1_e, "freq"); + if (!freq || !isspace_c(freq[-1]) || !isspace_c(freq[4])) + return; + n2 = skip_ws(n1_e); + if (n2 == freq) { + n2 = NULL; + } else { + n2_e = skip_non_ws(n2); + if (freq != skip_ws(n2_e)) // Three nodes or another keyword. + return; + } + + /* Isolate the input expression. */ + + expr = skip_ws(freq + 4); + if (*expr != '{') + return; + expr = skip_ws(expr + 1); + expr_e = strchr(expr, '}'); + if (!expr_e) + return; + skip_back_ws(expr_e, expr); + + /* Is the expression just a node name, or v(node) or v(node1, node2)? */ + + in = NULL; + diff = 0; + if (*expr < '0' || *expr > '9') { + for (in_e = expr; in_e < expr_e; ++in_e) { + if ((*in_e < '0' || *in_e > '9') && (*in_e < 'a' || *in_e > 'z') && + *in_e != '_') + break; + } + if (in_e == expr_e) { + /* A simple identifier. */ + + in = expr; + } + } + if (expr[0] == 'v' && expr[1] == '(' && expr_e[-1] == ')') { + in = expr + 2; + in_e = expr_e - 1; + cp = strchr(in, ','); + diff = (cp && cp < in_e); // Assume v(n1, n2) + } + + /* Look for a keyword. Previous processing may put braces around it. */ + + keywd = skip_ws(expr_e + 1); + if (*keywd == '=') + keywd = skip_ws(keywd + 1); + + db = 1; + rad = 0; + ri = 0; + do { + if (!keywd) + return; + list = keywd; // Perhaps not keyword + if (*keywd == '{') + ++keywd; + cp = key; + while (*keywd && !isspace_c(*keywd) && *keywd != '}' && + cp - key < sizeof key - 1) { + *cp++ = *keywd++; + } + *cp = 0; + if (*keywd == '}') + ++keywd; + if (!isspace_c(*keywd)) + return; + + /* Parse the format keyword, if any. */ + + got_key = 0; + if (!strcmp(key, "mag")) { + db = 0; + got_key = 1; + } else if (!strcmp(key, "db")) { + db = 1; + got_key = 1; + } else if (!strcmp(key, "rad")) { + rad = 1; + got_key = 1; + } else if (!strcmp(key, "deg")) { + rad = 0; + got_key = 1; + } else if (!strcmp(key, "r_i")) { + ri = 1; + got_key = 1; + } + + /* Get the list of values. */ + + if (got_key) + list = skip_ws(keywd); + if (!list) + return; + keywd = list; + } while(got_key); + + list_e = list + strlen(list) - 1; + skip_back_ws(list_e, list); + if (list >= list_e) + return; + + /* All good, rewrite the line. + * Macro BSTR is used to pass counted string arguments to tprintf(). + */ + +#define BSTR(s) (int)(s##_e - s), s + + pt = (*line == 'e') ? 'v' : 'i'; + *line = '*'; // Make a comment + if (in) { + /* Connect input nodes directly. */ + + if (diff) { + /* Differential input. */ + + if (n2) { + line = tprintf("a_gen_%.*s %%vd(%.*s) %%%cd(%.*s %.*s) " + "gen_model_%.*s", + BSTR(e), BSTR(in), pt, BSTR(n1), BSTR(n2), BSTR(e)); + } else { + line = tprintf("a_gen_%.*s %%vd(%.*s) %%%c(%.*s) " + "gen_model_%.*s", + BSTR(e), BSTR(in), pt, BSTR(n1), BSTR(e)); + } + } else { + /* Single node input. */ + + if (n2) { + line = tprintf("a_gen_%.*s %.*s %%%cd(%.*s %.*s) " + "gen_model_%.*s", + BSTR(e), BSTR(in), pt, BSTR(n1), BSTR(n2), + BSTR(e)); + } else { + line = tprintf("a_gen_%.*s %.*s %%%c(%.*s) gen_model_%.*s", + BSTR(e), BSTR(in), pt, BSTR(n1), BSTR(e)); + } + } + } else { + /* Use a B-source for input. */ + + line = tprintf("b_gen_%.*s gen_node_%.*s 0 v=%.*s", + BSTR(e), BSTR(e), BSTR(expr)); + c = insert_new_line(c, line, (*line_number)++, c->linenum_orig); + if (n2) { + line = tprintf("a_gen_%.*s gen_node_%.*s %%%cd(%.*s %.*s) " + "gen_model_%.*s", + BSTR(e), BSTR(e), pt, BSTR(n1), BSTR(n2), BSTR(e)); + } else { + line = tprintf("a_gen_%.*s gen_node_%.*s %%%c(%.*s) " + "gen_model_%.*s", + BSTR(e), BSTR(e), pt, BSTR(n1), BSTR(e)); + } + } + c = insert_new_line(c, line, (*line_number)++, c->linenum_orig); + + line = tprintf(".model gen_model_%.*s xfer %s table = [%.*s]", + BSTR(e), + ri ? "r_i=true" : rad ? "rad=true" : !db ? "db=false" : "", + BSTR(list)); + c = insert_new_line(c, line, (*line_number)++, c->linenum_orig); +#endif +} + +/* Convert some E and G-source variants to XSPICE code models. */ + +static void inp_chk_for_e_source_to_xspice(struct card *c, int *line_number) { int skip_control = 0; @@ -1938,143 +2266,17 @@ static void inp_chk_for_multi_in_vcvs(struct card *c, int *line_number) continue; } - if (*line == 'e') { + if (*line == 'e' && inp_chk_for_multi_in_vcvs(c, line_number)) + continue; + if (*line != 'e' && *line != 'g') + continue; - char *fcn_b; + /* Is it the FREQ form with S-parameter table? */ - if (((fcn_b = strstr(line, "nand(")) != NULL || - (fcn_b = strstr(line, "and(")) != NULL || - (fcn_b = strstr(line, "nor(")) != NULL || - (fcn_b = strstr(line, "or(")) != NULL) && - isspace_c(fcn_b[-1])) { -#ifndef XSPICE - fprintf(stderr, - "\n" - "Error: XSPICE is required to run the 'multi-input " - "pwl' option in line %d\n" - " %s\n" - "\n" - "See manual chapt. 31 for installation " - "instructions\n", - *line_number, line); - controlled_exit(EXIT_BAD); -#else - char keep, *comma_ptr, *xy_values1[5], *xy_values2[5]; - char *out_str, *ctrl_nodes_str, - *xy_values1_b = NULL, *ref_str, *fcn_name, - *fcn_e = NULL, *out_b, *out_e, *ref_e; - char *m_instance, *m_model; - char *xy_values2_b = NULL, *xy_values1_e = NULL, - *ctrl_nodes_b = NULL, *ctrl_nodes_e = NULL; - int xy_count1, xy_count2; - bool ok = FALSE; - - do { - ref_e = skip_non_ws(line); - - out_b = skip_ws(ref_e); - - out_e = skip_back_ws(fcn_b, out_b); - if (out_e <= out_b) - break; - - fcn_e = strchr(fcn_b, '('); - - ctrl_nodes_b = strchr(fcn_e, ')'); - if (!ctrl_nodes_b) - break; - ctrl_nodes_b = skip_ws(ctrl_nodes_b + 1); - - comma_ptr = strchr(ctrl_nodes_b, ','); - if (!comma_ptr) - break; - - xy_values1_b = skip_back_ws(comma_ptr, ctrl_nodes_b); - if (xy_values1_b[-1] == '}') { - while (--xy_values1_b >= ctrl_nodes_b) - if (*xy_values1_b == '{') - break; - } - else { - xy_values1_b = - skip_back_non_ws(xy_values1_b, ctrl_nodes_b); - } - if (xy_values1_b <= ctrl_nodes_b) - break; - - ctrl_nodes_e = skip_back_ws(xy_values1_b, ctrl_nodes_b); - if (ctrl_nodes_e <= ctrl_nodes_b) - break; - - xy_values1_e = skip_ws(comma_ptr + 1); - if (*xy_values1_e == '{') { - xy_values1_e = inp_spawn_brace(xy_values1_e); - } - else { - xy_values1_e = skip_non_ws(xy_values1_e); - } - if (!xy_values1_e) - break; - - xy_values2_b = skip_ws(xy_values1_e); - - ok = TRUE; - } while (0); - - if (!ok) { - fprintf(stderr, "ERROR: malformed line: %s\n", line); - controlled_exit(EXIT_FAILURE); - } - - ref_str = copy_substring(line, ref_e); - out_str = copy_substring(out_b, out_e); - fcn_name = copy_substring(fcn_b, fcn_e); - ctrl_nodes_str = copy_substring(ctrl_nodes_b, ctrl_nodes_e); - - keep = *xy_values1_e; - *xy_values1_e = '\0'; - xy_count1 = - get_comma_separated_values(xy_values1, xy_values1_b); - *xy_values1_e = keep; - - xy_count2 = - get_comma_separated_values(xy_values2, xy_values2_b); - - // place restrictions on only having 2 point values; this can - // change later - if (xy_count1 != 2 && xy_count2 != 2) - fprintf(stderr, - "ERROR: only expecting 2 pair values for " - "multi-input vcvs!\n"); - - m_instance = tprintf("%s %%vd[ %s ] %%vd( %s ) %s", ref_str, - ctrl_nodes_str, out_str, ref_str); - m_instance[0] = 'a'; - - m_model = tprintf(".model %s multi_input_pwl ( x = [%s %s] y " - "= [%s %s] model = \"%s\" )", - ref_str, xy_values1[0], xy_values2[0], xy_values1[1], - xy_values2[1], fcn_name); - - tfree(ref_str); - tfree(out_str); - tfree(fcn_name); - tfree(ctrl_nodes_str); - tfree(xy_values1[0]); - tfree(xy_values1[1]); - tfree(xy_values2[0]); - tfree(xy_values2[1]); - - *c->line = '*'; - c = insert_new_line(c, m_instance, (*line_number)++, c->linenum_orig); - c = insert_new_line(c, m_model, (*line_number)++, c->linenum_orig); -#endif - } - } + replace_freq(c, line_number); } } - /* If ngspice is started with option -a, then variable 'autorun' * will be set and a control section is inserted to try and ensure * some analysis is done; diff --git a/src/xspice/icm/analog/modpath.lst b/src/xspice/icm/analog/modpath.lst index 481162718..acf24b33f 100644 --- a/src/xspice/icm/analog/modpath.lst +++ b/src/xspice/icm/analog/modpath.lst @@ -14,6 +14,7 @@ sine slew square summer +xfer s_xfer triangle file_source diff --git a/src/xspice/icm/analog/xfer/cfunc.mod b/src/xspice/icm/analog/xfer/cfunc.mod new file mode 100644 index 000000000..e57cbeaa8 --- /dev/null +++ b/src/xspice/icm/analog/xfer/cfunc.mod @@ -0,0 +1,130 @@ +/* Transfer function block for AC simulation, based on s_xfer code model. */ + +#include + +#define PI 3.141592653589793238462643383279502884197 + +/* How the table information is stored internally. */ + +struct data_pt { + double f; /* Frequency, radians/sec. */ + Mif_Complex_t s; /* The S-parameter. */ +}; + +static void cleanup(ARGS, Mif_Callback_Reason_t reason) +{ + struct data_pt *table; + + switch (reason) { + case MIF_CB_DESTROY: + table = (struct data_pt *)STATIC_VAR(table); + if (table) { + free(table); + STATIC_VAR(table) = NULL; + } + break; + } +} + +void cm_xfer(ARGS) /* structure holding parms, inputs, outputs, etc. */ +{ + struct data_pt *table; + Mif_Complex_t ac_gain; + double factor; + int span, size, i; + + span = PARAM(span); + if (INIT) { + Mif_Boolean_t ri, db, rad; + int offset, bad = 0, j; + + /* Validate table. */ + + offset = PARAM(offset); + size = PARAM_SIZE(table); + bad = size % span; + if (!bad) { + for (i = 0; i < size - span; i += span) { + if (PARAM(table[i]) < 0 || + PARAM(table[i + span]) < PARAM(table[i])) { + bad = 1; + break; + } + } + } + if (bad) { + cm_message_send("Warning: badly formed table."); + return; + } + + /* Allocate the internal table. */ + + size /= span; + table = (struct data_pt *)calloc(size, sizeof(struct data_pt)); + STATIC_VAR(table) = table; + CALLBACK = cleanup; + + /* Fill it. */ + + ri = PARAM(r_i); + db = PARAM(db); + rad = PARAM(rad); + for (i = 0, j = 0; i < size; i++, j += span) { + table[i].f = PARAM(table[j]) * 2.0 * PI; + if (ri) { + table[i].s.real = PARAM(table[j + offset]); + table[i].s.imag = PARAM(table[j + offset + 1]); + } else { + double phase, mag; + + mag = PARAM(table[j + offset]); + if (db) + mag = pow(10, mag / 20); + phase = PARAM(table[j + offset + 1]); + if (!rad) + phase *= 2 * PI / 360; + table[i].s.real = mag * cos(phase); + table[i].s.imag = mag * sin(phase); + } + } + } + + table = (struct data_pt *)STATIC_VAR(table); + if (!table) + return; + if (ANALYSIS == MIF_AC) { + double rv; + + size = PARAM_SIZE(table) / span; + rv = RAD_FREQ; + if (rv <= table[0].f) { + ac_gain = table[0].s; + } else if (rv >= table[size - 1].f) { + ac_gain = table[size - 1].s; + } else { + for (i = 0; i < size; i++) { + if (table[i].f > rv) + break; + } + + /* Linear interpolation. */ + + factor = (rv - table[i - 1].f) / (table[i].f - table[i - 1].f); + ac_gain.real = table[i - 1].s.real + + factor * (table[i].s.real - table[i - 1].s.real); + ac_gain.imag = table[i - 1].s.imag + + factor * (table[i].s.imag - table[i - 1].s.imag); + } + AC_GAIN(out, in) = ac_gain; + } else { /* DC, transient ... */ + if (ANALYSIS == MIF_TRAN) { + if (!STATIC_VAR(warned)) { + STATIC_VAR(warned) = 1; + cm_message_send("The xfer code model does not support " + "transient analysis."); + } + } + OUTPUT(out) = table[0].s.real * INPUT(in); + } +} + diff --git a/src/xspice/icm/analog/xfer/ifspec.ifs b/src/xspice/icm/analog/xfer/ifspec.ifs new file mode 100644 index 000000000..41f2ac177 --- /dev/null +++ b/src/xspice/icm/analog/xfer/ifspec.ifs @@ -0,0 +1,91 @@ +/* Interface specification for PWL transfer function code model. */ + +NAME_TABLE: + +Spice_Model_Name: xfer +C_Function_Name: cm_xfer +Description: "AC transfer function block" + + +PORT_TABLE: + +Port_Name: in out +Description: "input" "output" +Direction: in out +Default_Type: v v +Allowed_Types: [v,vd,i,id] [v,vd,i,id] +Vector: no no +Vector_Bounds: - - +Null_Allowed: no no + +PARAMETER_TABLE: + +Parameter_Name: table +Description: "PWL table: frequency/magnitude/phase" +Data_Type: real +Default_Value: - +Limits: - +Vector: yes +Vector_Bounds: [3 -] +Null_Allowed: no + +PARAMETER_TABLE: + +Parameter_Name: r_i +Description: "table is in real/imaginary format" +Data_Type: boolean +Default_Value: false +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: + +Parameter_Name: db +Description: "table is in magnitude(dB)/phase format" +Data_Type: boolean +Default_Value: true +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: + +Parameter_Name: rad +Description: "phase in radians, not degrees" +Data_Type: boolean +Default_Value: false +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + +PARAMETER_TABLE: + +Parameter_Name: span offset +Description: "Length of table rows" "Offset within row" +Data_Type: int int +Default_Value: 3 1 +Limits: [ 3 - ] [ 1 - ] +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + +/* This is used internally to store the table in compact complex form. */ + +STATIC_VAR_TABLE: + +Static_Var_Name: table +Description: "Internal copy of data" +Data_Type: pointer + +/* Only warn once about use in transient analysis. */ + +STATIC_VAR_TABLE: + +Static_Var_Name: warned +Description: "Warning indicator" +Data_Type: int + From 88500c640a6b76c2d0b053b6af3ee2c146c985a8 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 24 May 2023 10:47:01 +0200 Subject: [PATCH 59/72] Enable compiling with MSVC --- visualc/xspice/analog.vcxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/visualc/xspice/analog.vcxproj b/visualc/xspice/analog.vcxproj index 39ec8381d..fd8097bc4 100644 --- a/visualc/xspice/analog.vcxproj +++ b/visualc/xspice/analog.vcxproj @@ -254,6 +254,8 @@ + + @@ -297,6 +299,8 @@ + + From 981c63f1ab55f3c277df8f82278af9cbd06e4b3c Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 2 Jun 2023 15:31:28 +0200 Subject: [PATCH 60/72] Add an extra model stitching for CIDER only. This one fills in actualLine, which is use by parsing the CIDER model parameters in INPparseNumMod() from inpgmod.c --- src/frontend/inpcom.c | 114 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index d0314d41a..2c29d83c8 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -705,6 +705,116 @@ static void inp_stitch_continuation_lines(struct card* working) ds_free(&newline); } +#ifdef CIDER +/* Only if we have a CIDER .model line with regular structure +'.model modname modtype level', +with modtype being one of numos, numd, nbjt: +Concatenate lines +line1 + + line2 + ----> + line1 line 2 +Store the original lines in card->actualLine, to be used for +CIDER model parameter parsing in INPparseNumMod() of inpgmod.c + */ +static void inp_cider_models(struct card* working) +{ + struct card* prev = NULL; + bool iscmod = FALSE; + + while (working) { + char *s, c, *buffer; + + for (s = working->line; (c = *s) != '\0' && c <= ' '; s++) + ; + + if(!iscmod) + iscmod = is_cider_model(s); + +#ifdef TRACE + /* SDB debug statement */ + printf("In inp_read, processing linked list element line = %d, s = " + "%s . . . \n", + working->linenum, s); +#endif + + if (iscmod) { + switch (c) { + case '#': + case '$': + case '*': + case '\0': + /* skip these cards, and keep prev as the last regular card */ + working = working->nextcard; /* for these chars, go to next + card */ + break; + + case '+': /* handle continuation */ + if (!prev) { + working->error = + copy("Illegal continuation line: ignored."); + working = working->nextcard; + break; + } + + /* We now may have lept over some comment lines, which are + located among the continuation lines. We have to delete them + here to prevent a memory leak */ + while (prev->nextcard != working) { + struct card* tmpl = prev->nextcard->nextcard; + line_free_x(prev->nextcard, FALSE); + prev->nextcard = tmpl; + } + + /* create buffer and write last and current line into it. + When reading a PDK, the following may be called more than 1e6 times. */ +#if defined (_MSC_VER) + /* vsnprintf (used by tprintf) in Windows is efficient, VS2019 arb. referencevalue 7, + cat2strings() yields ref. speed value 12 only, CYGWIN is 12 in both cases, + MINGW is 36. */ + buffer = tprintf("%s %s", prev->line, s + 1); +#else + /* vsnprintf in Linux is very inefficient, ref. value 24 + cat2strings() is efficient with ref. speed value 6, + MINGW is 12 */ + buffer = cat2strings(prev->line, s + 1, TRUE); +#endif + /* replace prev->line by buffer */ + s = prev->line; + prev->line = buffer; + prev->nextcard = working->nextcard; + working->nextcard = NULL; + /* add original line to prev->actualLine */ + if (prev->actualLine) { + struct card* end; + for (end = prev->actualLine; end->nextcard; + end = end->nextcard) + ; + end->nextcard = working; + tfree(s); + } + else { + prev->actualLine = + insert_new_line(NULL, s, prev->linenum, 0); + prev->actualLine->level = prev->level; + prev->actualLine->nextcard = working; + } + working = prev->nextcard; + break; + + default: /* regular one-line card */ + prev = working; + working = working->nextcard; + iscmod = is_cider_model(s); + break; + } + } + else + working = working->nextcard; + } +} +#endif + /* * search for `=' assignment operator * take care of `!=' `<=' `==' and `>=' @@ -1580,6 +1690,10 @@ struct inp_read_t inp_read( FILE *fp, int call_depth, const char *dir_name, if this is a command file or called from within a .control section. */ inp_stripcomments_deck(cc->nextcard, comfile || is_control); +#ifdef CIDER + inp_cider_models(cc->nextcard); +#endif + inp_stitch_continuation_lines(cc->nextcard); rv.line_number = line_number; From 5ba0177f21e6530a9d5a4d86e5928f73086272ea Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 2 Jun 2023 19:43:47 +0200 Subject: [PATCH 61/72] CIDER: Plug small memory leaks in INPparseNumMod() --- src/spicelib/parser/inpgmod.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/spicelib/parser/inpgmod.c b/src/spicelib/parser/inpgmod.c index 8892343b7..6450abf6d 100644 --- a/src/spicelib/parser/inpgmod.c +++ b/src/spicelib/parser/inpgmod.c @@ -462,8 +462,10 @@ INPparseNumMod(CKTcircuit *ckt, INPmodel *model, INPtables *tab, char **errMessa /* Add card structure to model */ info = INPcardTab[lastType]; error = info->newCard(&tmpCard, model->INPmodfast); - if (error) + if (error) { + FREE(cardName); return error; + } /* Handle parameter-less cards */ } else if (cinprefix(cardName, "title", 3)) { /* Do nothing */ @@ -472,6 +474,7 @@ INPparseNumMod(CKTcircuit *ckt, INPmodel *model, INPtables *tab, char **errMessa } else if (cinprefix(cardName, "end", 3)) { /* Terminate parsing */ *errMessage = err; + FREE(cardName); return 0; } else { /* Error */ @@ -479,6 +482,7 @@ INPparseNumMod(CKTcircuit *ckt, INPmodel *model, INPtables *tab, char **errMessa tprintf("Error on card %d : unrecognized name (%s) - ignored", cardNum, cardName)); } + FREE(cardName); } } @@ -525,6 +529,8 @@ INPparseNumMod(CKTcircuit *ckt, INPmodel *model, INPtables *tab, char **errMessa } error = info->setCardParm(info->cardParms[idx].id, value, tmpCard); + if (info->cardParms[idx].dataType & IF_STRING) + FREE(value->sValue); if (error) return error; } From 27173c9622802d65740f5ebe654c046b9f18948d Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 2 Jun 2023 19:44:34 +0200 Subject: [PATCH 62/72] CIDER: Plug some memory leaks by adding to TWOdestroy() --- src/ciderlib/twod/twodest.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/ciderlib/twod/twodest.c b/src/ciderlib/twod/twodest.c index d51297f93..147f5072b 100644 --- a/src/ciderlib/twod/twodest.c +++ b/src/ciderlib/twod/twodest.c @@ -66,9 +66,22 @@ TWOdestroy(TWOdevice *pDevice) FREE( pElem ); } FREE( pDevice->elements ); + for (int xIndex = 1; xIndex < pDevice->numXNodes; xIndex++) { + FREE(pDevice->elemArray[xIndex]); + } FREE( pDevice->elemArray ); } + if (pDevice->pMaterials) { + TWOmaterial* pMtmp = pDevice->pMaterials; + while (pMtmp) { + TWOmaterial* pMtmpnext = pMtmp->next; + FREE(pMtmp); + pMtmp = pMtmpnext; + } + } + + /* destroy the contacts & channels */ /* NOT IMPLEMENTED */ From 7de5fd276ead8da2b96d70057dbbd8944dc1e89f Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 2 Jun 2023 22:30:27 +0200 Subject: [PATCH 63/72] CIDER: Plug some memory leak --- src/ciderlib/twod/twodest.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ciderlib/twod/twodest.c b/src/ciderlib/twod/twodest.c index 147f5072b..01b646c42 100644 --- a/src/ciderlib/twod/twodest.c +++ b/src/ciderlib/twod/twodest.c @@ -81,8 +81,16 @@ TWOdestroy(TWOdevice *pDevice) } } + if (pDevice->pFirstContact) { + struct sTWOcontact* pFCtmp = pDevice->pFirstContact; + while (pFCtmp) { + struct sTWOcontact* pFCtmpnext = pFCtmp->next; + FREE(pFCtmp); + pFCtmp = pFCtmpnext; + } + } - /* destroy the contacts & channels */ + /* destroy the channels */ /* NOT IMPLEMENTED */ FREE( pDevice ); From a03369fc12cbe8125175e35d776e493795b8e4b1 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 3 Jun 2023 15:48:06 +0200 Subject: [PATCH 64/72] Improve error message --- src/frontend/inpcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 2c29d83c8..1137a36b3 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -9016,7 +9016,7 @@ utf8_syntax_check(struct card *deck) s = utf8_check((unsigned char*)curr_line); if (s) { - fprintf(stderr, "Error: UTF-8 syntax error in line %d at %s\n", card->linenum_orig, s); + fprintf(stderr, "Error: UTF-8 syntax error in input deck,\n line %d at token/word %s\n", card->linenum_orig, s); controlled_exit(1); } } From 10e86d72d3fbe48cc55c81d366176020609df0d3 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 3 Jun 2023 17:09:10 +0200 Subject: [PATCH 65/72] Prevent crash upon buggy user input (missing ] or >) --- src/frontend/inpcom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 1137a36b3..aa9305c1d 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -4558,7 +4558,7 @@ static void inp_fix_param_values(struct card *c) brackets around all params inside a pair of square brackets */ end_of_str = beg_of_str; - while (*end_of_str != ']') + while (*end_of_str != ']' && *end_of_str != '\0') end_of_str++; /* string xx yyy from vector [xx yyy] */ tmp_str = vec_str = @@ -4634,7 +4634,7 @@ static void inp_fix_param_values(struct card *c) /* A complex value following the '=' token: code to put curly brackets around all params inside a pair < > */ end_of_str = beg_of_str; - while (*end_of_str != '>') + while (*end_of_str != '>' && *end_of_str != '\0') end_of_str++; /* string xx yyy from vector [xx yyy] */ vec_str = copy_substring(beg_of_str + 1, end_of_str); From 3a535f19db7a069f6c981527793d2431a3c220eb Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 4 Jun 2023 09:46:13 +0200 Subject: [PATCH 66/72] Add a control language function cvector, to create a complex vector. Let vec1 = cvector(50) will generate a complex vector, with the real part values increasing from 0 to 49, the imaginary values are set to 0. Useful in ac loops to store result data. --- src/frontend/parse.c | 1 + src/include/ngspice/fteext.h | 1 + src/maths/cmaths/cmath2.c | 36 ++++++++++++++++++++++++++++++++++-- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/frontend/parse.c b/src/frontend/parse.c index 16666a1bc..ebe22d309 100644 --- a/src/frontend/parse.c +++ b/src/frontend/parse.c @@ -360,6 +360,7 @@ struct func ft_funcs[] = { { "avg", cx_avg }, /* A.Roldan 03/06/05 incremental average new function */ { "group_delay", (cx_function_t*)(void *) cx_group_delay }, /* A.Roldan 10/06/05 group delay new function */ { "vector", cx_vector }, + { "cvector", cx_cvector }, { "unitvec", cx_unitvec }, { "length", cx_length }, { "vecmin", cx_min }, diff --git a/src/include/ngspice/fteext.h b/src/include/ngspice/fteext.h index 7c8a383b7..4f2ce0c35 100644 --- a/src/include/ngspice/fteext.h +++ b/src/include/ngspice/fteext.h @@ -93,6 +93,7 @@ extern void *cx_mean(void *, short int , int , int *, short int *); extern void *cx_stddev(void *, short int , int , int *, short int *); extern void *cx_length(void *, short int , int , int *, short int *); extern void *cx_vector(void *, short int , int , int *, short int *); +extern void *cx_cvector(void *, short int , int , int *, short int *); extern void *cx_unitvec(void *, short int , int , int *, short int *); extern void *cx_plus(void *, void *, short int , short int , int ); extern void *cx_minus(void *, void *, short int , short int , int ); diff --git a/src/maths/cmaths/cmath2.c b/src/maths/cmaths/cmath2.c index 888c15a44..6dc37b6b1 100644 --- a/src/maths/cmaths/cmath2.c +++ b/src/maths/cmaths/cmath2.c @@ -4,7 +4,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group **********/ /** \file cmath2.c - \brief functions for the control language parser: norm, uminus, rnd, sunif, sgauss, poisson, exponential, mean, stddev, length, vector, unitvec, plus, minus, times, mod, max, min, d, avg, floor, ceil, nint + \brief functions for the control language parser: norm, uminus, rnd, sunif, sgauss, poisson, exponential, mean, stddev, length, vector, cvector, unitvec, plus, minus, times, mod, max, min, d, avg, floor, ceil, nint Routines to do complex mathematical functions. These routines require the -lm libraries. We sacrifice a lot of space to be able @@ -479,7 +479,7 @@ cx_length(void *data, short int type, int length, int *newlength, short int *new /* Return a vector from 0 to the magnitude of the argument. Length of the - * argument is irrelevent. + * argument is irrelevant. */ void * @@ -506,6 +506,38 @@ cx_vector(void *data, short int type, int length, int *newlength, short int *new return ((void *) d); } +/* Return a complex vector. Argument sets the length of the vector. +The real part ranges from 0 to the magnitude of the argument. The imaginary +part is set to 0. + */ + +void* +cx_cvector(void* data, short int type, int length, int* newlength, short int* newtype) +{ + ngcomplex_t* cc = (ngcomplex_t*)data; + double* dd = (double*)data; + int i, len; + ngcomplex_t* d; + + NG_IGNORE(length); + + if (type == VF_REAL) + len = (int)fabs(*dd); + else + len = (int)cmag(*cc); + if (len == 0) + len = 1; + d = alloc_c(len); + *newlength = len; + *newtype = VF_COMPLEX; + for (i = 0; i < len; i++) { + realpart(d[i]) = i; + imagpart(d[i]) = 0; + } + return ((void*)d); +} + + /* Create a vector of the given length composed of all ones. */ From 1ddb1f58b4e2567b289064134faec3557be32418 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 4 Jun 2023 10:36:21 +0200 Subject: [PATCH 67/72] Bail out if {...} or '...' are missing around RHS of the equation. (...) may be possible, elsewhere additional {} are put around, so we have {(...)}. --- src/frontend/inpcom.c | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index aa9305c1d..8916c4d65 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -6240,14 +6240,9 @@ static void inp_compat(struct card *card) /* Find equation, starts with '{', till end of line */ str_ptr = strchr(cut_line, '{'); if (str_ptr == NULL) { - /* if not, equation may start with a '(' */ - str_ptr = strchr(cut_line, '('); - if (str_ptr == NULL) { - fprintf(stderr, "ERROR: mal formed R line: %s\n", - curr_line); - controlled_exit(EXIT_FAILURE); - } - equation = gettok_char(&str_ptr, ')', TRUE, TRUE); + fprintf(stderr, "ERROR: mal formed R line: %s\n", curr_line); + fprintf(stderr, " {...} or '...' around equation's right hand side are missing!\n"); + controlled_exit(EXIT_FAILURE); } else equation = gettok_char(&str_ptr, '}', TRUE, TRUE); @@ -6324,14 +6319,9 @@ static void inp_compat(struct card *card) /* Find equation, starts with '{', till end of line */ str_ptr = strchr(cut_line, '{'); if (str_ptr == NULL) { - /* if not, equation may start with a '(' */ - str_ptr = strchr(cut_line, '('); - if (str_ptr == NULL) { - fprintf(stderr, "ERROR: mal formed C line: %s\n", - curr_line); - controlled_exit(EXIT_FAILURE); - } - equation = gettok_char(&str_ptr, ')', TRUE, TRUE); + fprintf(stderr, "ERROR: mal formed C line: %s\n", curr_line); + fprintf(stderr, " {...} or '...' around equation's right hand side are missing!\n"); + controlled_exit(EXIT_FAILURE); } else equation = gettok_char(&str_ptr, '}', TRUE, TRUE); @@ -6399,14 +6389,9 @@ static void inp_compat(struct card *card) /* Find equation, starts with '{', till end of line */ str_ptr = strchr(cut_line, '{'); if (str_ptr == NULL) { - /* if not, equation may start with a '(' */ - str_ptr = strchr(cut_line, '('); - if (str_ptr == NULL) { - fprintf(stderr, "ERROR: mal formed L line: %s\n", - curr_line); - controlled_exit(EXIT_FAILURE); - } - equation = gettok_char(&str_ptr, ')', TRUE, TRUE); + fprintf(stderr, "ERROR: mal formed L line: %s\n", curr_line); + fprintf(stderr, " {...} or '...' around equation's right hand side are missing!\n"); + controlled_exit(EXIT_FAILURE); } else equation = gettok_char(&str_ptr, '}', TRUE, TRUE); From 6dc09e6592e8eab7916696dd5e34310a50585a6e Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 4 Jun 2023 14:01:44 +0200 Subject: [PATCH 68/72] During syntax check: v,i sources need two nodes, and prevent crash upon buggy ac input. --- src/frontend/inpcom.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 8916c4d65..0a6febaa0 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -8421,7 +8421,17 @@ static void inp_check_syntax(struct card *deck) /* check for missing ac in voltage or current source */ if (check_control == 0 && strchr("VvIi", *cut_line)) { int err = 0; - char* acline = search_plain_identifier(cut_line, "ac"); + char* acline; + /* skip instance name and nodes */ + acline = nexttok(cut_line); + acline = nexttok(acline); + acline = nexttok(acline); + if (!acline) { + fprintf(stderr, "Error in line %s\n", cut_line); + fprintf(stderr, " Not enough parameters\n"); + controlled_exit(EXIT_BAD); + } + acline = search_plain_identifier(acline, "ac"); if (acline == NULL) continue; /* skip ac */ @@ -8438,17 +8448,20 @@ static void inp_check_syntax(struct card *deck) char* nnacline = nacline; /* get first token after ac */ char* numtok = gettok_node(&nnacline); - char* numtokfree = numtok; - /* Check if token is a parameter, to be filled in later */ - if (*numtok == '\'' || *numtok == '{') { - err = 0; + if (numtok) { + char* numtokfree = numtok; + /* Check if token is a parameter, to be filled in later */ + if (*numtok == '\'' || *numtok == '{') { + err = 0; + } + else { + /* check if token is a valid number */ + INPevaluate(&numtok, &err, 0); + } + tfree(numtokfree); } - else { - /* check if token is a valid number */ - INPevaluate(&numtok, &err, 0); - } - - tfree(numtokfree); + else + err = 1; } /* if no number, replace 'ac' by 'ac 1 0' */ if (err){ From 525d221325e5b520ca89b61e45f6b51e86256f9e Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 4 Jun 2023 14:23:09 +0200 Subject: [PATCH 69/72] Prevent crash if no or not enough coeffs are given. r is then probably not the repeat coefficient. --- src/spicelib/devices/vsrc/vsrcpar.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/spicelib/devices/vsrc/vsrcpar.c b/src/spicelib/devices/vsrc/vsrcpar.c index 72738cd31..dc77219b7 100644 --- a/src/spicelib/devices/vsrc/vsrcpar.c +++ b/src/spicelib/devices/vsrc/vsrcpar.c @@ -131,6 +131,12 @@ VSRCparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select) here->VSRCrGiven = FALSE; break; } + + if (!here->VSRCcoeffs || here->VSRCfunctionOrder < 2) { + here->VSRCrGiven = FALSE; + break; + } + here->VSRCr = value->rValue; here->VSRCrGiven = TRUE; From 1ff095321cf74d7f7e678718937316698404681e Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 4 Jun 2023 14:36:03 +0200 Subject: [PATCH 70/72] add comment --- src/spicelib/devices/vsrc/vsrcpar.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/spicelib/devices/vsrc/vsrcpar.c b/src/spicelib/devices/vsrc/vsrcpar.c index dc77219b7..27bed7c4f 100644 --- a/src/spicelib/devices/vsrc/vsrcpar.c +++ b/src/spicelib/devices/vsrc/vsrcpar.c @@ -132,6 +132,7 @@ VSRCparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select) break; } + /* buggy input? r is not a repetition coefficient */ if (!here->VSRCcoeffs || here->VSRCfunctionOrder < 2) { here->VSRCrGiven = FALSE; break; From a99caf504f22b1af70f7d850ebf377754cc27e72 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 4 Jun 2023 14:36:27 +0200 Subject: [PATCH 71/72] No syntax check for title line --- src/frontend/inpcom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 0a6febaa0..d9d927bae 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -1032,8 +1032,8 @@ struct card *inp_readall(FILE *fp, const char *dir_name, utf8_syntax_check(working); #endif - /* some syntax checks, including title line */ - inp_check_syntax(cc); + /* some syntax checks, excluding title line */ + inp_check_syntax(working); if (newcompat.lt && newcompat.a) ltspice_compat_a(working); From 5e73be130a9aaeed596b9f2e8d79648da51b1a72 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 4 Jun 2023 14:53:38 +0200 Subject: [PATCH 72/72] Allow ';' also at the beginning of a line. --- src/frontend/inpcom.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index d9d927bae..a4b157de3 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -8349,14 +8349,14 @@ static void inp_check_syntax(struct card *deck) if (*cut_line == '*' || *cut_line == '\0') continue; // check for unusable leading characters and change them to '*' - if (strchr("=[]?()&%$\"!:,\f;", *cut_line)) { + if (strchr("=[]?()&%$\"!:,\f", *cut_line)) { if (ft_stricterror) { fprintf(stderr, "Error: '%c' is not allowed as first character in line %s.\n", *cut_line, cut_line); controlled_exit(EXIT_BAD); } else { if (!check_ch) { - fprintf(stderr, "Warning: Unusual leading characters like '%c' or others out of '= [] ? () & %% $\"!:,;\\f'\n", *cut_line); + fprintf(stderr, "Warning: Unusual leading characters like '%c' or others out of '= [] ? () & %% $\"!:,\\f'\n", *cut_line); fprintf(stderr, " in netlist or included files, will be replaced with '*'.\n"); fprintf(stderr, " Check line no %d: %s\n\n", card->linenum_orig, cut_line); check_ch = 1; /* just one warning */ @@ -8364,6 +8364,10 @@ static void inp_check_syntax(struct card *deck) *cut_line = '*'; } } + /* leading end-of-line delimiter ';' silently change to '*' */ + else if (*cut_line == ';') { + *cut_line = '*'; + } // check for .control ... .endc if (ciprefix(".control", cut_line)) { if (check_control > 0) {