diff --git a/configure.ac b/configure.ac index 267bdd4ba..f4f5ece32 100644 --- a/configure.ac +++ b/configure.ac @@ -1261,6 +1261,7 @@ AC_CONFIG_FILES([Makefile src/spicelib/devices/numd/Makefile src/spicelib/devices/numd2/Makefile src/spicelib/devices/numos/Makefile + src/spicelib/devices/balun/Makefile src/spicelib/parser/Makefile src/ciderlib/Makefile src/ciderlib/input/Makefile diff --git a/examples/loop/diffpair.cir b/examples/loop/diffpair.cir new file mode 100644 index 000000000..2e25426e0 --- /dev/null +++ b/examples/loop/diffpair.cir @@ -0,0 +1,32 @@ +* simple differential pair with simple common-mode feedback + +.model n1 nmos level=49 version=3.3.0 tox=3.5n nch=2.4e17 nsub=5e16 vth0=0.6 +.model p1 pmos level=49 version=3.3.0 tox=3.5n nch=2.5e17 nsub=5e16 vth0=-0.7 + +.subckt diffpair inp inn outp outn setcm vdd vss +Mp1 outp cmfb vdd vdd p1 W=7.5u L=0.35u pd=13.5u ad=22.5p ps=13.5u as=22.5p m=4 +Mp2 outn cmfb vdd vdd p1 W=7.5u L=0.35u pd=13.5u ad=22.5p ps=13.5u as=22.5p m=4 +Mpcm cmfb cmfb vdd vdd p1 W=7.5u L=0.35u pd=13.5u ad=22.5p ps=13.5u as=22.5p m=2 + +Mncm cmfb setcm tail vss n1 W=7.5u L=0.35u pd=13.5u ad=22.5p ps=13.5u as=22.5p m=4 +Mn1 outn inp tail vss n1 W=7.5u L=0.35u pd=13.5u ad=22.5p ps=13.5u as=22.5p m=8 +Mn2 outp inn tail vss n1 W=7.5u L=0.35u pd=13.5u ad=22.5p ps=13.5u as=22.5p m=8 + +*bias +Mn0 tail bn vss vss n1 W=7.5u L=0.35u pd=13.5u ad=22.5p ps=13.5u as=22.5p m=4 +Mnn bn bn vss vss n1 W=7.5u L=0.35u pd=13.5u ad=22.5p ps=13.5u as=22.5p m=4 +Ib vss bn 1u +.ends + +Xdiff inp inn outp outn setcm vdd vss diffpair +Cload outp outn 100f + +Balun1#balun outp outn outcm outdiff +Balun1#balun inn inp incm indiff +Vprobediff outdiff indiff DC 0 +Vprobecm outcm incm DC 0 + +Vset setcm vss DC 1.1 +Vvdd vdd vss DC 3.3 +Vvss vss 0 DC 0 + diff --git a/src/Makefile.am b/src/Makefile.am index a8fb22e6a..7b9eb1bcf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -134,6 +134,10 @@ if NDEV_WANTED ngspice_LDADD += spicelib/devices/ndev/libndev.la endif +if LOOPANA_WANTED +ngspice_LDADD += spicelib/devices/balun/libbalun.la +endif + if NUMDEV_WANTED ngspice_LDADD += \ spicelib/devices/nbjt/libnbjt.la \ @@ -413,6 +417,10 @@ libspice_la_LIBADD += \ spicelib/devices/ndev/libndev.la endif +if LOOPANA_WANTED +libspice_la_LIBADD += spicelib/devices/balun/libbalun.la +endif + if NUMDEV_WANTED libspice_la_LIBADD += \ spicelib/devices/nbjt/libnbjt.la \ @@ -528,6 +536,10 @@ libngspice_la_LIBADD += \ spicelib/devices/ndev/libndev.la endif +if LOOPANA_WANTED +libngspice_la_LIBADD += spicelib/devices/balun/libbalun.la +endif + if NUMDEV_WANTED libngspice_la_LIBADD += \ spicelib/devices/nbjt/libnbjt.la \ diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 548456869..1369ddbb5 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -51,6 +51,10 @@ Author: 1985 Wayne A. Christopher /* gtri - end - 12/12/90 */ #endif +#ifdef WITH_LOOPANA +int INP2gentype(char* line); +#endif + /* SJB - Uncomment this line for debug tracing */ /*#define TRACE*/ @@ -4701,6 +4705,11 @@ static void inp_compat(struct card *card) if (*curr_line == '*') continue; + +#ifdef WITH_LOOPANA + if (INP2gentype(curr_line)) + continue; +#endif if (*curr_line == 'e') { /* Exxx n1 n2 VCVS n3 n4 gain --> Exxx n1 n2 n3 n4 gain @@ -5771,6 +5780,10 @@ static void inp_bsource_compat(struct card *card) else if (skip_control > 0) { continue; } +#ifdef WITH_LOOPANA + else if (INP2gentype(curr_line)) + continue; +#endif if (*curr_line == 'b') { /* remove white spaces of everything inside {}*/ @@ -8297,7 +8310,7 @@ static void inp_check_syntax(struct card *deck) } else { if (!check_ch) { - fprintf(stderr, "Warning: Unusal leading characters like '%c' or others out of '= [] ? () & %$§\"!:,'\n", *cut_line); + fprintf(stderr, "Warning: Unusal leading characters like '%c' or others out of '= [] ? () & %%$§\"!:,'\n", *cut_line); fprintf(stderr, " in netlist or included files, will be replaced with '*'\n"); check_ch = 1; /* just one warning */ } diff --git a/src/spicelib/devices/Makefile.am b/src/spicelib/devices/Makefile.am index 6f0989f26..29e2cd469 100644 --- a/src/spicelib/devices/Makefile.am +++ b/src/spicelib/devices/Makefile.am @@ -61,6 +61,11 @@ if NUMDEV_WANTED SUBDIRS += nbjt nbjt2 numd numd2 numos endif +if LOOPANA_WANTED +SUBDIRS += balun +endif + + DIST_SUBDIRS = \ asrc \ bjt \ @@ -117,7 +122,8 @@ DIST_SUBDIRS = \ nbjt2 \ numd \ numd2 \ - numos + numos \ + balun noinst_LTLIBRARIES = libdev.la diff --git a/src/spicelib/devices/balun/Makefile.am b/src/spicelib/devices/balun/Makefile.am new file mode 100644 index 000000000..b57aad859 --- /dev/null +++ b/src/spicelib/devices/balun/Makefile.am @@ -0,0 +1,22 @@ +## Process this file with automake to produce Makefile.in + +noinst_LTLIBRARIES = libbalun.la + +libbalun_la_SOURCES = \ + balun.c \ + balunask.c \ + balundefs.h \ + balunext.h \ + baluninit.c \ + baluninit.h \ + balunitf.h \ + balunload.c \ + balunpar.c \ + balunpzld.c \ + balunset.c + + + +AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include +AM_CFLAGS = $(STATIC) +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/balun/balun.c b/src/spicelib/devices/balun/balun.c new file mode 100644 index 000000000..33dfe3634 --- /dev/null +++ b/src/spicelib/devices/balun/balun.c @@ -0,0 +1,31 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice/ngspice.h" +#include "ngspice/ifsim.h" +#include "ngspice/devdefs.h" +#include "balundefs.h" +#include "ngspice/suffix.h" + +IFparm BALUNpTable[] = { /* parameters */ + OPU("pos_node", BALUN_POS_NODE, IF_INTEGER, "Positive node"), + OPU("neg_node", BALUN_NEG_NODE, IF_INTEGER, "Negative node"), + OPU("cm_node", BALUN_CM_NODE, IF_INTEGER, "Common-mode node"), + OPU("diff_node", BALUN_DIFF_NODE, IF_INTEGER, "Differential node"), + OP("p", BALUN_POWER, IF_REAL, "Power"), +}; + +char *BALUNnames[] = { + "Pos", + "Neg", + "CM", + "Diff" +}; + +int BALUNnSize = NUMELEMS(BALUNnames); +int BALUNpTSize = NUMELEMS(BALUNpTable); +int BALUNmPTSize = 0; +int BALUNiSize = sizeof(BALUNinstance); +int BALUNmSize = sizeof(BALUNmodel); diff --git a/src/spicelib/devices/balun/balunask.c b/src/spicelib/devices/balun/balunask.c new file mode 100644 index 000000000..3aea2b3d5 --- /dev/null +++ b/src/spicelib/devices/balun/balunask.c @@ -0,0 +1,63 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +/* + * This routine gives access to the internal device parameters + * of Voltage Controlled Voltage Source + */ + +#include "ngspice/ngspice.h" +#include "ngspice/cktdefs.h" +#include "ngspice/devdefs.h" +#include "ngspice/ifsim.h" +#include "balundefs.h" +#include "ngspice/sperror.h" +#include "ngspice/suffix.h" + +/* ARGSUSED */ +int +BALUNask(CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value, IFvalue *select) +{ + BALUNinstance *here = (BALUNinstance *)inst; + static char *msg = "Power not available for ac analysis"; + switch(which) { + case BALUN_POS_NODE: + value->iValue = here->BALUNposNode; + return (OK); + case BALUN_NEG_NODE: + value->iValue = here->BALUNnegNode; + return (OK); + case BALUN_DIFF_NODE: + value->iValue = here->BALUNdiffNode; + return (OK); + case BALUN_CM_NODE: + value->iValue = here->BALUNcmNode; + return (OK); + case BALUN_BRPOS: + value->iValue = here->BALUNbranchpos; + return (OK); + case BALUN_BRNEG: + value->iValue = here->BALUNbranchneg; + return (OK); + + case BALUN_POWER : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = TMALLOC(char, strlen(msg) + 1); + errRtn = "BALUNask"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + value->rValue = + *(ckt->CKTrhsOld + here->BALUNbranchpos) * + (*(ckt->CKTrhsOld + here->BALUNposNode)) + + *(ckt->CKTrhsOld + here->BALUNbranchneg) * + (*(ckt->CKTrhsOld + here->BALUNnegNode)); + } + return(OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/balun/balundefs.h b/src/spicelib/devices/balun/balundefs.h new file mode 100644 index 000000000..ca279e9e7 --- /dev/null +++ b/src/spicelib/devices/balun/balundefs.h @@ -0,0 +1,94 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef BALUN +#define BALUN + + +#include "ngspice/ifsim.h" +#include "ngspice/cktdefs.h" +#include "ngspice/gendefs.h" +#include "ngspice/complex.h" + + /* + * structures to describe Voltage Controlled Voltage Sources + */ + +/* information to describe a single instance */ + +typedef struct sBALUNinstance { + + struct GENinstance gen; + +#define BALUNmodPtr(inst) ((struct sBALUNmodel *)((inst)->gen.GENmodPtr)) +#define BALUNnextInstance(inst) ((struct sBALUNinstance *)((inst)->gen.GENnextInstance)) +#define BALUNname gen.GENname +#define BALUNstates gen.GENstate + + const int BALUNposNode; /* number of positive node of source */ + const int BALUNnegNode; /* number of negative node of source */ + const int BALUNcmNode; /* cm node */ + const int BALUNdiffNode; /* diff node */ + + int BALUNbranchpos; /* branch for ipos */ + int BALUNbranchneg; /* branch for ineg */ + + double *BALUNposIbrposPtr; + double *BALUNnegIbrnegPtr; + double *BALUNcmIbrposPtr; + double *BALUNcmIbrnegPtr; + double *BALUNdiffIbrposPtr; + double *BALUNdiffIbrnegPtr; + + double *BALUNibrposDiffPtr; + double *BALUNibrposPosPtr; + double *BALUNibrposNegPtr; + + double *BALUNibrnegCmPtr; + double *BALUNibrnegPosPtr; + double *BALUNibrnegNegPtr; + + + int BALUNsenParmNo; /* parameter # for sensitivity use; + set equal to 0 if not a design parameter*/ + +} BALUNinstance ; + +/* per model data */ + +typedef struct sBALUNmodel { /* model structure for a source */ + + struct GENmodel gen; + +#define BALUNmodType gen.GENmodType +#define BALUNnextModel(inst) ((struct sBALUNmodel *)((inst)->gen.GENnextModel)) +#define BALUNinstances(inst) ((BALUNinstance *)((inst)->gen.GENinstances)) +#define BALUNmodName gen.GENmodName + +} BALUNmodel; + +/* device parameters */ +enum { + BALUN_POS_NODE = 1, + BALUN_NEG_NODE, + BALUN_DIFF_NODE, + BALUN_CM_NODE, + BALUN_BRPOS, + BALUN_BRNEG, + BALUN_POWER, +}; + +/* model parameters */ + +/* device questions */ +enum { + BALUN_QUEST_NONE = 201, +}; + +/* model questions */ + +#include "balunext.h" + +#endif /*BALUN*/ diff --git a/src/spicelib/devices/balun/balunext.h b/src/spicelib/devices/balun/balunext.h new file mode 100644 index 000000000..2d6d857f2 --- /dev/null +++ b/src/spicelib/devices/balun/balunext.h @@ -0,0 +1,12 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +extern int BALUNask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int BALUNload(GENmodel*,CKTcircuit*); +extern int BALUNparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int BALUNpzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int BALUNsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int BALUNunsetup(GENmodel*,CKTcircuit*); + diff --git a/src/spicelib/devices/balun/baluninit.c b/src/spicelib/devices/balun/baluninit.c new file mode 100644 index 000000000..560182e3e --- /dev/null +++ b/src/spicelib/devices/balun/baluninit.c @@ -0,0 +1,76 @@ +#include "ngspice/config.h" + +#include "ngspice/devdefs.h" + +#include "balunitf.h" +#include "balunext.h" +#include "baluninit.h" + + +SPICEdev BALUNinfo = { + .DEVpublic = { + .name = "BALUN", + .description = "Ideal balun", + .terms = &BALUNnSize, + .numNames = &BALUNnSize, + .termNames = BALUNnames, + .numInstanceParms = &BALUNpTSize, + .instanceParms = BALUNpTable, + .numModelParms = NULL, + .modelParms = NULL, + .flags = DEV_DEFAULT, + +#ifdef XSPICE + .cm_func = NULL, + .num_conn = 0, + .conn = NULL, + .num_param = 0, + .param = NULL, + .num_inst_var = 0, + .inst_var = NULL, +#endif + }, + + .DEVparam = BALUNparam, + .DEVmodParam = NULL, + .DEVload = BALUNload, + .DEVsetup = BALUNsetup, + .DEVunsetup = BALUNunsetup, + .DEVpzSetup = BALUNsetup, + .DEVtemperature = NULL, + .DEVtrunc = NULL, + .DEVfindBranch = NULL, + .DEVacLoad = BALUNload, + .DEVaccept = NULL, + .DEVdestroy = NULL, + .DEVmodDelete = NULL, + .DEVdelete = NULL, + .DEVsetic = NULL, + .DEVask = BALUNask, + .DEVmodAsk = NULL, + .DEVpzLoad = BALUNpzLoad, + .DEVconvTest = NULL, + .DEVsenSetup = NULL, + .DEVsenLoad = NULL, + .DEVsenUpdate = NULL, + .DEVsenAcLoad = NULL, + .DEVsenPrint = NULL, + .DEVsenTrunc = NULL, + .DEVdisto = NULL, + .DEVnoise = NULL, + .DEVsoaCheck = NULL, + .DEVinstSize = &BALUNiSize, + .DEVmodSize = &BALUNmSize, + +#ifdef CIDER + .DEVdump = NULL, + .DEVacct = NULL, +#endif +}; + + +SPICEdev * +get_balun_info(void) +{ + return &BALUNinfo; +} diff --git a/src/spicelib/devices/balun/baluninit.h b/src/spicelib/devices/balun/baluninit.h new file mode 100644 index 000000000..5118c2ddc --- /dev/null +++ b/src/spicelib/devices/balun/baluninit.h @@ -0,0 +1,11 @@ +#ifndef _VCVSINIT_H +#define _VCVSINIT_H + +extern IFparm BALUNpTable[ ]; +extern char *BALUNnames[ ]; +extern int BALUNpTSize; +extern int BALUNnSize; +extern int BALUNiSize; +extern int BALUNmSize; + +#endif diff --git a/src/spicelib/devices/balun/balunitf.h b/src/spicelib/devices/balun/balunitf.h new file mode 100644 index 000000000..d9dbe16b3 --- /dev/null +++ b/src/spicelib/devices/balun/balunitf.h @@ -0,0 +1,9 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifndef DEV_BALUN +#define DEV_BALUN + +SPICEdev *get_balun_info(void); + +#endif diff --git a/src/spicelib/devices/balun/balunload.c b/src/spicelib/devices/balun/balunload.c new file mode 100644 index 000000000..f2085a88c --- /dev/null +++ b/src/spicelib/devices/balun/balunload.c @@ -0,0 +1,57 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice/ngspice.h" +#include "ngspice/cktdefs.h" +#include "balundefs.h" +#include "ngspice/sperror.h" +#include "ngspice/suffix.h" + + +/*ARGSUSED*/ +int +BALUNload(GENmodel *inModel, CKTcircuit *ckt) + /* actually load the current voltage value into the + * sparse matrix previously provided + */ +{ + BALUNmodel *model = (BALUNmodel *)inModel; + BALUNinstance *here; + + NG_IGNORE(ckt); + + /* loop through all the voltage source models */ + for( ; model != NULL; model = BALUNnextModel(model)) { + + /* loop through all the instances of the model */ + for (here = BALUNinstances(model); here != NULL ; + here=BALUNnextInstance(here)) { + + /* currents to and from nodes */ + *(here->BALUNposIbrposPtr) -= 1.0; + *(here->BALUNnegIbrnegPtr) -= 1.0; + /* icm = ipos + ineg */ + *(here->BALUNcmIbrposPtr) += 1.0; + *(here->BALUNcmIbrnegPtr) += 1.0; + /* idiff = (ipos - ineg)/2 */ + *(here->BALUNdiffIbrposPtr) += 0.5; + *(here->BALUNdiffIbrnegPtr) -= 0.5; + + /* vd = vp - vn */ + *(here->BALUNibrposDiffPtr) += 1.0 ; + *(here->BALUNibrposPosPtr) -= 1.0 ; + *(here->BALUNibrposNegPtr) += 1.0 ; + + /* vc = (vp + vn)/2 */ + *(here->BALUNibrnegCmPtr) += 1.0 ; + *(here->BALUNibrnegPosPtr) -= 0.5 ; + *(here->BALUNibrnegNegPtr) -= 0.5 ; + + } + } + return(OK); +} diff --git a/src/spicelib/devices/balun/balunpar.c b/src/spicelib/devices/balun/balunpar.c new file mode 100644 index 000000000..7e1ae125c --- /dev/null +++ b/src/spicelib/devices/balun/balunpar.c @@ -0,0 +1,28 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice/ngspice.h" +#include "ngspice/ifsim.h" +#include "balundefs.h" +#include "ngspice/sperror.h" +#include "ngspice/suffix.h" + + +/* ARGSUSED */ +int +BALUNparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select) +{ + BALUNinstance *here = (BALUNinstance *)inst; + + NG_IGNORE(select); + + switch(param) { + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/balun/balunpzld.c b/src/spicelib/devices/balun/balunpzld.c new file mode 100644 index 000000000..e106679b1 --- /dev/null +++ b/src/spicelib/devices/balun/balunpzld.c @@ -0,0 +1,58 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice/ngspice.h" +#include "ngspice/cktdefs.h" +#include "ngspice/complex.h" +#include "ngspice/sperror.h" +#include "balundefs.h" +#include "ngspice/suffix.h" + + +/*ARGSUSED*/ +int +BALUNpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s) + /* actually load the current voltage value into the + * sparse matrix previously provided + */ +{ + BALUNmodel *model = (BALUNmodel *)inModel; + BALUNinstance *here; + + NG_IGNORE(s); + NG_IGNORE(ckt); + + /* loop through all the voltage source models */ + for( ; model != NULL; model = BALUNnextModel(model)) { + + /* loop through all the instances of the model */ + for (here = BALUNinstances(model); here != NULL ; + here=BALUNnextInstance(here)) { + + /* currents to and from nodes */ + *(here->BALUNposIbrposPtr) -= 1.0; + *(here->BALUNnegIbrnegPtr) -= 1.0; + /* icm = ipos + ineg */ + *(here->BALUNcmIbrposPtr) += 1.0; + *(here->BALUNcmIbrnegPtr) += 1.0; + /* idiff = (ipos - ineg)/2 */ + *(here->BALUNdiffIbrposPtr) += 0.5; + *(here->BALUNdiffIbrnegPtr) -= 0.5; + + /* vd = vp - vn */ + *(here->BALUNibrposDiffPtr) += 1.0 ; + *(here->BALUNibrposPosPtr) -= 1.0 ; + *(here->BALUNibrposNegPtr) += 1.0 ; + + /* vc = (vp + vn)/2 */ + *(here->BALUNibrnegCmPtr) += 1.0 ; + *(here->BALUNibrnegPosPtr) -= 0.5 ; + *(here->BALUNibrnegNegPtr) -= 0.5 ; + } + } + return(OK); +} diff --git a/src/spicelib/devices/balun/balunset.c b/src/spicelib/devices/balun/balunset.c new file mode 100644 index 000000000..58d3772a6 --- /dev/null +++ b/src/spicelib/devices/balun/balunset.c @@ -0,0 +1,100 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice/ngspice.h" +#include "ngspice/smpdefs.h" +#include "ngspice/cktdefs.h" +#include "balundefs.h" +#include "ngspice/sperror.h" +#include "ngspice/suffix.h" + +/*ARGSUSED*/ +int +BALUNsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) +{ + BALUNmodel *model = (BALUNmodel *)inModel; + BALUNinstance *here; + int error; + CKTnode *tmp; + + NG_IGNORE(states); + + /* loop through all the voltage source models */ + for( ; model != NULL; model = BALUNnextModel(model)) { + + /* loop through all the instances of the model */ + for (here = BALUNinstances(model); here != NULL ; + here=BALUNnextInstance(here)) { + + if(here->BALUNposNode == here->BALUNnegNode) { + SPfrontEnd->IFerrorf (ERR_FATAL, + "instance %s is a shorted BALUN", here->BALUNname); + return(E_UNSUPP); + } + + if(here->BALUNcmNode == here->BALUNdiffNode) { + SPfrontEnd->IFerrorf (ERR_FATAL, + "instance %s is a shorted BALUN", here->BALUNname); + return(E_UNSUPP); + } + + if(here->BALUNbranchpos == 0) { + error = CKTmkCur(ckt,&tmp,here->BALUNname,"branchpos"); + if(error) return(error); + here->BALUNbranchpos = tmp->number; + } + if(here->BALUNbranchneg == 0) { + error = CKTmkCur(ckt,&tmp,here->BALUNname,"branchneg"); + if(error) return(error); + here->BALUNbranchneg = tmp->number; + } + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ + return(E_NOMEM);\ +} } while(0) + + TSTALLOC(BALUNposIbrposPtr, BALUNposNode, BALUNbranchpos); + TSTALLOC(BALUNnegIbrnegPtr, BALUNnegNode, BALUNbranchneg); + TSTALLOC(BALUNcmIbrposPtr, BALUNcmNode, BALUNbranchpos); + TSTALLOC(BALUNcmIbrnegPtr, BALUNcmNode, BALUNbranchneg); + TSTALLOC(BALUNdiffIbrposPtr, BALUNdiffNode, BALUNbranchpos); + TSTALLOC(BALUNdiffIbrnegPtr, BALUNdiffNode, BALUNbranchneg); + + TSTALLOC(BALUNibrposDiffPtr, BALUNbranchpos, BALUNdiffNode); + TSTALLOC(BALUNibrposPosPtr, BALUNbranchpos, BALUNposNode); + TSTALLOC(BALUNibrposNegPtr, BALUNbranchpos, BALUNnegNode); + + TSTALLOC(BALUNibrnegCmPtr, BALUNbranchneg, BALUNcmNode); + TSTALLOC(BALUNibrnegPosPtr, BALUNbranchneg, BALUNposNode); + TSTALLOC(BALUNibrnegNegPtr, BALUNbranchneg, BALUNnegNode); + } + } + return(OK); +} + +int +BALUNunsetup(GENmodel *inModel, CKTcircuit *ckt) +{ + BALUNmodel *model; + BALUNinstance *here; + + for (model = (BALUNmodel *)inModel; model != NULL; + model = BALUNnextModel(model)) + { + for (here = BALUNinstances(model); here != NULL; + here=BALUNnextInstance(here)) + { + if (here->BALUNbranchpos > 0) + CKTdltNNum(ckt, here->BALUNbranchpos); + here->BALUNbranchpos = 0; + if (here->BALUNbranchneg > 0) + CKTdltNNum(ckt, here->BALUNbranchneg); + here->BALUNbranchneg = 0; + } + } + return OK; +} diff --git a/src/spicelib/devices/dev.c b/src/spicelib/devices/dev.c index 9a5c4d2c1..81080ef47 100644 --- a/src/spicelib/devices/dev.c +++ b/src/spicelib/devices/dev.c @@ -142,6 +142,9 @@ extern struct coreInfo_t coreInfo; /* cmexport.c */ #ifdef NDEV #include "ndev/ndevitf.h" #endif +#ifdef WITH_LOOPANA +#include "balun/balunitf.h" +#endif static SPICEdev *(*static_devices[])(void) = { /* URC device MUST precede both resistors and capacitors */ @@ -217,6 +220,10 @@ static SPICEdev *(*static_devices[])(void) = { get_ndev_info, #endif +#ifdef WITH_LOOPANA + get_balun_info, +#endif + }; static int DEVNUM = NUMELEMS(static_devices); diff --git a/src/spicelib/parser/Makefile.am b/src/spicelib/parser/Makefile.am index 3cc7e7cce..ab7cb3d17 100644 --- a/src/spicelib/parser/Makefile.am +++ b/src/spicelib/parser/Makefile.am @@ -69,6 +69,10 @@ libinp_la_SOURCES = \ sperror.c \ inpxx.h +if LOOPANA_WANTED +libinp_la_SOURCES += inp2gen.c +endif + AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include -I$(top_srcdir)/src/frontend AM_CFLAGS = $(STATIC) AM_YFLAGS = -d diff --git a/src/spicelib/parser/inp2gen.c b/src/spicelib/parser/inp2gen.c new file mode 100644 index 000000000..2f6e71cf5 --- /dev/null +++ b/src/spicelib/parser/inp2gen.c @@ -0,0 +1,155 @@ +/******************************************************************************* + * Copyright 2020 Florian Ballenegger, Anamosic Ballenegger Design + ******************************************************************************* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +#include "ngspice/ngspice.h" +#include +#include "ngspice/ifsim.h" +#include "ngspice/inpdefs.h" +#include "ngspice/inpmacs.h" +#include "ngspice/fteext.h" +#include "inpxx.h" + +#include "ngspice/cktdefs.h" + + +int INP2gentype(char* line) +{ + int i; + char c; + for(i=0;c=line[i];i++) + if(!isblank(c)) + break; + if(line[i]=='.') return 0; + if(line[i]=='*') return 0; + if(line[i]=='$') return 0; + + for(;c=line[i];i++) + { + if(isblank(c)) + return 0; + if(c=='#') + return i+1; + } + return 0; +} + +int INP2GEN(CKTcircuit *ckt, INPtables * tab, struct card *current) +{ + +/* # node1 node2 ... noden param=val */ + + int type; /* the type the model says it is */ + int idx, len; + char *line; /* the part of the current line left to parse */ + char *name; /* a name */ + CKTnode *node; /* a node pointer */ + int error; /* error code temporary */ + GENinstance *fast; /* pointer to the actual instance */ + IFvalue ptemp; /* a value structure to package resistance into */ + IFuid uid; /* uid of default model to be created */ + GENmodel* genmod; + + line = current->line; + idx=INP2gentype(line); + if(!idx) + return 0; /* not a new generic instance format */ + + /* calc length of device type string */ + for(len=0;line[idx+len];len++) + if(isblank(line[idx+len])) + break; + if(len==0) return 0; + + /* look if find this device */ + for (type = 0; type < ft_sim->numDevices; type++) { + if(ft_sim->devices[type]) + if(strlen(ft_sim->devices[type]->name)==len) + if(strncasecmp(&line[idx], ft_sim->devices[type]->name, len)==0) + break; + } + if(type==ft_sim->numDevices) { /* not found */ + LITERR("Device type not supported by this binary\n"); + return 0; + } + + if (1) { + /* create default model */ + name = dup_string(ft_sim->devices[type]->name,len); + IFnewUid(ckt, &uid, NULL, name, UID_MODEL, NULL); + genmod = ft_sim->findModel(ckt, uid); + if(!genmod) + IFC(newModel, (ckt, type, &genmod, uid)); + } + name = dup_string(line, idx-1); + IFC(newInstance, (ckt, genmod, &fast, name)); + if(0) printf("Instance name: %s\n", name); + + line = &line[idx+len]; + + /* parse node connections and bind nodes */ + for(idx=0;idx<*(ft_sim->devices[type]->terms);idx++) + { + INPgetNetTok(&line, &name, 1); + INPtermInsert(ckt, &name, tab, &node); + IFC(bindNode, (ckt, fast, idx+1, node)); + if(0) printf("bind term %d to %s\n", idx, node->name); + } + + /* parse parameters and assign parameters */ + while(*line) + { + INPgetTok(&line, &name, 0); + if(*line!='=') { + printf("Expect param=val format for %s, got %c\n", name, *line); + LITERR("Expect param=val format\n"); + return(0); + } + line++; /* skip '=' */ + for(idx=0;idx<*(ft_sim->devices[type]->numInstanceParms);idx++) + if(strcmp(name, ft_sim->devices[type]->instanceParms[idx].keyword)==0) + break; + tfree(name); /* don't need it anymore, we still know the keyword */ + if(idx<*(ft_sim->devices[type]->numInstanceParms)) + { /* found */ + int dataType; + IFvalue *parm; + dataType = ft_sim->devices[type]->instanceParms[idx].dataType; + parm = INPgetValue(ckt, &line, dataType, tab); + GCA(INPpName, (ft_sim->devices[type]->instanceParms[idx].keyword, parm, ckt, type, fast)); + if(0) printf("Assign %s\n", ft_sim->devices[type]->instanceParms[idx].keyword); + } + else + { + LITERR("Unrecognized parameter\n"); + return(0); + } + + } +} diff --git a/src/spicelib/parser/inppas2.c b/src/spicelib/parser/inppas2.c index c53c85922..452ff9e3d 100644 --- a/src/spicelib/parser/inppas2.c +++ b/src/spicelib/parser/inppas2.c @@ -16,6 +16,22 @@ Author: 1985 Thomas L. Quarles /* gtri - end - wbk - 11/9/90 */ #endif +#ifdef WITH_LOOPANA +/* detect A# */ +int INPlookahead(char* line) +{ + int i; + char c; + for(i=1;c=line[i];i++) + { + if(isblank(c)) + return 0; + if(c=='#') + return i+1; + } + return 0; +} +#endif /* uncomment to trace in this file */ /*#define TRACE*/ @@ -90,7 +106,11 @@ void INPpas2(CKTcircuit *ckt, struct card *data, INPtables * tab, TSKtask *task) c = *(current->line); if(islower_c(c)) c = toupper_c(c); - +#ifdef WITH_LOOPANA + if(INP2GEN(ckt, tab, current)) + ; /* well done */ + else +#endif switch (c) { case ' ': @@ -98,11 +118,8 @@ void INPpas2(CKTcircuit *ckt, struct card *data, INPtables * tab, TSKtask *task) case '\t': /* blank line (tab leading) */ break; - #ifdef XSPICE - /* gtri - add - wbk - 10/23/90 - add case for 'A' devices */ - - case 'A': /* Aname */ + case 'A': MIF_INP2A(ckt, tab, current); ckt->CKTadevFlag = 1; /* an 'A' device is requested */ break; diff --git a/src/spicelib/parser/inpxx.h b/src/spicelib/parser/inpxx.h index afbb9d162..ac7976691 100644 --- a/src/spicelib/parser/inpxx.h +++ b/src/spicelib/parser/inpxx.h @@ -33,6 +33,9 @@ void INP2W(CKTcircuit *ckt, INPtables *tab, struct card *current); void INP2Y(CKTcircuit *ckt, INPtables *tab, struct card *current); void INP2Z(CKTcircuit *ckt, INPtables *tab, struct card *current); +#ifdef WITH_LOOPANA +int INP2GEN(CKTcircuit *ckt, INPtables * tab, struct card *current); +#endif /* ptfuncs.c */