From 9702557f8116ded55b19b3a176a5a396621212ad Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 16 Oct 2023 17:53:58 +0200 Subject: [PATCH 1/5] Evaluate function gauss() in B sources. This is required when in .model files the tokens 'temper' and gauss() coexist, because then the B Source function parser is applied. --- src/spicelib/parser/inpptree.c | 37 ++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/spicelib/parser/inpptree.c b/src/spicelib/parser/inpptree.c index 063bbd5f9..22d298489 100644 --- a/src/spicelib/parser/inpptree.c +++ b/src/spicelib/parser/inpptree.c @@ -12,6 +12,7 @@ Author: 1987 Wayne A. Christopher, U. C. Berkeley CAD Group #include "ngspice/iferrmsg.h" #include "ngspice/inpdefs.h" #include "ngspice/inpptree.h" +#include "ngspice/randnumb.h" #include "inpxx.h" #include "inpptree-parser.h" @@ -36,6 +37,8 @@ static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum); static void free_tree(INPparseNode *); static void printTree(INPparseNode *); +static double gauss(double nominal_val, double rel_variation, double sigma); + /* * LAW for INPparseNode* generator and consumer functions: @@ -1145,6 +1148,30 @@ INPparseNode *PT_mkfnode(const char *fname, INPparseNode * arg) return mkfirst(NULL, arg); } + /* This is used only to evaluate fcn gauss(a1, a2, a3) in .model files, where + temper is used also. a1, a2, and a3 have to be constant double values. */ + if (!strcmp("gauss", buf)) { + if (arg->type == PT_COMMA && arg->left->type == PT_COMMA) { + + INPparseNode* arg1 = arg->left->left; + INPparseNode* arg2 = arg->left->right; + INPparseNode* arg3 = arg->right; + double a1 = arg1->constant; + double a2 = arg2->constant; + double a3 = arg3->constant; + + if (a2 == 0.0 || a3 == 0.0) { + fprintf(stderr, "Error: bogus gauss form\n"); + return mkfirst(NULL, arg); //return mkcon(a1); + } + + return mkcon(gauss(a1, a2, a3)); + } + + fprintf(stderr, "Error: bogus gauss form\n"); + return mkfirst(NULL, arg); + } + for (i = 0; i < NUM_FUNCS; i++) if (!strcmp(funcs[i].name, buf)) break; @@ -1626,6 +1653,16 @@ void free_tree(INPparseNode *pt) txfree(pt); } +static double +gauss(double nominal_val, double rel_variation, double sigma) +{ + double stdvar; + if (rel_variation <= 0 || sigma <= 0) + return nominal_val; + stdvar = nominal_val * rel_variation / sigma; + return (nominal_val + stdvar * gauss1()); +} + /* Debugging stuff. */ From 8ef0aece58965b6c3dd551c20dc14f61b9538f0d Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 18 Oct 2023 14:34:16 +0200 Subject: [PATCH 2/5] During setup of the models thre have been search scans in the linked model list modtab. The time used here grows approx. quadratically with the number of models. If the numbers get large, e.g. with the IHP Open PDK, setup time make simulation impractical. Therefore the linked list modtab has been enhanced by a hash table modtabhash, which allows linear search time and makes simulation of a 200k transistor circuit with IHP PDK possible. Already the setup time for 15k transistor circuits has been reduced. --- src/frontend/runcoms.c | 3 +++ src/frontend/runcoms2.c | 5 +++- src/frontend/spiceif.c | 4 +++ src/include/ngspice/ftedefs.h | 2 ++ src/spicelib/parser/inpgmod.c | 30 ++++++++++++++++++++++- src/spicelib/parser/inpkmods.c | 8 ++++++ src/spicelib/parser/inpmkmod.c | 45 +++++++++++++++++++++------------- 7 files changed, 78 insertions(+), 19 deletions(-) diff --git a/src/frontend/runcoms.c b/src/frontend/runcoms.c index 9d52e192e..613be5d9e 100644 --- a/src/frontend/runcoms.c +++ b/src/frontend/runcoms.c @@ -14,6 +14,7 @@ Modified: 2000 AlansFixes #include "ngspice/ftedev.h" #include "ngspice/ftedebug.h" #include "ngspice/dvec.h" +#include "ngspice/hash.h" #include "numparam/numpaif.h" @@ -33,6 +34,7 @@ Modified: 2000 AlansFixes static int dosim(char *what, wordlist *wl); extern struct INPmodel *modtab; +extern NGHASHPTR modtabhash; extern struct dbcomm *dbs; extern void NIresetwarnmsg(void); @@ -107,6 +109,7 @@ com_scirc(wordlist *wl) ft_curckt = p; /* get the model table for the current circuit, store it in the global variable modtab */ modtab = ft_curckt->ci_modtab; + modtabhash = ft_curckt->ci_modtabhash; /* get the database for save, iplot, stop */ dbs = ft_curckt->ci_dbs; /* set the numparam dicos structure for use with measure */ diff --git a/src/frontend/runcoms2.c b/src/frontend/runcoms2.c index ac6c9dead..baf43ee79 100644 --- a/src/frontend/runcoms2.c +++ b/src/frontend/runcoms2.c @@ -14,6 +14,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group #include "ngspice/ftedebug.h" #include "ngspice/dvec.h" #include "ngspice/trandefs.h" +#include "ngspice/hash.h" #include "circuits.h" #include "runcoms2.h" @@ -33,6 +34,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group extern void line_free_x(struct card *deck, bool recurse); extern INPmodel *modtab; +extern NGHASHPTR modtabhash; #ifdef SHARED_MODULE extern void exec_controls(wordlist *newcontrols); @@ -273,10 +275,11 @@ com_remcirc(wordlist *wl) prev = p; } - /* make first entry in ft_circuits the actual circuit (or NULL) */ + /* make first entry in ft_circuits the current circuit (or NULL) */ ft_curckt = ft_circuits; if (ft_curckt) { modtab = ft_curckt->ci_modtab; + modtabhash = ft_curckt->ci_modtabhash; dbs = ft_curckt->ci_dbs; nupa_set_dicoslist(ft_curckt->ci_dicos); } diff --git a/src/frontend/spiceif.c b/src/frontend/spiceif.c index 724e4f879..c135b37db 100644 --- a/src/frontend/spiceif.c +++ b/src/frontend/spiceif.c @@ -54,6 +54,7 @@ CDHW*/ #include "ngspice/inpdefs.h" #include "ngspice/iferrmsg.h" #include "ngspice/ifsim.h" +#include "ngspice/hash.h" #include "circuits.h" #include "spiceif.h" @@ -75,6 +76,7 @@ CDHW*/ #endif extern INPmodel *modtab; +extern NGHASHPTR modtabhash; extern bool ft_batchmode; static struct variable *parmtovar(IFvalue *pv, IFparm *opt); @@ -160,9 +162,11 @@ if_inpdeck(struct card *deck, INPtables **tab) /* Parse the .model lines. Enter the model into the global model table modtab. */ modtab = NULL; + modtabhash = NULL; INPpas1(ckt, deck->nextcard, *tab); /* store the new model table in the current circuit */ ft_curckt->ci_modtab = modtab; + ft_curckt->ci_modtabhash = modtabhash; /* Scan through the instance lines and parse the circuit. */ INPpas2(ckt, deck->nextcard, *tab, ft_curckt->ci_defTask); diff --git a/src/include/ngspice/ftedefs.h b/src/include/ngspice/ftedefs.h index 471f1c9b2..639707250 100644 --- a/src/include/ngspice/ftedefs.h +++ b/src/include/ngspice/ftedefs.h @@ -17,6 +17,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group #include "ngspice/fteparse.h" #include "ngspice/fteinp.h" #include "ngspice/fteoptdefs.h" +#include "ngspice/hash.h" struct ccom; @@ -34,6 +35,7 @@ struct circ { CKTcircuit *ci_ckt; /* The CKTcircuit structure. */ INPtables *ci_symtab; /* The INP symbol table. */ INPmodel *ci_modtab; /* The INP model table. */ + NGHASHPTR ci_modtabhash; /* The INP model hash table. */ struct dbcomm *ci_dbs; /* The database storing save, iplot, stop data */ struct card *ci_deck; /* The input deck. */ struct card *ci_origdeck; /* The input deck, before subckt expansion. */ diff --git a/src/spicelib/parser/inpgmod.c b/src/spicelib/parser/inpgmod.c index 6450abf6d..44dc93989 100644 --- a/src/spicelib/parser/inpgmod.c +++ b/src/spicelib/parser/inpgmod.c @@ -39,6 +39,7 @@ static int INPfindParm(char *name, IFparm *table, int numParms); #endif extern INPmodel *modtab; +extern NGHASHPTR modtabhash; static IFparm * @@ -342,6 +343,33 @@ INPgetMod(CKTcircuit *ckt, char *name, INPmodel **model, INPtables *tab) printf("In INPgetMod, examining model %s ...\n", name); #endif + modtmp = nghash_find(modtabhash, name); + if (modtmp) { + /* found the model in question - now instantiate if necessary */ + /* and return an appropriate pointer to it */ + +/* if illegal device type */ + if (modtmp->INPmodType < 0) { +#ifdef TRACE + printf("In INPgetMod, illegal device type for model %s ...\n", name); +#endif + * model = NULL; + return tprintf("Unknown device type for model %s\n", name); + } + + /* create unless model is already defined */ + if (!modtmp->INPmodfast) { + int error = create_model(ckt, modtmp, tab); + if (error) { + *model = NULL; + return INPerror(error); + } + } + + *model = modtmp; + return NULL; + } +#if (0) for (modtmp = modtab; modtmp; modtmp = modtmp->INPnextModel) { #ifdef TRACE @@ -374,7 +402,7 @@ INPgetMod(CKTcircuit *ckt, char *name, INPmodel **model, INPtables *tab) return NULL; } } - +#endif #ifdef TRACE printf("In INPgetMod, didn't find model for %s, using default ...\n", name); #endif diff --git a/src/spicelib/parser/inpkmods.c b/src/spicelib/parser/inpkmods.c index 8e356a840..40c68be51 100644 --- a/src/spicelib/parser/inpkmods.c +++ b/src/spicelib/parser/inpkmods.c @@ -13,6 +13,7 @@ Author: 1985 Thomas L. Quarles extern INPmodel *modtab; +extern NGHASHPTR modtabhash; void INPkillMods(void) { @@ -28,4 +29,11 @@ void INPkillMods(void) FREE(prev); modtab = NULL; ft_curckt->ci_modtab = NULL; + /* free the hash table */ + if (modtabhash) { + nghash_free(modtabhash, NULL, NULL); + modtabhash = NULL; + } + ft_curckt->ci_modtabhash = NULL; + } diff --git a/src/spicelib/parser/inpmkmod.c b/src/spicelib/parser/inpmkmod.c index 456c4f5e4..055d7a66b 100644 --- a/src/spicelib/parser/inpmkmod.c +++ b/src/spicelib/parser/inpmkmod.c @@ -7,10 +7,14 @@ Author: 1985 Thomas L. Quarles #include #include "ngspice/inpdefs.h" #include "ngspice/iferrmsg.h" +#include "ngspice/hash.h" #include "inpxx.h" /* global input model table. */ INPmodel *modtab = NULL; +/* Global input model hash table. + The modelname is the key, the return value is the pointer to the model. */ +NGHASHPTR modtabhash = NULL; /*-------------------------------------------------------------- * This fcn takes the model name and looks to see if it is already @@ -21,33 +25,40 @@ INPmodel *modtab = NULL; int INPmakeMod(char *token, int type, struct card *line) { - register INPmodel **i; - - /* First cycle through model table and see if model name - already exists in there. If it does, just return. */ - for (i = &modtab; *i != NULL; i = &((*i)->INPnextModel)) { - if (strcmp((*i)->INPmodName, token) == 0) { - return (OK); - } + register INPmodel *newm; + /* Initialze the hash table. The default key type is string. + The default comparison function is strcmp.*/ + if (!modtabhash) { + modtabhash = nghash_init(NGHASH_MIN_SIZE); + nghash_unique(modtabhash, TRUE); } + /* If the model is already there, just return. */ + else if (nghash_find(modtabhash, token)) + return (OK); - /* Model name was not already in model table. Therefore stick - it in the model table. Then return. */ + /* Model name was not already in model table. Therefore stick + it in the front of the model table, also into the model hash table. + Then return. */ #ifdef TRACE /* debug statement */ printf("In INPmakeMod, about to insert new model name = %s . . .\n", token); #endif - *i = TMALLOC(INPmodel, 1); - if (*i == NULL) + newm = TMALLOC(INPmodel, 1); + if (newm == NULL) return (E_NOMEM); - (*i)->INPmodName = token; /* model name */ - (*i)->INPmodType = type; /* model type */ - (*i)->INPnextModel = NULL; /* pointer to next model (end of list) */ - (*i)->INPmodLine = line; /* model line */ - (*i)->INPmodfast = NULL; + newm->INPmodName = token; /* model name */ + newm->INPmodType = type; /* model type */ + newm->INPnextModel = modtab; /* pointer to second model */ + newm->INPmodLine = line; /* model line */ + newm->INPmodfast = NULL; + + nghash_insert(modtabhash, token, newm); + + modtab = newm; + return (OK); } From 39443fafddd3bb0790606ef1f97241eff11b47c3 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 18 Oct 2023 14:36:08 +0200 Subject: [PATCH 3/5] Removing unused models takes much more time than keeping them for large circuits. Probably a hash table may help here (t.b.d.). --- src/frontend/inp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/inp.c b/src/frontend/inp.c index b164bc1fe..aba8450d1 100644 --- a/src/frontend/inp.c +++ b/src/frontend/inp.c @@ -960,8 +960,8 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) So again try to remove unused MOS models. All binning models are still here when w or l have been determined by an expression. */ - if (newcompat.hs || newcompat.spe) - rem_unused_mos_models(deck->nextcard); +// if (newcompat.hs || newcompat.spe) +// rem_unused_mos_models(deck->nextcard); /* now load deck into ft_curckt -- the current circuit. */ if(inp_dodeck(deck, tt, wl_first, FALSE, options, filename) != 0) From f26dda86167b13c3225754e97954f4cd7236a7b9 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 18 Oct 2023 17:44:56 +0200 Subject: [PATCH 4/5] Formatting --- src/spicelib/parser/inpkmods.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/spicelib/parser/inpkmods.c b/src/spicelib/parser/inpkmods.c index 40c68be51..1c0f75be3 100644 --- a/src/spicelib/parser/inpkmods.c +++ b/src/spicelib/parser/inpkmods.c @@ -1,8 +1,8 @@ /********** Copyright 1990 Regents of the University of California. All rights reserved. -Author: 1985 Thomas L. Quarles +Author: 1985 Thomas L. Quarles, 2023 Holger Vogt **********/ -/* +/* Deletes the model table modtab and the hash table modtabhash. */ #include "ngspice/ngspice.h" @@ -11,22 +11,21 @@ Author: 1985 Thomas L. Quarles #include "ngspice/ftedefs.h" #include "inpxx.h" - -extern INPmodel *modtab; +extern INPmodel* modtab; extern NGHASHPTR modtabhash; void INPkillMods(void) { - INPmodel *modtmp; - INPmodel *prev = NULL; + INPmodel* modtmp; + INPmodel* prev = NULL; for (modtmp = modtab; modtmp != NULL; modtmp = modtmp->INPnextModel) { - if (prev) - FREE(prev); - prev = modtmp; + if (prev) + FREE(prev); + prev = modtmp; } if (prev) - FREE(prev); + FREE(prev); modtab = NULL; ft_curckt->ci_modtab = NULL; /* free the hash table */ @@ -35,5 +34,4 @@ void INPkillMods(void) modtabhash = NULL; } ft_curckt->ci_modtabhash = NULL; - } From 19ebfb18874ac83bd3df45a4151f55180df172da Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 18 Oct 2023 22:46:27 +0200 Subject: [PATCH 5/5] Add a code model function cm_exit(const int exitcode). This function calls controlled_exit(exitcode) to shut down gracefully. --- src/include/ngspice/cmproto.h | 2 ++ src/include/ngspice/dllitf.h | 1 + src/xspice/cm/cmexport.c | 3 ++- src/xspice/cm/cmutil.c | 9 +++++++-- src/xspice/icm/dlmain.c | 4 ++++ 5 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/include/ngspice/cmproto.h b/src/include/ngspice/cmproto.h index aa987d584..5f7fc4c11 100644 --- a/src/include/ngspice/cmproto.h +++ b/src/include/ngspice/cmproto.h @@ -125,4 +125,6 @@ FILE *fopen_with_path(const char *path, const char *mode); #define CM_IGNORE(x) (void) (x) +void cm_cexit(const int); + #endif /* include guard */ diff --git a/src/include/ngspice/dllitf.h b/src/include/ngspice/dllitf.h index b3a68c65d..1d9295d81 100644 --- a/src/include/ngspice/dllitf.h +++ b/src/include/ngspice/dllitf.h @@ -83,6 +83,7 @@ struct coreInfo_t { void * ((*dllitf_tmalloc)(size_t)); void * ((*dllitf_trealloc)(const void *, size_t)); void ((*dllitf_txfree)(const void *)); + void ((*dllitf_cexit)(const int)); #ifdef KLU int ((*dllitf_MIFbindCSC) (GENmodel *, CKTcircuit *)) ; diff --git a/src/xspice/cm/cmexport.c b/src/xspice/cm/cmexport.c index 2240eaf01..0e65a1f75 100644 --- a/src/xspice/cm/cmexport.c +++ b/src/xspice/cm/cmexport.c @@ -81,7 +81,8 @@ struct coreInfo_t coreInfo = txfree, tmalloc, trealloc, - txfree + txfree, + cm_cexit #else GC_malloc, tcalloc, diff --git a/src/xspice/cm/cmutil.c b/src/xspice/cm/cmutil.c index c1953192c..ee69a0f99 100644 --- a/src/xspice/cm/cmutil.c +++ b/src/xspice/cm/cmutil.c @@ -36,7 +36,7 @@ INTERFACES cm_complex_subtract() cm_complex_multiply() cm_complex_divide() - + cm_cexit() REFERENCED FILES @@ -51,6 +51,8 @@ NON-STANDARD FEATURES #include #include #include "ngspice/cm.h" + +extern void controlled_exit(const int); /* Corner Smoothing Function ************************************ * * @@ -525,4 +527,7 @@ Complex_t cm_complex_divide(Complex_t x, Complex_t y) return(c); } - +void cm_cexit(const int exitcode) +{ + controlled_exit(exitcode); +} diff --git a/src/xspice/icm/dlmain.c b/src/xspice/icm/dlmain.c index c64668991..87f6050f9 100644 --- a/src/xspice/icm/dlmain.c +++ b/src/xspice/icm/dlmain.c @@ -430,6 +430,10 @@ void txfree(const void *ptr) { (coreitf->dllitf_txfree)(ptr); } +void cm_cexit(const int exitcode) { + (coreitf->dllitf_cexit)(exitcode); +} + #ifdef KLU int MIFbindCSC (GENmodel *inModel, CKTcircuit *ckt) { return (coreitf->dllitf_MIFbindCSC) (inModel, ckt) ;