diff --git a/configure.ac b/configure.ac index 2419e69f1..267bdd4ba 100644 --- a/configure.ac +++ b/configure.ac @@ -70,6 +70,10 @@ AC_ARG_ENABLE([adms], AC_ARG_ENABLE([pss], [AS_HELP_STRING([--enable-pss], [Enable PSS Analysis, (experimental)])]) +# --enable-loopana: enable Loop Analysis +AC_ARG_ENABLE([loopana], + [AS_HELP_STRING([--enable-loopana], [Enable Loop Analysis])]) + # --enable-relpath: Relative path for binary and data. Default is "no". # ngspice shared may want relative paths for spinit etc. AC_ARG_ENABLE([relpath], @@ -967,6 +971,11 @@ if test "x$enable_pss" = xyes; then AC_DEFINE([WITH_PSS], [], [Define if you want PSS analysis]) AC_MSG_RESULT([WARNING: PSS analysis enabled]) fi +if test "x$enable_loopana" = xyes; then + AC_DEFINE([WITH_LOOPANA], [], [Define if you want LOOP analysis]) + AC_MSG_RESULT([WARNING: LOOP analysis enabled]) +fi + if test "x$enable_blktmsdebug" = xyes; then AC_DEFINE([D_DBG_BLOCKTIMES], [], [Define if we want debug distortion analysis (BLOCKTIMES)]) AC_MSG_RESULT([WARNING: Distortion analysis debug *D_DBG_BLOCKTIMES* is enabled]) @@ -1059,6 +1068,8 @@ AM_CONDITIONAL([NUMDEV_WANTED], [test "x$enable_cider" = xyes]) AM_CONDITIONAL([PSS_WANTED], [test "x$enable_pss" = xyes]) +AM_CONDITIONAL([LOOPANA_WANTED], [test "x$enable_loopana" = xyes]) + AM_CONDITIONAL([SENSE2_WANTED], [test "x$enable_sense2" = xyes]) # adms option diff --git a/src/frontend/spiceif.c b/src/frontend/spiceif.c index 9683d3fb1..481bbcfd1 100644 --- a/src/frontend/spiceif.c +++ b/src/frontend/spiceif.c @@ -220,6 +220,9 @@ if_run(CKTcircuit *ckt, char *what, wordlist *args, INPtables *tab) /* SP: Steady State Analysis */ || eq(what, "pss") /* SP */ +#endif +#ifdef WITH_LOOPANA + || eq(what, "loop") #endif ) { @@ -335,6 +338,9 @@ if_run(CKTcircuit *ckt, char *what, wordlist *args, INPtables *tab) /* SP: Steady State Analysis */ (eq(what, "pss")) || /* SP */ +#endif +#ifdef WITH_LOOPANA + (eq(what, "loop")) || #endif (eq(what, "run"))) { diff --git a/src/frontend/typesdef.c b/src/frontend/typesdef.c index b15c389f0..2fcb83829 100644 --- a/src/frontend/typesdef.c +++ b/src/frontend/typesdef.c @@ -86,7 +86,9 @@ static struct plotab plotabs[NUMPLOTTYPES] = { { "sp", "sp", FALSE, FALSE }, { "harm", "harm", FALSE, FALSE }, { "spect", "spect", FALSE, FALSE }, - { "pss", "periodic", FALSE, FALSE } + { "pss", "periodic", FALSE, FALSE }, + { "loop", "loop", FALSE, FALSE }, + }; diff --git a/src/spicelib/analysis/Makefile.am b/src/spicelib/analysis/Makefile.am index 86d6b7371..e4169edbd 100644 --- a/src/spicelib/analysis/Makefile.am +++ b/src/spicelib/analysis/Makefile.am @@ -106,6 +106,12 @@ libckt_la_SOURCES += \ psssetp.c endif +if LOOPANA_WANTED +libckt_la_SOURCES += \ + loopan.c \ + loopsetp.c \ + loopaskq.c +endif AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include -I$(top_srcdir)/src/spicelib/devices AM_CFLAGS = $(STATIC) diff --git a/src/spicelib/analysis/analysis.c b/src/spicelib/analysis/analysis.c index ecb9279a6..65c98a78a 100644 --- a/src/spicelib/analysis/analysis.c +++ b/src/spicelib/analysis/analysis.c @@ -20,6 +20,10 @@ extern SPICEanalysis SENSinfo; extern SPICEanalysis PSSinfo; #endif +#ifdef WITH_LOOPANA +extern SPICEanalysis LOOPinfo; +#endif + #ifdef WANT_SENSE2 extern SPICEanalysis SEN2info; #endif @@ -38,6 +42,9 @@ SPICEanalysis *analInfo[] = { #ifdef WITH_PSS &PSSinfo, #endif +#ifdef WITH_LOOPANA + &LOOPinfo, +#endif #ifdef WANT_SENSE2 &SEN2info, #endif diff --git a/src/spicelib/analysis/analysis.h b/src/spicelib/analysis/analysis.h index 78c1b91e9..64457bde2 100644 --- a/src/spicelib/analysis/analysis.h +++ b/src/spicelib/analysis/analysis.h @@ -10,6 +10,9 @@ struct SPICEanalysis { int (*askQuest)(CKTcircuit *ckt, JOB *anal, int which, IFvalue *value); int (*an_init)(CKTcircuit *ckt, JOB *job); int (*an_func)(CKTcircuit *ckt, int restart); + #ifdef WITH_LOOPANA + int (*an_preset)(CKTcircuit *ckt, JOB *job); + #endif }; diff --git a/src/spicelib/analysis/cktdojob.c b/src/spicelib/analysis/cktdojob.c index 5c87b2101..45a6d7312 100644 --- a/src/spicelib/analysis/cktdojob.c +++ b/src/spicelib/analysis/cktdojob.c @@ -156,6 +156,20 @@ CKTdoJob(CKTcircuit *ckt, int reset, TSKtask *task) /* gtri - end - 12/12/90 */ #endif +#ifdef WITH_LOOPANA + /* add opportunity to modify the circuit before CKTsetup */ + /* Note that it must be done in a benign way in order not to */ + /* affect others analysis */ + for (i = 0; i < ANALmaxnum; i++) + for (job = task->jobs; job; job = job->JOBnextJob) + if (job->JOBtype == i) + if (!error) + { + if (analInfo[i]->an_preset) + error = analInfo[i]->an_preset (ckt, job); + } +#endif + if (!error) error = CKTsetup(ckt); diff --git a/src/spicelib/parser/inp2dot.c b/src/spicelib/parser/inp2dot.c index 18be7ca2e..a68206ea1 100644 --- a/src/spicelib/parser/inp2dot.c +++ b/src/spicelib/parser/inp2dot.c @@ -14,6 +14,21 @@ Modified: 2000 AlansFixes #include "ngspice/cpdefs.h" #include "ngspice/tskdefs.h" +/* F.B. 2020 + parse additionnal parameters in the form key=val. + Use analysis INFO IFparm list to check if key is recognized and + the type of val. +*/ +static int +dot_params(char *line, CKTcircuit *ckt, int ana, JOB* job) +{ + char *name; /* the resistor's name */ + while(*line) + { + + } +} + static int dot_noise(char *line, CKTcircuit *ckt, INPtables *tab, struct card *current, TSKtask *task, CKTnode *gnode, JOB *foo) @@ -553,6 +568,137 @@ dot_sens2(char *line, CKTcircuit *ckt, INPtables *tab, struct card *current, } #endif +#ifdef WITH_LOOPANA +int +dot_loop(char *line, void *ckt, INPtables *tab, struct card *current, + void *task, void *gnode, JOB *foo) +{ +int error; /* error code temporary */ + IFvalue ptemp; /* a value structure to package resistance into */ + IFvalue *parm; /* a pointer to a value struct for function returns */ + char *nname; /* the oscNode name */ + CKTnode *nnode; /* the oscNode node */ + int which; /* which analysis we are performing */ + char *word; /* something to stick a word of input into */ + char *steptype; /* type of stepping function */ + char *name; /* a name */ + + static char* probesparams[2]={"probe","probe-"}; + static char* probenumparams[2]={"portnum","portnum-"}; + static char* probenameparams[2]={"portname","portname-"}; + static char* dirparams[2]={"dir","dir-"}; + + NG_IGNORE(gnode); + + /* .loop probe {DEC OCT LIN} NP FSTART FSTOP */ + /* @M2(#2) @M2:gate:into + + + */ + which = ft_find_analysis("LOOP"); + if (which == -1) { + LITERR("Loop analysis unsupported.\n"); + return (0); + } + IFC(newAnalysis, (ckt, which, "Loop gain analysis", &foo, task)); + + for(int diff=0;diff<2;diff++) + { + INPgetTok(&line, &name, 1); + INPinsert(&name, tab); + if(0) printf("loop probe element is %s\n", name); + ptemp.uValue = name; + GCA(INPapName, (ckt, which, foo, probesparams[diff], &ptemp)); + + if(*line=='/') + { + INPgetTok(&line, &name, 1); /* eat / */ + tfree(name); + INPgetTok(&line, &name, 1); + if(*name== '#') { + if(0) printf("port number %d\n",atoi(&name[1])); + ptemp.iValue = atoi(&name[1]); + tfree(name); + GCA(INPapName, (ckt, which, foo, probenumparams[diff], &ptemp)); + } else { + if(0) printf("port name %s\n",name); + ptemp.uValue = name; + GCA(INPapName, (ckt, which, foo, probenameparams[diff], &ptemp)); + } + } + if(*line=='/') + { + INPgetTok(&line, &name, 1); /* eat / */ + tfree(name); + INPgetTok(&line, &name, 1); + if(strcmp(name, "in")==0 || strcmp(name, "into")==0 + || strcmp(name, "to")==0 ) { + if(0) printf("into\n"); + ptemp.iValue = 1; + GCA(INPapName, (ckt, which, foo, dirparams[diff], &ptemp)); + } else if(strcmp(name, "out")==0 || strcmp(name, "from")==0 + || strcmp(name, "outfrom")==0) { + if(0) printf("out\n"); + ptemp.iValue = 2; + GCA(INPapName, (ckt, which, foo, dirparams[diff], &ptemp)); + } else + printf("syntax error for .loop, expect direction, got %s\n", name); + tfree(name); + } + if(*line != '+') break; + INPgetTok(&line, &name, 1); tfree(name); /* eat the + and start again*/ + } + + INPgetTok(&line, &steptype, 1); + ptemp.iValue = 1; + GCA(INPapName, (ckt, which, foo, steptype, &ptemp)); + tfree(steptype); + parm = INPgetValue(ckt, &line, IF_INTEGER, tab); /* number of points */ + GCA(INPapName, (ckt, which, foo, "numsteps", parm)); + parm = INPgetValue(ckt, &line, IF_REAL, tab); /* fstart */ + GCA(INPapName, (ckt, which, foo, "start", parm)); + parm = INPgetValue(ckt, &line, IF_REAL, tab); /* fstop */ + GCA(INPapName, (ckt, which, foo, "stop", parm)); + + if(*line) + { + /* input & output follows for transfert function calculations */ + INPgetTok(&line, &name, 1); + INPinsert(&name, tab); + ptemp.uValue = name; + GCA(INPapName, (ckt, which, foo, "insrc", &ptemp)); + + INPgetTok(&line, &name, 1); + if(strcmp(name,"v")==0 && *line=='(') + { + /* v(pos,neg) format */ + tfree(name); + INPgetNetTok(&line, &name, 0); + INPtermInsert(ckt, &name, tab, &ptemp.nValue); + GCA(INPapName, (ckt, which, foo, "outpos", &ptemp)); + if(*line==',') { + INPgetNetTok(&line, &name, 1); + INPtermInsert(ckt, &name, tab, &ptemp.nValue); + GCA(INPapName, (ckt, which, foo, "outneg", &ptemp)); + } else { + ptemp.nValue = gnode; + GCA(INPapName, (ckt, which, foo, "outneg", &ptemp)); + } + } + else + { + INPinsert(&name, tab); + ptemp.uValue = name; + GCA(INPapName, (ckt, which, foo, "outsrc", &ptemp)); + } + + } + + return (0); + +} +#endif + #ifdef WITH_PSS /*SP: Steady State Analyis */ static int @@ -699,6 +845,11 @@ INP2dot(CKTcircuit *ckt, INPtables *tab, struct card *current, TSKtask *task, CK rtn = dot_pss(line, ckt, tab, current, task, gnode, foo); goto quit; /* SP */ +#endif +#ifdef WITH_LOOPANA + } else if ((strcmp(token, ".loop") == 0)) { + rtn = dot_loop(line, ckt, tab, current, task, gnode, foo); + goto quit; #endif } else if ((strcmp(token, ".subckt") == 0) || (strcmp(token, ".ends") == 0)) {