From 7c0688cca45b87d5ccbd779c3228cdb9ae6b3a3a Mon Sep 17 00:00:00 2001 From: Florian Ballenegger Date: Tue, 29 Sep 2020 17:47:44 +0200 Subject: [PATCH] instance parameters for xspice, initial commit --- src/include/ngspice/dllitf.h | 3 + src/include/ngspice/mifcmdat.h | 2 +- src/include/ngspice/mifdefs.h | 3 + src/include/ngspice/mifparse.h | 4 +- src/include/ngspice/mifproto.h | 6 + src/xspice/cmpp/cmpp.h | 11 ++ src/xspice/cmpp/ifs_lex.l | 7 +- src/xspice/cmpp/ifs_yacc.y | 22 ++++ src/xspice/cmpp/mod_yacc.y | 6 +- src/xspice/cmpp/writ_ifs.c | 116 ++++++++++++++++-- src/xspice/evt/evtload.c | 1 + src/xspice/icm/dlmain.c | 11 +- src/xspice/mif/Makefile.am | 1 + src/xspice/mif/mif_inp2.c | 15 ++- src/xspice/mif/mifask.c | 209 +++++++++++++++++++++++++++++++-- src/xspice/mif/mifdelete.c | 17 +++ src/xspice/mif/mifload.c | 1 + src/xspice/mif/mifpara.c | 203 ++++++++++++++++++++++++++++++++ src/xspice/mif/mifsetup.c | 3 +- src/xspice/xspice.c | 5 +- 20 files changed, 613 insertions(+), 33 deletions(-) create mode 100644 src/xspice/mif/mifpara.c diff --git a/src/include/ngspice/dllitf.h b/src/include/ngspice/dllitf.h index 8bdbc2354..e4b19eb33 100644 --- a/src/include/ngspice/dllitf.h +++ b/src/include/ngspice/dllitf.h @@ -76,6 +76,9 @@ struct coreInfo_t { void * ((*dllitf_tmalloc)(size_t)); void * ((*dllitf_trealloc)(const void *, size_t)); void ((*dllitf_txfree)(const void *)); + + /* added for instance parameters */ + int ((*dllitf_MIFParam)(int, IFvalue *, GENinstance*, IFvalue *)); }; #endif diff --git a/src/include/ngspice/mifcmdat.h b/src/include/ngspice/mifcmdat.h index 213713c6c..4a4b43f11 100644 --- a/src/include/ngspice/mifcmdat.h +++ b/src/include/ngspice/mifcmdat.h @@ -368,7 +368,7 @@ struct Mif_Private { int num_inst_var; /* Number of instance variables */ Mif_Inst_Var_Data_t **inst_var; /* Information about each inst variable */ Mif_Callback_t *callback; /* Callback function */ - + Mif_Param_Data_t **iparam; /* Information about each inst parameter */ }; diff --git a/src/include/ngspice/mifdefs.h b/src/include/ngspice/mifdefs.h index da654e054..2dfc81a4a 100644 --- a/src/include/ngspice/mifdefs.h +++ b/src/include/ngspice/mifdefs.h @@ -85,6 +85,9 @@ struct MIFinstance { int inst_index; /* Index into inst_table in evt struct in ckt */ Mif_Callback_t callback; /* instance callback function */ + /* F.B: add instance parameters ? */ + int num_iparam; /* number of instance parameters on the code model */ + Mif_Param_Data_t **iparam; /* array of structs for each instance parameter */ }; diff --git a/src/include/ngspice/mifparse.h b/src/include/ngspice/mifparse.h index fcd5e98e1..89be10120 100644 --- a/src/include/ngspice/mifparse.h +++ b/src/include/ngspice/mifparse.h @@ -115,7 +115,9 @@ struct Mif_Param_Info { Mif_Boolean_t has_upper_bound; /* True if there is an array size upper bound */ int upper_bound; /* Array size upper bound */ Mif_Boolean_t null_allowed; /* True if null is allowed for this parameter */ - + Mif_Boolean_t has_model_scope; /* True if the parameter is a model parameter */ + Mif_Boolean_t has_inst_scope; /* True if the parameter is an instance parameter */ + int inst_param_index; /* Index of instance parameter */ }; diff --git a/src/include/ngspice/mifproto.h b/src/include/ngspice/mifproto.h index 722e4b633..94af53a4a 100644 --- a/src/include/ngspice/mifproto.h +++ b/src/include/ngspice/mifproto.h @@ -91,6 +91,12 @@ extern int MIFload( CKTcircuit *ckt ); +extern int MIFParam( + int iparam, + IFvalue *value, + GENinstance *inst, + IFvalue *select +); extern int MIFmParam( int param_index, diff --git a/src/xspice/cmpp/cmpp.h b/src/xspice/cmpp/cmpp.h index 27e713ab7..def95447f 100644 --- a/src/xspice/cmpp/cmpp.h +++ b/src/xspice/cmpp/cmpp.h @@ -132,6 +132,16 @@ typedef struct { } Complex_t; +/* + * The scope of a parameter + */ + +typedef enum { + CMPP_MODEL, + CMPP_INSTANCE, + CMPP_BOTH, + } Param_Scope_t; + /* * Values of different types. @@ -223,6 +233,7 @@ typedef struct { bool has_upper_bound; /* True if there is an array size upper bound */ int upper_bound; /* Array size upper bound */ bool null_allowed; /* True if null is allowed for this parameter */ + Param_Scope_t scope; /* is instance or model parameter */ } Param_Info_t; diff --git a/src/xspice/cmpp/ifs_lex.l b/src/xspice/cmpp/ifs_lex.l index 51339f0bd..d4a88c03b 100644 --- a/src/xspice/cmpp/ifs_lex.l +++ b/src/xspice/cmpp/ifs_lex.l @@ -62,7 +62,7 @@ double yydval; %} -%start BOOL CTYPE DIR DTYPE +%start BOOL CTYPE DIR DTYPE SCOPE %x comment stringl @@ -120,6 +120,7 @@ null_allowed{W}*: {BEGIN BOOL; return TOK_NULL_ALLOWED;} parameter_name{W}*: {return TOK_PARAMETER_NAME;} parameter_table{W}*: {return TOK_PARAMETER_TABLE;} spice_model_name{W}*: {return TOK_SPICE_MODEL_NAME;} +parameter_scope{W}*: {BEGIN SCOPE; return TOK_PARAMETER_SCOPE;} yes {return TOK_BOOL_YES;} no {return TOK_BOOL_NO;} @@ -148,6 +149,10 @@ false {return TOK_BOOL_NO;} string {return TOK_DTYPE_STRING;} pointer {return TOK_DTYPE_POINTER;} +model {return TOK_SCOPE_MODEL;} +instance {return TOK_SCOPE_INSTANCE;} +both {return TOK_SCOPE_BOTH;} + "<" {return TOK_LANGLE;} ">" {return TOK_RANGLE;} "[" {return TOK_LBRACKET;} diff --git a/src/xspice/cmpp/ifs_yacc.y b/src/xspice/cmpp/ifs_yacc.y index 3f9688ca1..b266d9967 100644 --- a/src/xspice/cmpp/ifs_yacc.y +++ b/src/xspice/cmpp/ifs_yacc.y @@ -496,6 +496,11 @@ check_end_item_num (void) %token TOK_SPICE_MODEL_NAME %token TOK_STRING_LITERAL +%token TOK_PARAMETER_SCOPE +%token TOK_SCOPE_MODEL +%token TOK_SCOPE_INSTANCE +%token TOK_SCOPE_BOTH + %union { Ctype_List_t *ctype_list; Dir_t dir; @@ -509,6 +514,7 @@ check_end_item_num (void) int ival; double rval; Complex_t cval; + Param_Scope_t scope; } %type ctype_list delimited_ctype_list @@ -523,6 +529,7 @@ check_end_item_num (void) %type integer %type real %type complex +%type scope %start ifs_file @@ -739,6 +746,13 @@ parameter_table_item : TOK_PARAMETER_NAME list_of_ids FOR_ITEM (i) { TBL->param[i].null_allowed = ITEM_BUF(i).btype; }} + | TOK_PARAMETER_SCOPE list_of_scopes + {int i; + END; + FOR_ITEM (i) { + TBL->param[i].scope = ITEM_BUF(i).scope; + } + } ; static_var_table : /* empty */ @@ -798,6 +812,14 @@ direction : TOK_DIR_IN {$$ = CMPP_IN;} | TOK_DIR_INOUT {$$ = CMPP_INOUT;} ; +list_of_scopes : /* empty */ + | list_of_scopes scope {ITEM; BUF.scope = $2;} + ; + +scope : TOK_SCOPE_MODEL {$$ = CMPP_MODEL;} + | TOK_SCOPE_INSTANCE {$$ = CMPP_INSTANCE;} + | TOK_SCOPE_BOTH {$$ = CMPP_BOTH;} + list_of_bool : /* empty */ | list_of_bool btype {ITEM; BUF.btype = $2;} ; diff --git a/src/xspice/cmpp/mod_yacc.y b/src/xspice/cmpp/mod_yacc.y index 4d3e00aa3..0b327602b 100644 --- a/src/xspice/cmpp/mod_yacc.y +++ b/src/xspice/cmpp/mod_yacc.y @@ -448,7 +448,11 @@ macro : TOK_INIT {fprintf (mod_yyout, "mif_private->circuit.t[%s]", $3);} | TOK_PARAM TOK_LPAREN subscriptable_id TOK_RPAREN {int i = valid_subid ($3, PARAM); - fprintf (mod_yyout, "mif_private->param[%d]->element[%s]", + if(mod_ifs_table->param[i].scope == CMPP_MODEL) + fprintf (mod_yyout, "mif_private->param[%d]->element[%s]", + i, subscript ($3)); + else + fprintf (mod_yyout, "mif_private->iparam[mif_private->param[%d]->inst_param_index]->element[%s]", i, subscript ($3)); put_type (mod_yyout, mod_ifs_table->param[i].type); } diff --git a/src/xspice/cmpp/writ_ifs.c b/src/xspice/cmpp/writ_ifs.c index 6015a8fbf..c71d0ef0c 100644 --- a/src/xspice/cmpp/writ_ifs.c +++ b/src/xspice/cmpp/writ_ifs.c @@ -106,7 +106,7 @@ int write_ifs_c_file( /* Open the ifspec.c file for write access */ if ((filename = gen_filename(filename_in, "w")) == (char *) NULL) { - print_error("ERROR - Unable to build path to \"%s\".", filename); + print_error("ERROR - Unable to build path to \"%s\".", filename_in); xrc = -1; goto EXITPOINT; } @@ -290,11 +290,15 @@ static int write_pTable( int i; bool is_array; Data_Type_t type; - + int iparam_index; /* Only write the pTable if there is something to put in it. */ /* Otherwise, we will put NULL in the SPICEdev structure in its slot */ - if (ifs_table->num_inst_var == 0) { + for(i = 0; i < ifs_table->num_param; i++) + if(ifs_table->param[i].scope != CMPP_MODEL) + break; /* has at least one instance parameter */ + if(i==ifs_table->num_param) /* has no instance parameter */ + if (ifs_table->num_inst_var == 0) { /* has no static var */ return 0; } @@ -306,6 +310,68 @@ static int write_pTable( "static IFparm MIFpTable[] = {\n"); + /* F.B: add instance parameters as IOP */ + /* Use the index of the element in the parameter info array */ + /* as the SPICE3 integer tag. */ + /* i.e for the same parameter, the same tag is used for both model and instance */ + iparam_index=0; + Param_Info_t *param = ifs_table->param; + for(i = 0; i < ifs_table->num_param; i++) { + Param_Info_t *param_cur = param + i; + + /* skip if it is a model parameter */ + if(param_cur->scope == CMPP_MODEL) + continue; + + /* Use the SPICE3 IOP macro since instance parameters are input/output */ + + rc |= fprintf(fp, " IOP("); + + /* Put in the name of the parameter and the integer tag */ + rc |= fprintf(fp, "\"%s\", ", param_cur->name); + rc |= fprintf(fp, "%d, ", i); + + /* Format SPICE3 type according to parameter type field */ + + const bool is_array = param_cur->is_array; + const Data_Type_t type = param_cur->type; + + if (is_array) { + rc |= fprintf(fp, "("); + } + + if (type == CMPP_BOOLEAN) { + rc |= fprintf(fp, "IF_FLAG"); /* no BOOLEAN in SPICE3 */ + } + else if (type == CMPP_INTEGER) { + rc |= fprintf(fp, "IF_INTEGER"); + } + else if (type == CMPP_REAL) { + rc |= fprintf(fp, "IF_REAL"); + } + else if (type == CMPP_COMPLEX) { + rc |= fprintf(fp, "IF_COMPLEX"); + } + else if (type == CMPP_STRING) { + rc |= fprintf(fp, "IF_STRING"); + } + else { + print_error("INTERNAL ERROR - write_mPTable() - Impossible data type."); + xrc = -1; + } + + if (is_array) { + rc |= fprintf(fp, "|IF_VECTOR)"); + } + + + /* Put in the description string and finish this line off */ + rc |= fprintf(fp, ", \"%s\"),\n", ifs_table->param[i].description); + + iparam_index++; + } /* end of loop over parameters */ + + /* Write out an entry for each instance variable in the table */ /* Use the index of the element in the instance variable info array */ @@ -363,6 +429,11 @@ static int write_pTable( /* Put in the description string and finish this line off */ rc |= fprintf(fp, ", \"%s\"),\n", ifs_table->inst_var[i].description); } /* end of loop over instance variables */ + + + + + /* Finish off the structure */ rc |= fprintf(fp, "};\n\n"); @@ -422,7 +493,11 @@ static int write_mPTable( Param_Info_t *param = ifs_table->param; for(i = 0; i < ifs_table->num_param; i++) { Param_Info_t *param_cur = param + i; - + + /* skip if it is an instance parameter */ + if(param_cur->scope == CMPP_INSTANCE) + continue; + /* Use the SPICE3 IOP macro since model parameters are input/output */ rc |= fprintf(fp, " IOP("); @@ -684,6 +759,7 @@ static int write_param_info( int xrc = 0; int i; const char *str; + int inst_param_index = 0; /* Only write the paramTable if there is something to put in it. */ @@ -815,7 +891,18 @@ static int write_param_info( str = boolean_to_str(p_param_cur->null_allowed); rc |= fprintf(fp, " %s,\n", str); - + + /* F.B. info about instance parameters */ + str = boolean_to_str(p_param_cur->scope != CMPP_INSTANCE); + rc |= fprintf(fp, " %s,\n", str); + str = boolean_to_str(p_param_cur->scope != CMPP_MODEL); + rc |= fprintf(fp, " %s,\n", str); + str = integer_to_str(p_param_cur->scope == CMPP_MODEL ? -1 : inst_param_index); + rc |= fprintf(fp, " %s,\n", str); + + if(p_param_cur->scope != CMPP_MODEL) + inst_param_index++; + rc |= fprintf(fp, " },\n"); } /* for number of parameters */ @@ -931,13 +1018,20 @@ static int write_SPICEdev( { int rc = 0; /* init print rc to nonnegative (no error) */ int xrc = 0; - + int i, ninstparams; + /* Extern the code model function name */ rc |= fprintf(fp, "\n" "extern void %s(Mif_Private_t *);\n", ifs_table->name.c_fcn_name); - + + /* count instance parameters */ + ninstparams=0; + for(i = 0; i < ifs_table->num_param; i++) + if(ifs_table->param[i].scope != CMPP_MODEL) + ninstparams++; + /* SPICE now needs these static integers */ rc |= fprintf(fp, "\n" @@ -947,7 +1041,7 @@ static int write_SPICEdev( "static int val_numModelParms = %d;\n" "static int val_sizeofMIFinstance = sizeof(MIFinstance);\n" "static int val_sizeofMIFmodel = sizeof(MIFmodel);\n", - ifs_table->num_inst_var, ifs_table->num_param); + ifs_table->num_inst_var + ninstparams, ifs_table->num_param); /* Write out the structure beginning */ @@ -969,10 +1063,10 @@ static int write_SPICEdev( " .termNames = NULL,\n" " .numInstanceParms = &val_numInstanceParms,\n"); - if(ifs_table->num_inst_var > 0) - rc |= fprintf(fp, " .instanceParms = MIFpTable,\n"); - else + if((ninstparams == 0) && (ifs_table->num_inst_var == 0)) rc |= fprintf(fp, " .instanceParms = NULL,\n"); + else + rc |= fprintf(fp, " .instanceParms = MIFpTable,\n"); rc |= fprintf(fp, " .numModelParms = &val_numModelParms,\n"); if(ifs_table->num_param > 0) diff --git a/src/xspice/evt/evtload.c b/src/xspice/evt/evtload.c index 1dc0368a7..770b557c7 100644 --- a/src/xspice/evt/evtload.c +++ b/src/xspice/evt/evtload.c @@ -223,6 +223,7 @@ int EVTload( cm_data.conn = inst->conn; cm_data.num_param = inst->num_param; cm_data.param = inst->param; + cm_data.iparam = inst->iparam; cm_data.num_inst_var = inst->num_inst_var; cm_data.inst_var = inst->inst_var; cm_data.callback = &(inst->callback); diff --git a/src/xspice/icm/dlmain.c b/src/xspice/icm/dlmain.c index ce9f79292..b92092573 100644 --- a/src/xspice/icm/dlmain.c +++ b/src/xspice/icm/dlmain.c @@ -23,7 +23,7 @@ ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -// Do not modify anything below this line +// Do not modify anything below this line (F.B.: added MIFparam however) ////////////////////////////////////////////////////////////////////////////// SPICEdev *cmDEVices[] = { @@ -164,6 +164,15 @@ int MIFmParam( return (coreitf->dllitf_MIFmParam)(param_index,value,inModel); } +int MIFParam( + int param_index, + IFvalue *value, + GENinstance *inst, + IFvalue *select + ) { + return (coreitf->dllitf_MIFParam)(param_index,value,inst,select); +} + int MIFask( CKTcircuit *ckt, GENinstance *inst, diff --git a/src/xspice/mif/Makefile.am b/src/xspice/mif/Makefile.am index 60b1b6fdf..e290f2b3f 100644 --- a/src/xspice/mif/Makefile.am +++ b/src/xspice/mif/Makefile.am @@ -19,6 +19,7 @@ libmifxsp_la_SOURCES = \ mifdelete.c \ mifmdelete.c \ mifdestr.c \ + mifpara.c \ mif.c AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include diff --git a/src/xspice/mif/mif_inp2.c b/src/xspice/mif/mif_inp2.c index aa84ff97e..2f5851c15 100644 --- a/src/xspice/mif/mif_inp2.c +++ b/src/xspice/mif/mif_inp2.c @@ -682,7 +682,20 @@ static void MIFinit_inst( fast->num_param = mdfast->num_param; fast->param = mdfast->param; - + + /* allocate instance parameter data */ + fast->num_iparam = *(DEVices[mod_type]->DEVpublic.numInstanceParms) - DEVices[mod_type]->DEVpublic.num_inst_var; + if(fast->num_iparam>0) + fast->iparam = TMALLOC(Mif_Param_Data_t* ,fast->num_iparam); + else + fast->iparam = NULL; + for(i = 0; i < fast->num_iparam; i++) { + fast->iparam[i] = TMALLOC(Mif_Param_Data_t, 1); + fast->iparam[i]->is_null = MIF_TRUE; + fast->iparam[i]->size = 0; + fast->iparam[i]->element = NULL; + } + /* initialize any additional instance data */ fast->initialized = MIF_FALSE; fast->analog = MIF_FALSE; diff --git a/src/xspice/mif/mifask.c b/src/xspice/mif/mifask.c index f91c63b7b..fccdba077 100644 --- a/src/xspice/mif/mifask.c +++ b/src/xspice/mif/mifask.c @@ -51,8 +51,22 @@ NON-STANDARD FEATURES #include "ngspice/mifproto.h" #include "ngspice/mifdefs.h" +#include "ngspice/mifparse.h" + /* #include "suffix.h" */ +/* forward prototypes */ +int MIFaskInstVar( + MIFinstance *inst, /* The instance to get the value from */ + int inst_index, /* The inst var to get */ + IFvalue *value /* The value returned */ +); +int MIFaskInstParam( + MIFinstance *inst, /* The instance to get the value from */ + int param_index, /* The parameter to get */ + IFvalue *value /* The value returned */ +); + /* MIFask @@ -77,13 +91,7 @@ int MIFask( MIFinstance *inst; MIFmodel *model; int mod_type; - int value_type; int i; - int size; - - int inst_index; - - Mif_Boolean_t is_array; NG_IGNORE(ckt); NG_IGNORE(select); @@ -94,21 +102,46 @@ int MIFask( /* Arrange for access to MIF specific data in the model */ model = MIFmodPtr(inst); - /* Get model type */ mod_type = model->MIFmodType; if((mod_type < 0) || (mod_type >= DEVmaxnum)) return(E_BADPARM); - /* Adjust parameter tag to actual index into inst info array */ - inst_index = which - model->num_param; + /* see if is trying to get an instance variable or an instance parameter */ + if(which>= model->num_param) + return MIFaskInstVar(inst, which - model->num_param, value); + else + return MIFaskInstParam(inst, which, value); +} - /* Check instance index for validity */ - if((inst_index < 0) || (inst_index >= inst->num_inst_var)) + +int MIFaskInstVar( + MIFinstance *inst, /* The instance to get the value from */ + int inst_index, /* The inst var to get */ + IFvalue *value /* The value returned */ +) +{ + MIFmodel *model; + int mod_type; + int value_type; + int i; + int size; + + Mif_Boolean_t is_array; + + model = MIFmodPtr(inst); + /* Get model type */ + mod_type = model->MIFmodType; + if((mod_type < 0) || (mod_type >= DEVmaxnum)) return(E_BADPARM); - /* get value type to know which members of unions to access */ - value_type = DEVices[mod_type]->DEVpublic.instanceParms[inst_index].dataType; + /* get value type to know which members of unions to access */ + for(i=0;i<*(DEVices[mod_type]->DEVpublic.numInstanceParms);i++) + if(DEVices[mod_type]->DEVpublic.instanceParms[i].id == model->num_param+inst_index) + break; + if(i>=*(DEVices[mod_type]->DEVpublic.numInstanceParms)) + return(E_BADPARM); + value_type = DEVices[mod_type]->DEVpublic.instanceParms[i].dataType; value_type &= IF_VARTYPES; @@ -223,3 +256,153 @@ int MIFask( return(OK); } + + + +int MIFaskInstParam( + MIFinstance *inst, /* The instance to get the value from */ + int param_index, /* The parameter to get */ + IFvalue *value /* The value returned */ +) +{ + MIFmodel *model; + int mod_type; + int value_type; + int i; + int size; + + int inst_index; + + Mif_Boolean_t is_array; + + model = MIFmodPtr(inst); + /* Get model type */ + mod_type = model->MIFmodType; + if((mod_type < 0) || (mod_type >= DEVmaxnum)) + return(E_BADPARM); + + /* get value type to know which members of unions to access */ + for(i=0;i<*(DEVices[mod_type]->DEVpublic.numInstanceParms);i++) + if(DEVices[mod_type]->DEVpublic.instanceParms[i].id == param_index) + break; + if(i>=*(DEVices[mod_type]->DEVpublic.numInstanceParms)) + return(E_BADPARM); + value_type = DEVices[mod_type]->DEVpublic.instanceParms[i].dataType; + value_type &= IF_VARTYPES; + + /* get index into inst->iparam */ + inst_index = DEVices[mod_type]->DEVpublic.param[param_index].inst_param_index; + if(inst_index <0) + return(E_BADPARM); + + /* determine if the parameter is an array or not */ + is_array = value_type & IF_VECTOR; + + + /* Transfer the values to the SPICE3C1 value union from the param elements */ + /* This is analagous to what SPICE3 does with other device types */ + + + if(! is_array) { + + switch(value_type) { + + case IF_FLAG: + value->iValue = inst->iparam[inst_index]->element[0].bvalue; + break; + + case IF_INTEGER: + value->iValue = inst->iparam[inst_index]->element[0].ivalue; + break; + + case IF_REAL: + value->rValue = inst->iparam[inst_index]->element[0].rvalue; + break; + + case IF_STRING: + /* Make copy of string. We don't trust caller to not free it */ + /* These copies could get expensive! */ + value->sValue = MIFcopy(inst->iparam[inst_index]->element[0].svalue); + break; + + case IF_COMPLEX: + /* we don't trust the caller to have a parallel complex structure */ + /* so copy the real and imaginary parts explicitly */ + value->cValue.real = inst->iparam[inst_index]->element[0].cvalue.real; + value->cValue.imag = inst->iparam[inst_index]->element[0].cvalue.imag; + break; + + default: + return(E_BADPARM); + + } + } + else { /* it is an array */ + + size = inst->iparam[inst_index]->size; + if(size < 0) + size = 0; + + value->v.numValue = size; + + switch(value_type) { + + /* Note that we malloc space each time this function is called. */ + /* This is what TRAask.c does, so we do it too, even though */ + /* we don't know if it is ever freed... */ + + case IF_FLAGVEC: + if(size <= 0) + break; + value->v.vec.iVec = TMALLOC(int, size); + for(i = 0; i < size; i++) + value->v.vec.iVec[i] = inst->iparam[inst_index]->element[i].bvalue; + break; + + case IF_INTVEC: + if(size <= 0) + break; + value->v.vec.iVec = TMALLOC(int, size); + for(i = 0; i < size; i++) + value->v.vec.iVec[i] = inst->iparam[inst_index]->element[i].ivalue; + break; + + case IF_REALVEC: + if(size <= 0) + break; + value->v.vec.rVec = TMALLOC(double, size); + for(i = 0; i < size; i++) + value->v.vec.rVec[i] = inst->iparam[inst_index]->element[i].rvalue; + break; + + case IF_STRINGVEC: + if(size <= 0) + break; + value->v.vec.sVec = TMALLOC(char *, size); + for(i = 0; i < size; i++) + /* Make copy of string. We don't trust caller to not free it */ + /* These copies could get expensive! */ + value->v.vec.sVec[i] = MIFcopy(inst->iparam[inst_index]->element[i].svalue); + break; + + case IF_CPLXVEC: + if(size <= 0) + break; + /* we don't trust the caller to have a parallel complex structure */ + /* so copy the real and imaginary parts explicitly */ + value->v.vec.cVec = TMALLOC(IFcomplex, size); + for(i = 0; i < size; i++) { + value->v.vec.cVec[i].real = inst->iparam[inst_index]->element[i].cvalue.real; + value->v.vec.cVec[i].imag = inst->iparam[inst_index]->element[i].cvalue.imag; + } + break; + + default: + return(E_BADPARM); + + } /* end switch */ + + } /* end else */ + + return(OK); +} diff --git a/src/xspice/mif/mifdelete.c b/src/xspice/mif/mifdelete.c index 3c077d6a0..3b643ffe3 100644 --- a/src/xspice/mif/mifdelete.c +++ b/src/xspice/mif/mifdelete.c @@ -86,6 +86,7 @@ MIFdelete(GENinstance *gen_inst) cm_data.conn = here->conn; cm_data.num_param = here->num_param; cm_data.param = here->param; + cm_data.iparam = here->iparam; cm_data.num_inst_var = here->num_inst_var; cm_data.inst_var = here->inst_var; cm_data.callback = &(here->callback); @@ -170,7 +171,23 @@ MIFdelete(GENinstance *gen_inst) } FREE(here->inst_var); + /* Free the instance params stuff allocated in mif_inp2.c */ + for (i = 0; i < here->num_iparam; i++) { + /* delete content of union 'element' if it contains a string */ + if (here->iparam[i]->element) { + if (here->iparam[i]->eltype == IF_STRING) + FREE(here->iparam[i]->element[0].svalue); + else if (here->iparam[i]->eltype == IF_STRINGVEC) + for (int j = 0; j < here->iparam[i]->size; j++) + FREE(here->iparam[i]->element[j].svalue); + FREE(here->iparam[i]->element); + } + FREE(here->iparam[i]); + } + FREE(here->iparam); + /* ************************************************************* */ + /* Before instance parameters was added there was this comment: */ /* Dont free params here. They are not currently implemented on */ /* a per-instance basis, so their allocated space is owned by */ /* the parent model, not the instance. Param stuff will be freed */ diff --git a/src/xspice/mif/mifload.c b/src/xspice/mif/mifload.c index febc67342..d32035810 100644 --- a/src/xspice/mif/mifload.c +++ b/src/xspice/mif/mifload.c @@ -435,6 +435,7 @@ MIFload( cm_data.conn = here->conn; cm_data.num_param = here->num_param; cm_data.param = here->param; + cm_data.iparam = here->iparam; cm_data.num_inst_var = here->num_inst_var; cm_data.inst_var = here->inst_var; cm_data.callback = &(here->callback); diff --git a/src/xspice/mif/mifpara.c b/src/xspice/mif/mifpara.c new file mode 100644 index 000000000..a14cd8e3a --- /dev/null +++ b/src/xspice/mif/mifpara.c @@ -0,0 +1,203 @@ +/*============================================================================ +FILE MIFPara.c + +Derived from MIFmPara.c by Florian Ballenegger + +Original copyright: + +MEMBER OF process XSPICE + +Copyright 1991 +Georgia Tech Research Corporation +Atlanta, Georgia 30332 +All Rights Reserved + +PROJECT A-8503 + +AUTHORS + + 9/12/91 Bill Kuhn + +SUMMARY + + This file contains the function used to assign the value of a parameter + read from the .model card into the appropriate structure in the model. + +============================================================================*/ + +#include "ngspice/ngspice.h" +#include "ngspice/const.h" +#include "ngspice/ifsim.h" +#include "ngspice/devdefs.h" +#include "ngspice/sperror.h" + +#include "ngspice/mifproto.h" +#include "ngspice/mifparse.h" +#include "ngspice/mifdefs.h" +#include "ngspice/mifcmdat.h" + + + +/* ARGSUSED */ +int +MIFParam(int param_index, IFvalue *value, GENinstance *inst_in, IFvalue *select) +{ + + MIFmodel *model; + MIFinstance *inst; + int mod_type; + int value_type; + int i; + int iparam; + Mif_Boolean_t is_array; + + + NG_IGNORE(select); + + /* Arrange for access to MIF specific data in the model */ + inst = (MIFinstance*) inst_in; + model = MIFmodPtr(inst); + + /* Get model type */ + mod_type = model->MIFmodType; + if((mod_type < 0) || (mod_type >= DEVmaxnum)) + return(E_BADPARM); + + + /* Check parameter index for validity */ + if((param_index < 0) || (param_index >= model->num_param)) + return(E_BADPARM); + + if(!DEVices[mod_type]->DEVpublic.param[param_index].has_inst_scope) + return(E_BADPARM); + + iparam = DEVices[mod_type]->DEVpublic.param[param_index].inst_param_index; + if((iparam < 0) || (iparam >= inst->num_iparam)) + return(E_BADPARM); + + /* find param_index */ + /* + param_index=-1; + for(i=0;iDEVpublic.num_param;i++) + if(DEVices[mod_type]->DEVpublic.param[i].inst_param_index == iparam) + { + param_index=i; + break; + } + if(param_index<0) + return(E_BADPARM); */ + + /* get value type to know which members of unions to access */ + value_type = DEVices[mod_type]->DEVpublic.modelParms[param_index].dataType; + value_type &= IF_VARTYPES; + + + /* determine if the parameter is an array or not */ + is_array = value_type & IF_VECTOR; + + /* initialize the parameter is_null and size elements and allocate elements */ + inst->iparam[iparam]->is_null = MIF_FALSE; + /* element may exist already, if called from 'alter' */ + FREE(inst->iparam[iparam]->element); + if(is_array) { + inst->iparam[iparam]->size = value->v.numValue; + inst->iparam[iparam]->element = TMALLOC(Mif_Value_t, value->v.numValue); + } + else { + inst->iparam[iparam]->size = 1; + inst->iparam[iparam]->element = TMALLOC(Mif_Value_t, 1); + } + + + /* Transfer the values from the SPICE3C1 value union to the param elements */ + /* This is analagous to what SPICE3 does with other device types */ + + + if(! is_array) { + + switch(value_type) { + + case IF_FLAG: + inst->iparam[iparam]->element[0].bvalue = value->iValue; + inst->iparam[iparam]->eltype = IF_FLAG; + break; + + case IF_INTEGER: + inst->iparam[iparam]->element[0].ivalue = value->iValue; + inst->iparam[iparam]->eltype = IF_INTEGER; + break; + + case IF_REAL: + inst->iparam[iparam]->element[0].rvalue = value->rValue; + inst->iparam[iparam]->eltype = IF_REAL; + break; + + case IF_STRING: + /* we don't trust the caller to keep the string alive, so copy it */ + inst->iparam[iparam]->element[0].svalue = + TMALLOC(char, 1 + strlen(value->sValue)); + strcpy(inst->iparam[iparam]->element[0].svalue, value->sValue); + inst->iparam[iparam]->eltype = IF_STRING; + break; + + case IF_COMPLEX: + /* we don't trust the caller to have a parallel complex structure */ + /* so copy the real and imaginary parts explicitly */ + inst->iparam[iparam]->element[0].cvalue.real = value->cValue.real; + inst->iparam[iparam]->element[0].cvalue.imag = value->cValue.imag; + inst->iparam[iparam]->eltype = IF_COMPLEX; + break; + + default: + return(E_BADPARM); + + } + } + else { /* it is an array */ + + for(i = 0; i < value->v.numValue; i++) { + + switch(value_type) { + + case IF_FLAGVEC: + inst->iparam[iparam]->element[i].bvalue = value->v.vec.iVec[i]; + inst->iparam[iparam]->eltype = IF_FLAGVEC; + break; + + case IF_INTVEC: + inst->iparam[iparam]->element[i].ivalue = value->v.vec.iVec[i]; + inst->iparam[iparam]->eltype = IF_INTVEC; + break; + + case IF_REALVEC: + inst->iparam[iparam]->element[i].rvalue = value->v.vec.rVec[i]; + inst->iparam[iparam]->eltype = IF_REALVEC; + break; + + case IF_STRINGVEC: + /* we don't trust the caller to keep the string alive, so copy it */ + inst->iparam[iparam]->element[i].svalue = + TMALLOC(char, 1 + strlen(value->v.vec.sVec[i])); + strcpy(inst->iparam[iparam]->element[i].svalue, value->v.vec.sVec[i]); + inst->iparam[iparam]->eltype = IF_STRINGVEC; + break; + + case IF_CPLXVEC: + /* we don't trust the caller to have a parallel complex structure */ + /* so copy the real and imaginary parts explicitly */ + inst->iparam[iparam]->element[i].cvalue.real = value->v.vec.cVec[i].real; + inst->iparam[iparam]->element[i].cvalue.imag = value->v.vec.cVec[i].imag; + inst->iparam[iparam]->eltype = IF_CPLXVEC; + break; + + default: + return(E_BADPARM); + + } /* end switch */ + + } /* end for number of elements of vector */ + + } /* end else */ + + return(OK); +} diff --git a/src/xspice/mif/mifsetup.c b/src/xspice/mif/mifsetup.c index 275c75f13..b5aaff90c 100644 --- a/src/xspice/mif/mifsetup.c +++ b/src/xspice/mif/mifsetup.c @@ -142,7 +142,7 @@ MIFsetup( for(i = 0; i < model->num_param; i++) { - if(model->param[i]->is_null) { + if(model->param[i]->is_null && DEVices[mod_type]->DEVpublic.param[i].has_model_scope) { /* setup a pointer for quick access */ param_info = &(DEVices[mod_type]->DEVpublic.param[i]); @@ -545,6 +545,7 @@ MIFunsetup(GENmodel *inModel,CKTcircuit *ckt) cm_data.conn = here->conn; cm_data.num_param = here->num_param; cm_data.param = here->param; + cm_data.iparam = here->iparam; cm_data.num_inst_var = here->num_inst_var; cm_data.inst_var = here->inst_var; cm_data.callback = &(here->callback); diff --git a/src/xspice/xspice.c b/src/xspice/xspice.c index 620981b91..5f94d0557 100644 --- a/src/xspice/xspice.c +++ b/src/xspice/xspice.c @@ -73,7 +73,7 @@ struct coreInfo_t coreInfo = txfree, tmalloc, trealloc, - txfree + txfree, #else GC_malloc, tcalloc, @@ -81,6 +81,7 @@ struct coreInfo_t coreInfo = no_free, GC_malloc, GC_realloc, - no_free + no_free, #endif + MIFParam, };