|
|
|
@ -13,58 +13,60 @@ Modified: 2001 Paolo Nenzi (Cider Integration) |
|
|
|
#include <errno.h> |
|
|
|
|
|
|
|
#ifdef CIDER |
|
|
|
|
|
|
|
#include "ngspice/numcards.h" |
|
|
|
#include "ngspice/carddefs.h" |
|
|
|
#include "ngspice/numgen.h" |
|
|
|
#include "ngspice/suffix.h" |
|
|
|
|
|
|
|
#define E_MISSING -1 |
|
|
|
#define E_AMBIGUOUS -2 |
|
|
|
#define E_MISSING -1 |
|
|
|
#define E_AMBIGUOUS -2 |
|
|
|
|
|
|
|
extern IFcardInfo *INPcardTab[]; |
|
|
|
extern int INPnumCards; |
|
|
|
static int INPparseNumMod( CKTcircuit* ckt, INPmodel *model, INPtables *tab, char **errMessage ); |
|
|
|
static int INPfindCard( char *name, IFcardInfo *table[], int numCards ); |
|
|
|
static int INPfindParm( char *name, IFparm *table, int numParms ); |
|
|
|
|
|
|
|
static int INPparseNumMod(CKTcircuit *ckt, INPmodel *model, INPtables *tab, char **errMessage); |
|
|
|
static int INPfindCard(char *name, IFcardInfo *table[], int numCards); |
|
|
|
static int INPfindParm(char *name, IFparm *table, int numParms); |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
extern INPmodel *modtab; |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
* code moved from INPgetMod |
|
|
|
*/ |
|
|
|
static int |
|
|
|
create_model( CKTcircuit* ckt, INPmodel* modtmp, INPtables* tab ) |
|
|
|
create_model(CKTcircuit *ckt, INPmodel *modtmp, INPtables *tab) |
|
|
|
{ |
|
|
|
IFvalue* val; |
|
|
|
char *err = NULL, *line, *parm, *endptr; |
|
|
|
int error, j; |
|
|
|
double dval; |
|
|
|
|
|
|
|
/* not already defined, so create & give parameters */ |
|
|
|
error = ft_sim->newModel (ckt, modtmp->INPmodType, &(modtmp->INPmodfast), modtmp->INPmodName); |
|
|
|
|
|
|
|
if (error) |
|
|
|
return error; |
|
|
|
IFvalue *val; |
|
|
|
char *err = NULL, *line, *parm, *endptr; |
|
|
|
int error, j; |
|
|
|
double dval; |
|
|
|
|
|
|
|
#ifdef CIDER |
|
|
|
/* Handle Numerical Models Differently */ |
|
|
|
if ( modtmp->INPmodType == INPtypelook("NUMD") || |
|
|
|
modtmp->INPmodType == INPtypelook("NBJT") || |
|
|
|
modtmp->INPmodType == INPtypelook("NUMD2") || |
|
|
|
modtmp->INPmodType == INPtypelook("NBJT2") || |
|
|
|
modtmp->INPmodType == INPtypelook("NUMOS") ) |
|
|
|
{ |
|
|
|
error = INPparseNumMod( ckt, modtmp, tab, &err ); |
|
|
|
/* not already defined, so create & give parameters */ |
|
|
|
error = ft_sim->newModel(ckt, modtmp->INPmodType, &(modtmp->INPmodfast), modtmp->INPmodName); |
|
|
|
if (error) |
|
|
|
return error; |
|
|
|
modtmp->INPmodLine->error = err; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
#ifdef CIDER |
|
|
|
/* Handle Numerical Models Differently */ |
|
|
|
if (modtmp->INPmodType == INPtypelook("NUMD") || |
|
|
|
modtmp->INPmodType == INPtypelook("NBJT") || |
|
|
|
modtmp->INPmodType == INPtypelook("NUMD2") || |
|
|
|
modtmp->INPmodType == INPtypelook("NBJT2") || |
|
|
|
modtmp->INPmodType == INPtypelook("NUMOS")) |
|
|
|
{ |
|
|
|
error = INPparseNumMod(ckt, modtmp, tab, &err); |
|
|
|
if (error) |
|
|
|
return error; |
|
|
|
modtmp->INPmodLine->error = err; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
/* parameter isolation, identification, binding */ |
|
|
|
/* parameter isolation, identification, binding */ |
|
|
|
|
|
|
|
line = modtmp->INPmodLine->line; |
|
|
|
|
|
|
|
@ -76,225 +78,233 @@ create_model( CKTcircuit* ckt, INPmodel* modtmp, INPtables* tab ) |
|
|
|
tfree(parm); |
|
|
|
INPgetTok(&line, &parm, 1); /* throw away 'modname' */ |
|
|
|
tfree(parm); |
|
|
|
|
|
|
|
while (*line) { |
|
|
|
INPgetTok(&line, &parm, 1); |
|
|
|
if (!*parm) |
|
|
|
continue; |
|
|
|
INPgetTok(&line, &parm, 1); |
|
|
|
if (!*parm) |
|
|
|
continue; |
|
|
|
|
|
|
|
for (j = 0; j < *(ft_sim->devices[modtmp->INPmodType]->numModelParms); j++) { |
|
|
|
for (j = 0; j < *(ft_sim->devices[modtmp->INPmodType]->numModelParms); j++) { |
|
|
|
|
|
|
|
if (strcmp(parm, "txl") == 0) |
|
|
|
if (strcmp("cpl", ft_sim->devices[modtmp->INPmodType]->modelParms[j].keyword) == 0) |
|
|
|
strcpy(parm, "cpl"); |
|
|
|
if (strcmp(parm, "txl") == 0) |
|
|
|
if (strcmp("cpl", ft_sim->devices[modtmp->INPmodType]->modelParms[j].keyword) == 0) |
|
|
|
strcpy(parm, "cpl"); |
|
|
|
|
|
|
|
if (strcmp(parm, ft_sim->devices[modtmp->INPmodType]->modelParms[j].keyword) == 0) { |
|
|
|
if (strcmp(parm, ft_sim->devices[modtmp->INPmodType]->modelParms[j].keyword) == 0) { |
|
|
|
|
|
|
|
val = INPgetValue(ckt, &line, ft_sim->devices[modtmp->INPmodType]->modelParms[j].dataType, tab); |
|
|
|
val = INPgetValue(ckt, &line, ft_sim->devices[modtmp->INPmodType]->modelParms[j].dataType, tab); |
|
|
|
|
|
|
|
error = ft_sim->setModelParm (ckt, modtmp->INPmodfast, |
|
|
|
error = ft_sim->setModelParm(ckt, modtmp->INPmodfast, |
|
|
|
ft_sim->devices[modtmp->INPmodType]->modelParms[j].id, |
|
|
|
val, NULL); |
|
|
|
if (error) |
|
|
|
return error; |
|
|
|
break; |
|
|
|
if (error) |
|
|
|
return error; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (strcmp(parm, "level") == 0) { |
|
|
|
/* just grab the level number and throw away */ |
|
|
|
/* since we already have that info from pass1 */ |
|
|
|
val = INPgetValue(ckt, &line, IF_REAL, tab); |
|
|
|
} else if (j >= *(ft_sim->devices[modtmp->INPmodType]->numModelParms)) { |
|
|
|
|
|
|
|
/* want only the parameter names in output - not the values */ |
|
|
|
errno = 0; /* To distinguish success/failure after call */ |
|
|
|
dval = strtod(parm, &endptr); |
|
|
|
/* Check for various possible errors */ |
|
|
|
if ((errno == ERANGE && dval == HUGE_VAL) || errno != 0) { |
|
|
|
perror("strtod"); |
|
|
|
controlled_exit(EXIT_FAILURE); |
|
|
|
|
|
|
|
if (strcmp(parm, "level") == 0) { |
|
|
|
/* just grab the level number and throw away */ |
|
|
|
/* since we already have that info from pass1 */ |
|
|
|
val = INPgetValue(ckt, &line, IF_REAL, tab); |
|
|
|
} else if (j >= *(ft_sim->devices[modtmp->INPmodType]->numModelParms)) { |
|
|
|
|
|
|
|
/* want only the parameter names in output - not the values */ |
|
|
|
errno = 0; /* To distinguish success/failure after call */ |
|
|
|
dval = strtod(parm, &endptr); |
|
|
|
/* Check for various possible errors */ |
|
|
|
if ((errno == ERANGE && dval == HUGE_VAL) || errno != 0) { |
|
|
|
perror("strtod"); |
|
|
|
controlled_exit(EXIT_FAILURE); |
|
|
|
} |
|
|
|
if (endptr == parm) /* it was no number - it is really a string */ |
|
|
|
err = INPerrCat(err, |
|
|
|
tprintf("unrecognized parameter (%s) - ignored", |
|
|
|
parm)); |
|
|
|
} |
|
|
|
if (endptr == parm) /* it was no number - it is really a string */ |
|
|
|
err = INPerrCat(err, |
|
|
|
tprintf("unrecognized parameter (%s) - ignored", |
|
|
|
parm)); |
|
|
|
} |
|
|
|
FREE(parm); |
|
|
|
FREE(parm); |
|
|
|
} |
|
|
|
|
|
|
|
modtmp->INPmodLine->error = err; |
|
|
|
|
|
|
|
return 0; |
|
|
|
modtmp->INPmodLine->error = err; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool |
|
|
|
parse_line( char* line, char* tokens[], int num_tokens, double values[], bool found[] ) |
|
|
|
parse_line(char *line, char *tokens[], int num_tokens, double values[], bool found[]) |
|
|
|
{ |
|
|
|
int get_index = -1; |
|
|
|
int i; |
|
|
|
int get_index = -1; |
|
|
|
int i; |
|
|
|
|
|
|
|
for (i = 0; i < num_tokens; i++) |
|
|
|
found[i] = FALSE; |
|
|
|
|
|
|
|
for ( i = 0; i < num_tokens; i++ ) |
|
|
|
found[i] = FALSE; |
|
|
|
while (*line) { |
|
|
|
|
|
|
|
while (*line) { |
|
|
|
if (get_index != -1) { |
|
|
|
int error; |
|
|
|
values[get_index] = INPevaluate(&line, &error, 1); |
|
|
|
found[get_index] = TRUE; |
|
|
|
get_index = -1; |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
if ( get_index != -1 ) { |
|
|
|
int error; |
|
|
|
values[get_index] = INPevaluate( &line, &error, 1 ); |
|
|
|
found[get_index] = TRUE; |
|
|
|
get_index = -1; |
|
|
|
continue; |
|
|
|
} |
|
|
|
char *token = NULL; |
|
|
|
INPgetNetTok(&line, &token, 1); |
|
|
|
|
|
|
|
char *token = NULL; |
|
|
|
INPgetNetTok( &line, &token, 1 ); |
|
|
|
for (i = 0; i < num_tokens; i++) |
|
|
|
if (strcmp(tokens[i], token) == 0) |
|
|
|
get_index = i; |
|
|
|
|
|
|
|
for ( i = 0; i < num_tokens; i++ ) |
|
|
|
if ( strcmp( tokens[i], token ) == 0 ) |
|
|
|
get_index = i; |
|
|
|
txfree(token); |
|
|
|
} |
|
|
|
txfree(token); |
|
|
|
} |
|
|
|
|
|
|
|
for ( i = 0; i < num_tokens; i++ ) |
|
|
|
if (!found[i]) |
|
|
|
return FALSE; |
|
|
|
for (i = 0; i < num_tokens; i++) |
|
|
|
if (!found[i]) |
|
|
|
return FALSE; |
|
|
|
|
|
|
|
return TRUE; |
|
|
|
return TRUE; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool |
|
|
|
is_equal( double result, double expectedResult ) |
|
|
|
is_equal(double result, double expectedResult) |
|
|
|
{ |
|
|
|
return fabs(result - expectedResult) < 1e-15; |
|
|
|
return fabs(result - expectedResult) < 1e-15; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool |
|
|
|
in_range( double value, double min, double max ) |
|
|
|
in_range(double value, double min, double max) |
|
|
|
{ |
|
|
|
/* the standard binning rule is: min <= value < max */ |
|
|
|
return is_equal(value, min) || (min < value && value < max); |
|
|
|
/* the standard binning rule is: min <= value < max */ |
|
|
|
return is_equal(value, min) || (min < value && value < max); |
|
|
|
} |
|
|
|
|
|
|
|
char* |
|
|
|
INPgetModBin( CKTcircuit* ckt, char* name, INPmodel** model, INPtables* tab, char* line ) |
|
|
|
|
|
|
|
char * |
|
|
|
INPgetModBin(CKTcircuit *ckt, char *name, INPmodel **model, INPtables *tab, char *line) |
|
|
|
{ |
|
|
|
INPmodel* modtmp; |
|
|
|
double l, w, lmin, lmax, wmin, wmax; |
|
|
|
double parse_values[4]; |
|
|
|
bool parse_found[4]; |
|
|
|
static char* instance_tokens[] = { "l", "w" }; |
|
|
|
static char* model_tokens[] = { "lmin", "lmax", "wmin", "wmax" }; |
|
|
|
double scale; |
|
|
|
INPmodel *modtmp; |
|
|
|
double l, w, lmin, lmax, wmin, wmax; |
|
|
|
double parse_values[4]; |
|
|
|
bool parse_found[4]; |
|
|
|
static char *instance_tokens[] = { "l", "w" }; |
|
|
|
static char *model_tokens[] = { "lmin", "lmax", "wmin", "wmax" }; |
|
|
|
double scale; |
|
|
|
|
|
|
|
if (!cp_getvar("scale", CP_REAL, &scale)) |
|
|
|
scale = 1; |
|
|
|
if (!cp_getvar("scale", CP_REAL, &scale)) |
|
|
|
scale = 1; |
|
|
|
|
|
|
|
*model = NULL; |
|
|
|
*model = NULL; |
|
|
|
|
|
|
|
if (!parse_line( line, instance_tokens, 2, parse_values, parse_found )) |
|
|
|
return NULL; |
|
|
|
if (!parse_line(line, instance_tokens, 2, parse_values, parse_found)) |
|
|
|
return NULL; |
|
|
|
|
|
|
|
l = parse_values[0]*scale; |
|
|
|
w = parse_values[1]*scale; |
|
|
|
|
|
|
|
for ( modtmp = modtab; modtmp; modtmp = modtmp->INPnextModel ) { |
|
|
|
|
|
|
|
if ( model_name_match(name, modtmp->INPmodName) < 2 ) |
|
|
|
continue; |
|
|
|
|
|
|
|
/* skip if not binnable */ |
|
|
|
if (modtmp->INPmodType != INPtypelook ("BSIM3") && |
|
|
|
modtmp->INPmodType != INPtypelook ("BSIM3v32") && |
|
|
|
modtmp->INPmodType != INPtypelook ("BSIM3v0") && |
|
|
|
modtmp->INPmodType != INPtypelook ("BSIM3v1") && |
|
|
|
modtmp->INPmodType != INPtypelook ("BSIM4") && |
|
|
|
modtmp->INPmodType != INPtypelook ("BSIM4v5") && |
|
|
|
modtmp->INPmodType != INPtypelook ("BSIM4v6") && |
|
|
|
modtmp->INPmodType != INPtypelook ("BSIM4v7") && |
|
|
|
modtmp->INPmodType != INPtypelook ("HiSIM2") && |
|
|
|
modtmp->INPmodType != INPtypelook ("HiSIMHV1") && |
|
|
|
modtmp->INPmodType != INPtypelook ("HiSIMHV2")) |
|
|
|
{ |
|
|
|
continue; |
|
|
|
} |
|
|
|
l = parse_values[0] * scale; |
|
|
|
w = parse_values[1] * scale; |
|
|
|
|
|
|
|
/* if illegal device type */ |
|
|
|
if (modtmp->INPmodType < 0) { |
|
|
|
*model = NULL; |
|
|
|
return tprintf("Unknown device type for model %s\n", name); |
|
|
|
} |
|
|
|
for (modtmp = modtab; modtmp; modtmp = modtmp->INPnextModel) { |
|
|
|
|
|
|
|
if (model_name_match(name, modtmp->INPmodName) < 2) |
|
|
|
continue; |
|
|
|
|
|
|
|
/* skip if not binnable */ |
|
|
|
if (modtmp->INPmodType != INPtypelook("BSIM3") && |
|
|
|
modtmp->INPmodType != INPtypelook("BSIM3v32") && |
|
|
|
modtmp->INPmodType != INPtypelook("BSIM3v0") && |
|
|
|
modtmp->INPmodType != INPtypelook("BSIM3v1") && |
|
|
|
modtmp->INPmodType != INPtypelook("BSIM4") && |
|
|
|
modtmp->INPmodType != INPtypelook("BSIM4v5") && |
|
|
|
modtmp->INPmodType != INPtypelook("BSIM4v6") && |
|
|
|
modtmp->INPmodType != INPtypelook("BSIM4v7") && |
|
|
|
modtmp->INPmodType != INPtypelook("HiSIM2") && |
|
|
|
modtmp->INPmodType != INPtypelook("HiSIMHV1") && |
|
|
|
modtmp->INPmodType != INPtypelook("HiSIMHV2")) |
|
|
|
{ |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
if (!parse_line( modtmp->INPmodLine->line, model_tokens, 4, parse_values, parse_found )) |
|
|
|
continue; |
|
|
|
/* if illegal device type */ |
|
|
|
if (modtmp->INPmodType < 0) { |
|
|
|
*model = NULL; |
|
|
|
return tprintf("Unknown device type for model %s\n", name); |
|
|
|
} |
|
|
|
|
|
|
|
if (!parse_line(modtmp->INPmodLine->line, model_tokens, 4, parse_values, parse_found)) |
|
|
|
continue; |
|
|
|
|
|
|
|
lmin = parse_values[0]; lmax = parse_values[1]; |
|
|
|
wmin = parse_values[2]; wmax = parse_values[3]; |
|
|
|
lmin = parse_values[0]; lmax = parse_values[1]; |
|
|
|
wmin = parse_values[2]; wmax = parse_values[3]; |
|
|
|
|
|
|
|
if ( in_range( l, lmin, lmax ) && in_range( w, wmin, wmax ) ) { |
|
|
|
/* create unless model is already defined */ |
|
|
|
if ( !modtmp->INPmodfast ) { |
|
|
|
int error = create_model( ckt, modtmp, tab ); |
|
|
|
if ( error ) |
|
|
|
return NULL; |
|
|
|
if (in_range(l, lmin, lmax) && in_range(w, wmin, wmax)) { |
|
|
|
/* create unless model is already defined */ |
|
|
|
if (!modtmp->INPmodfast) { |
|
|
|
int error = create_model(ckt, modtmp, tab); |
|
|
|
if (error) |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
*model = modtmp; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
*model = modtmp; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
return NULL; |
|
|
|
|
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
char * |
|
|
|
INPgetMod(CKTcircuit *ckt, char *name, INPmodel ** model, INPtables * tab) |
|
|
|
INPgetMod(CKTcircuit *ckt, char *name, INPmodel **model, INPtables *tab) |
|
|
|
{ |
|
|
|
INPmodel *modtmp; |
|
|
|
INPmodel *modtmp; |
|
|
|
|
|
|
|
#ifdef TRACE |
|
|
|
printf("In INPgetMod, examining model %s ...\n", name); |
|
|
|
printf("In INPgetMod, examining model %s ...\n", name); |
|
|
|
#endif |
|
|
|
|
|
|
|
for (modtmp = modtab; modtmp; modtmp = modtmp->INPnextModel) { |
|
|
|
for (modtmp = modtab; modtmp; modtmp = modtmp->INPnextModel) { |
|
|
|
|
|
|
|
#ifdef TRACE |
|
|
|
printf("In INPgetMod, comparing %s against stored model %s ...\n", name, modtmp->INPmodName); |
|
|
|
printf("In INPgetMod, comparing %s against stored model %s ...\n", name, modtmp->INPmodName); |
|
|
|
#endif |
|
|
|
|
|
|
|
if (strcmp(modtmp->INPmodName, name) == 0) { |
|
|
|
/* found the model in question - now instantiate if necessary */ |
|
|
|
/* and return an appropriate pointer to it */ |
|
|
|
|
|
|
|
/* if illegal device type */ |
|
|
|
if (modtmp->INPmodType < 0) { |
|
|
|
if (strcmp(modtmp->INPmodName, name) == 0) { |
|
|
|
/* 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); |
|
|
|
printf("In INPgetMod, illegal device type for model %s ...\n", name); |
|
|
|
#endif |
|
|
|
*model = NULL; |
|
|
|
return tprintf("Unknown device type for model %s\n", name); |
|
|
|
} |
|
|
|
|
|
|
|
*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); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* 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; |
|
|
|
} |
|
|
|
} |
|
|
|
*model = modtmp; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#ifdef TRACE |
|
|
|
printf("In INPgetMod, didn't find model for %s, using default ...\n", name); |
|
|
|
printf("In INPgetMod, didn't find model for %s, using default ...\n", name); |
|
|
|
#endif |
|
|
|
|
|
|
|
*model = NULL; |
|
|
|
return tprintf("Unable to find definition of model %s - default assumed\n", name); |
|
|
|
*model = NULL; |
|
|
|
return tprintf("Unable to find definition of model %s - default assumed\n", name); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#ifdef CIDER |
|
|
|
/* |
|
|
|
* Parse a numerical model by running through the list of original |
|
|
|
@ -308,14 +318,14 @@ INPgetMod(CKTcircuit *ckt, char *name, INPmodel ** model, INPtables * tab) |
|
|
|
* other = new card |
|
|
|
*/ |
|
|
|
static int |
|
|
|
INPparseNumMod( CKTcircuit* ckt, INPmodel *model, INPtables *tab, char **errMessage ) |
|
|
|
INPparseNumMod(CKTcircuit *ckt, INPmodel *model, INPtables *tab, char **errMessage) |
|
|
|
{ |
|
|
|
card *txtCard; /* Text description of a card */ |
|
|
|
card *txtCard; /* Text description of a card */ |
|
|
|
GENcard *tmpCard; /* Processed description of a card */ |
|
|
|
IFcardInfo *info = NULL; /* Info about the type of card located */ |
|
|
|
char *cardName = NULL; /* name of a card */ |
|
|
|
int cardNum = 0; /* number of this card in the overall line */ |
|
|
|
char *err = NULL; /* Strings for error messages */ |
|
|
|
IFcardInfo *info = NULL; /* Info about the type of card located */ |
|
|
|
char *cardName = NULL; /* name of a card */ |
|
|
|
int cardNum = 0; /* number of this card in the overall line */ |
|
|
|
char *err = NULL; /* Strings for error messages */ |
|
|
|
int error; |
|
|
|
|
|
|
|
/* Chase down to the top of the list of actual cards */ |
|
|
|
@ -366,21 +376,21 @@ INPparseNumMod( CKTcircuit* ckt, INPmodel *model, INPtables *tab, char **errMess |
|
|
|
/* new command card */ |
|
|
|
if (cardName) /* get rid of old card name */ |
|
|
|
FREE(cardName); |
|
|
|
INPgetTok(&line,&cardName,1); /* get new card name */ |
|
|
|
INPgetTok(&line, &cardName, 1); /* get new card name */ |
|
|
|
if (*cardName) { /* Found a name? */ |
|
|
|
int lastType = INPfindCard(cardName,INPcardTab,INPnumCards); |
|
|
|
int lastType = INPfindCard(cardName, INPcardTab, INPnumCards); |
|
|
|
if (lastType >= 0) { |
|
|
|
/* Add card structure to model */ |
|
|
|
info = INPcardTab[lastType]; |
|
|
|
error = info->newCard (&tmpCard, model->INPmodfast ); |
|
|
|
error = info->newCard(&tmpCard, model->INPmodfast); |
|
|
|
if (error) |
|
|
|
return error; |
|
|
|
/* Handle parameter-less cards */ |
|
|
|
} else if (cinprefix( cardName, "title", 3 ) ) { |
|
|
|
} else if (cinprefix(cardName, "title", 3)) { |
|
|
|
/* Do nothing */ |
|
|
|
} else if (cinprefix( cardName, "comment", 3 ) ) { |
|
|
|
} else if (cinprefix(cardName, "comment", 3)) { |
|
|
|
/* Do nothing */ |
|
|
|
} else if (cinprefix( cardName, "end", 3 ) ) { |
|
|
|
} else if (cinprefix(cardName, "end", 3)) { |
|
|
|
/* Terminate parsing */ |
|
|
|
*errMessage = err; |
|
|
|
return 0; |
|
|
|
@ -398,16 +408,19 @@ INPparseNumMod( CKTcircuit* ckt, INPmodel *model, INPtables *tab, char **errMess |
|
|
|
|
|
|
|
/* parse the rest of this line */ |
|
|
|
while (*line) { |
|
|
|
|
|
|
|
int invert = FALSE; |
|
|
|
/* Strip leading carat from booleans */ |
|
|
|
if (*line == '^') { |
|
|
|
invert = TRUE; |
|
|
|
line++; |
|
|
|
} |
|
|
|
|
|
|
|
char *parm; /* name of a parameter */ |
|
|
|
INPgetTok(&line,&parm,1); |
|
|
|
INPgetTok(&line, &parm, 1); |
|
|
|
if (!*parm) |
|
|
|
break; |
|
|
|
|
|
|
|
int idx = INPfindParm(parm, info->cardParms, info->numParms); |
|
|
|
if (idx == E_MISSING) { |
|
|
|
/* parm not found */ |
|
|
|
@ -420,7 +433,8 @@ INPparseNumMod( CKTcircuit* ckt, INPmodel *model, INPtables *tab, char **errMess |
|
|
|
tprintf("Error on card %d : ambiguous parameter (%s) - ignored", |
|
|
|
cardNum, parm)); |
|
|
|
} else { |
|
|
|
IFvalue *value = INPgetValue( ckt, &line, info->cardParms[idx].dataType, tab ); |
|
|
|
IFvalue *value = INPgetValue(ckt, &line, info->cardParms[idx].dataType, tab); |
|
|
|
|
|
|
|
/* invert if this is a boolean entry */ |
|
|
|
if (invert) { |
|
|
|
if ((info->cardParms[idx].dataType & IF_VARTYPES) == IF_FLAG) |
|
|
|
@ -430,7 +444,8 @@ INPparseNumMod( CKTcircuit* ckt, INPmodel *model, INPtables *tab, char **errMess |
|
|
|
tprintf("Error on card %d : non-boolean parameter (%s) - \'^\' ignored", |
|
|
|
cardNum, parm)); |
|
|
|
} |
|
|
|
error = info->setCardParm (info->cardParms[idx].id, value, tmpCard ); |
|
|
|
|
|
|
|
error = info->setCardParm(info->cardParms[idx].id, value, tmpCard); |
|
|
|
if (error) |
|
|
|
return error; |
|
|
|
} |
|
|
|
@ -442,11 +457,12 @@ INPparseNumMod( CKTcircuit* ckt, INPmodel *model, INPtables *tab, char **errMess |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
* Locate the best match to a card name in an IFcardInfo table |
|
|
|
*/ |
|
|
|
static int |
|
|
|
INPfindCard( char *name, IFcardInfo *table[], int numCards ) |
|
|
|
INPfindCard(char *name, IFcardInfo *table[], int numCards) |
|
|
|
{ |
|
|
|
int length = (int) strlen(name); |
|
|
|
int best = E_MISSING; |
|
|
|
@ -455,23 +471,25 @@ INPfindCard( char *name, IFcardInfo *table[], int numCards ) |
|
|
|
int test; |
|
|
|
|
|
|
|
/* compare all the names in the card table to this name */ |
|
|
|
for ( test = 0; test < numCards; test++ ) { |
|
|
|
int match = cimatch( name, table[test]->name ); |
|
|
|
if ((match > 0) && (match == bestMatch )){ |
|
|
|
for (test = 0; test < numCards; test++) { |
|
|
|
int match = cimatch(name, table[test]->name); |
|
|
|
if ((match > 0) && (match == bestMatch)) { |
|
|
|
best = E_AMBIGUOUS; |
|
|
|
} else if ((match > bestMatch) && (match == length)) { |
|
|
|
best = test; |
|
|
|
bestMatch = match; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return best; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
* Locate the best match to a parameter name in an IFparm table |
|
|
|
*/ |
|
|
|
static int |
|
|
|
INPfindParm( char *name, IFparm *table, int numParms ) |
|
|
|
INPfindParm(char *name, IFparm *table, int numParms) |
|
|
|
{ |
|
|
|
int length = (int) strlen(name); |
|
|
|
int best = E_MISSING; |
|
|
|
@ -481,9 +499,9 @@ INPfindParm( char *name, IFparm *table, int numParms ) |
|
|
|
int test; |
|
|
|
|
|
|
|
/* compare all the names in the parameter table to this name */ |
|
|
|
for ( test = 0; test < numParms; test++ ) { |
|
|
|
int match = cimatch( name, table[test].keyword ); |
|
|
|
if ( (match == length) && (match == (int) strlen(table[test].keyword)) ) { |
|
|
|
for (test = 0; test < numParms; test++) { |
|
|
|
int match = cimatch(name, table[test].keyword); |
|
|
|
if ((match == length) && (match == (int) strlen(table[test].keyword))) { |
|
|
|
/* exact match */ |
|
|
|
return test; |
|
|
|
} |
|
|
|
@ -496,6 +514,7 @@ INPfindParm( char *name, IFparm *table, int numParms ) |
|
|
|
best = test; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return best; |
|
|
|
} |
|
|
|
|
|
|
|
|