Support use of vector defaults for XSPICE vector parameters.
This answers Feature Request 60 - "Array as default value for parameter".
This commit is contained in:
parent
f37a292c82
commit
7ff4ad0b32
|
|
@ -101,8 +101,8 @@ struct Mif_Param_Info {
|
|||
char *name; /* Name of this parameter */
|
||||
char *description; /* Description of this parameter */
|
||||
Mif_Data_Type_t type; /* Is this a real, boolean, string, ... */
|
||||
Mif_Boolean_t has_default; /* True if there is a default value */
|
||||
Mif_Parse_Value_t default_value; /* The default value */
|
||||
int default_value_siz;/* Size of default_values array. */
|
||||
Mif_Parse_Value_t *default_values; /* The default values (array). */
|
||||
Mif_Boolean_t has_lower_limit; /* True if there is a lower limit */
|
||||
Mif_Parse_Value_t lower_limit; /* The lower limit for this parameter */
|
||||
Mif_Boolean_t has_upper_limit; /* True if there is a upper limit */
|
||||
|
|
|
|||
|
|
@ -208,8 +208,8 @@ typedef struct {
|
|||
char *name; /* Name of this parameter */
|
||||
char *description; /* Description of this parameter */
|
||||
Data_Type_t type; /* Data type, e.g. REAL, INTEGER, ... */
|
||||
bool has_default; /* True if there is a default value */
|
||||
Value_t default_value; /* The default value */
|
||||
int default_value_idx;/* Start of default_values.. */
|
||||
int default_value_cnt;/* Number of default_values.. */
|
||||
bool has_lower_limit; /* True if there is a lower limit */
|
||||
Value_t lower_limit; /* The lower limit for this parameter */
|
||||
bool has_upper_limit; /* True if there is a upper limit */
|
||||
|
|
@ -239,7 +239,14 @@ typedef struct {
|
|||
|
||||
} Inst_Var_Info_t;
|
||||
|
||||
/* Structure used when parsing default values from the IFS file, used below. */
|
||||
|
||||
typedef struct {
|
||||
bool has_value;
|
||||
bool advance; // Used for vector default values.
|
||||
Data_Type_t kind;
|
||||
Value_t u; // Union holding the value.
|
||||
} My_Value_t;
|
||||
|
||||
/*
|
||||
* The all encompassing structure for the ifs table information
|
||||
|
|
@ -254,7 +261,8 @@ typedef struct {
|
|||
Param_Info_t *param; /* Array of parameter info structs */
|
||||
int num_inst_var; /* Number of entries in the instance var table(s) */
|
||||
Inst_Var_Info_t *inst_var; /* Array of instance variable info structs */
|
||||
|
||||
int num_default_values;
|
||||
My_Value_t *defaults_var; /* Array of annotated values. */
|
||||
} Ifs_Table_t;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -115,16 +115,14 @@ Ifs_Table_t *parser_ifs_table;
|
|||
|
||||
int ifs_num_errors;
|
||||
|
||||
static size_t alloced_size [4];
|
||||
/* Allocated and initial sizes of tables for parse results. */
|
||||
|
||||
/*
|
||||
* !!!!! Make sure these are large enough so that they never get realloced
|
||||
* !!!!! since that will cause garbage uninitialized data...
|
||||
* !!!!! (FIX THIS!)
|
||||
*/
|
||||
#define DEFAULT_SIZE_CONN 100
|
||||
#define DEFAULT_SIZE_PARAM 100
|
||||
#define DEFAULT_SIZE_INST_VAR 100
|
||||
static size_t alloced_size [5];
|
||||
|
||||
#define DEFAULT_SIZE_CONN 10
|
||||
#define DEFAULT_SIZE_PARAM 10
|
||||
#define DEFAULT_SIZE_INST_VAR 10
|
||||
#define DEFAULT_SIZE_DEFAULTS 100
|
||||
#define GROW_SIZE 10
|
||||
|
||||
typedef enum {
|
||||
|
|
@ -132,6 +130,7 @@ typedef enum {
|
|||
TBL_PORT,
|
||||
TBL_PARAMETER,
|
||||
TBL_STATIC_VAR,
|
||||
TBL_DEFAULTS,
|
||||
} Table_t;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -368,15 +367,19 @@ assign_limits (Data_Type_t type, Param_Info_t *param, Range_t range)
|
|||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Advance the item variable, checking for table overflow. */
|
||||
|
||||
static void
|
||||
check_item_num (void)
|
||||
{
|
||||
item++;
|
||||
if (item-item_offset >= ITEM_BUFFER_SIZE) {
|
||||
fatal ("Too many items in table - split into sub-tables");
|
||||
fatal("Too many items in table - split into sub-tables");
|
||||
}
|
||||
if (item > (int) alloced_size [context.table] ) {
|
||||
if (item >= (int) alloced_size [context.table] ) {
|
||||
switch (context.table) {
|
||||
case TBL_NAME:
|
||||
case TBL_NAME: // Fixed size.
|
||||
case TBL_DEFAULTS: // Handled in store_default_value().
|
||||
break;
|
||||
case TBL_PORT:
|
||||
alloced_size[context.table] += GROW_SIZE;
|
||||
|
|
@ -407,7 +410,6 @@ check_item_num (void)
|
|||
break;
|
||||
}
|
||||
}
|
||||
item++;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
|
@ -429,6 +431,7 @@ check_end_item_num (void)
|
|||
num_items_fixed = true;
|
||||
switch (context.table) {
|
||||
case TBL_NAME:
|
||||
case TBL_DEFAULTS:
|
||||
break;
|
||||
case TBL_PORT:
|
||||
TBL->num_conn = num_items;
|
||||
|
|
@ -445,11 +448,38 @@ check_end_item_num (void)
|
|||
}
|
||||
|
||||
#define INIT(n) item = (n); item_offset = (n); num_items = (n); num_items_fixed = false
|
||||
#define ITEM check_item_num()
|
||||
#define END check_end_item_num()
|
||||
#define ITEM check_item_num() // Advances the item_buffer index.
|
||||
#define END check_end_item_num() // Check for excessive values in later row.
|
||||
|
||||
/* Store a default value for a parameter. */
|
||||
|
||||
static void store_default_value(My_Value_t *vp)
|
||||
{
|
||||
if (TBL->num_default_values >= alloced_size[TBL_DEFAULTS]) {
|
||||
/* Expand table. */
|
||||
|
||||
alloced_size [TBL_DEFAULTS] += GROW_SIZE * 5;
|
||||
TBL->defaults_var = (My_Value_t *) realloc(TBL->defaults_var,
|
||||
alloced_size[TBL_DEFAULTS] * sizeof (My_Value_t));
|
||||
if (!TBL->defaults_var) {
|
||||
fatal ("Error allocating memory for default parameter values");
|
||||
}
|
||||
}
|
||||
TBL->defaults_var[TBL->num_default_values++] = *vp;
|
||||
if (vp->advance)
|
||||
ITEM; // Count another parameter sub-table.
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
/* The parser perfoms a double scan for each row (labelled line), with the
|
||||
* row spanning multiple sub-tables (individual connection definitions etc.).
|
||||
* Values and other information are copied into the item_buffer[]
|
||||
* array as they are recognised and then moved to their destination stucture
|
||||
* TBL->xxxx[index] when the whole row has been parsed. Default parameter
|
||||
* values are hndled differently and copied directly to TBL->defaults_var.
|
||||
*/
|
||||
|
||||
%token TOK_ALLOWED_TYPES
|
||||
%token TOK_ARRAY
|
||||
%token TOK_ARRAY_BOUNDS
|
||||
|
|
@ -501,6 +531,10 @@ check_end_item_num (void)
|
|||
%token TOK_SPICE_MODEL_NAME
|
||||
%token TOK_STRING_LITERAL
|
||||
|
||||
/* This declares the type of Bison's "semantic values" (the value associated
|
||||
* with an instance of a symbol of the grammer, $$), defining YYSTYPE.
|
||||
*/
|
||||
|
||||
%union {
|
||||
Ctype_List_t *ctype_list;
|
||||
Dir_t dir;
|
||||
|
|
@ -549,6 +583,7 @@ YYSTYPE item_buffer [ITEM_BUFFER_SIZE];
|
|||
ifs_file : {TBL->num_conn = 0;
|
||||
TBL->num_param = 0;
|
||||
TBL->num_inst_var = 0;
|
||||
TBL->num_default_values = 0;
|
||||
|
||||
saw_function_name = false;
|
||||
saw_model_name = false;
|
||||
|
|
@ -556,14 +591,18 @@ ifs_file : {TBL->num_conn = 0;
|
|||
alloced_size [TBL_PORT] = DEFAULT_SIZE_CONN;
|
||||
alloced_size [TBL_PARAMETER] = DEFAULT_SIZE_PARAM;
|
||||
alloced_size [TBL_STATIC_VAR] = DEFAULT_SIZE_INST_VAR;
|
||||
alloced_size [TBL_DEFAULTS] = DEFAULT_SIZE_DEFAULTS;
|
||||
|
||||
TBL->conn = (Conn_Info_t*)
|
||||
calloc(DEFAULT_SIZE_CONN, sizeof (Conn_Info_t));
|
||||
TBL->param = (Param_Info_t*)
|
||||
calloc (DEFAULT_SIZE_PARAM, sizeof (Param_Info_t));
|
||||
calloc (DEFAULT_SIZE_PARAM, sizeof (Param_Info_t));
|
||||
TBL->inst_var = (Inst_Var_Info_t*)
|
||||
calloc (DEFAULT_SIZE_INST_VAR, sizeof (Inst_Var_Info_t));
|
||||
if (! (TBL->conn && TBL->param && TBL->inst_var) ) {
|
||||
calloc (DEFAULT_SIZE_INST_VAR, sizeof (Inst_Var_Info_t));
|
||||
TBL->defaults_var = (My_Value_t *)
|
||||
calloc(DEFAULT_SIZE_DEFAULTS, sizeof (My_Value_t));
|
||||
if (! (TBL->conn && TBL->param &&
|
||||
TBL->inst_var && TBL->defaults_var) ) {
|
||||
fatal ("Could not allocate enough memory");
|
||||
}
|
||||
}
|
||||
|
|
@ -701,18 +740,8 @@ parameter_table_item : TOK_PARAMETER_NAME list_of_ids
|
|||
check_dtype_not_pointer (ITEM_BUF(i).dtype);
|
||||
TBL->param[i].type = ITEM_BUF(i).dtype;
|
||||
}}
|
||||
| TOK_DEFAULT_VALUE list_of_values
|
||||
{int i;
|
||||
END;
|
||||
FOR_ITEM (i) {
|
||||
TBL->param[i].has_default =
|
||||
ITEM_BUF(i).value.has_value;
|
||||
if (TBL->param[i].has_default) {
|
||||
assign_value (TBL->param[i].type,
|
||||
&TBL->param[i].default_value,
|
||||
ITEM_BUF(i).value);
|
||||
}
|
||||
}}
|
||||
| TOK_DEFAULT_VALUE list_of_default_values
|
||||
{END; } // Check against current sub-table count.
|
||||
| TOK_LIMITS list_of_ranges
|
||||
{int i;
|
||||
END;
|
||||
|
|
@ -870,15 +899,22 @@ number_or_dash : TOK_DASH {$$.has_bound = false;}
|
|||
$$.bound = $1;}
|
||||
;
|
||||
|
||||
list_of_values : /* empty */
|
||||
| list_of_values value_or_dash {ITEM; BUF.value = $2;}
|
||||
list_of_pure_values : value { $1.advance = 1; store_default_value(&$1); }
|
||||
| list_of_pure_values value
|
||||
{ $2.advance = 0; store_default_value(&$2); }
|
||||
;
|
||||
|
||||
list_of_default_values : /* empty */
|
||||
| list_of_default_values value_or_dash
|
||||
{ $2.advance = 1; store_default_value(&$2); }
|
||||
| list_of_default_values
|
||||
TOK_LBRACKET list_of_pure_values TOK_RBRACKET
|
||||
|
||||
value_or_dash : TOK_DASH {$$.has_value = false;}
|
||||
| value
|
||||
;
|
||||
|
||||
value : string {$$.has_value = true;
|
||||
value : string {$$.has_value = true;
|
||||
$$.kind = CMPP_STRING;
|
||||
$$.u.svalue = $1;}
|
||||
| btype {$$.has_value = true;
|
||||
|
|
|
|||
|
|
@ -39,18 +39,6 @@ NON-STANDARD FEATURES
|
|||
|
||||
#include "cmpp.h"
|
||||
|
||||
typedef struct {
|
||||
bool has_value;
|
||||
Data_Type_t kind;
|
||||
union {
|
||||
bool bvalue;
|
||||
int ivalue;
|
||||
double rvalue;
|
||||
Complex_t cvalue;
|
||||
char *svalue;
|
||||
} u;
|
||||
} My_Value_t;
|
||||
|
||||
typedef struct {
|
||||
bool has_bound;
|
||||
My_Value_t bound;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,10 @@ NON-STANDARD FEATURES
|
|||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "cmpp.h"
|
||||
|
||||
/* Local function prototypes */
|
||||
|
|
@ -183,6 +187,8 @@ EXITPOINT:
|
|||
filename, strerror(errno));
|
||||
xrc = -1;
|
||||
}
|
||||
if (xrc < 0 && filename)
|
||||
unlink(filename); // So "make" will not see it.
|
||||
}
|
||||
|
||||
if (filename != (char *) NULL) {
|
||||
|
|
@ -680,29 +686,91 @@ static int write_param_info(
|
|||
FILE *fp, /* File to write to */
|
||||
Ifs_Table_t *ifs_table) /* Table of Interface Specification data */
|
||||
{
|
||||
int xrc = 0;
|
||||
int i;
|
||||
const char *str;
|
||||
|
||||
Param_Info_t * const param = ifs_table->param;
|
||||
const int num_param = ifs_table->num_param;
|
||||
int rc, xrc = 0;
|
||||
int i, dv_idx;
|
||||
const char *str;
|
||||
|
||||
/* Only write the paramTable if there is something to put in it. */
|
||||
/* Otherwise, we will put NULL in the SPICEdev structure in its slot */
|
||||
|
||||
if (ifs_table->num_param == 0) {
|
||||
if (num_param <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write the default values for each parameter. */
|
||||
|
||||
/* Write the structure beginning */
|
||||
int rc = 0;
|
||||
for (i = 0, dv_idx = 0, rc = 0; i < num_param; i++) {
|
||||
Param_Info_t * p_param_cur = param + i;
|
||||
My_Value_t * p_val = ifs_table->defaults_var + dv_idx;
|
||||
int start_index = dv_idx;
|
||||
|
||||
if (dv_idx >= ifs_table->num_default_values) {
|
||||
fprintf(stderr, "Not enough default values for parameter: %s.\n",
|
||||
p_param_cur->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!p_val->has_value) {
|
||||
/* Dummy entry, no default values. */
|
||||
|
||||
++dv_idx;
|
||||
p_param_cur->default_value_cnt = 0;
|
||||
continue;
|
||||
}
|
||||
rc |= fprintf(fp, "static struct Mif_Parse_Value %s_default[] = {\n",
|
||||
p_param_cur->name);
|
||||
|
||||
do { // Write the default values for this parameter.
|
||||
if (!p_val->advance && !p_param_cur->is_array) {
|
||||
fprintf(stderr,
|
||||
"Vector initialisation of default values "
|
||||
"for non-vector parameter: %s.\n",
|
||||
p_param_cur->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (p_val->kind != p_param_cur->type) {
|
||||
if (p_val->kind == CMPP_INTEGER &&
|
||||
p_param_cur->type == CMPP_REAL) {
|
||||
/* Promote it. */
|
||||
|
||||
p_val->u.rvalue = p_val->u.ivalue;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Data type of default value does not match for "
|
||||
"parameter: %s.\n",
|
||||
p_param_cur->name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
str = value_to_str(p_param_cur->type, p_val->u);
|
||||
rc |= fprintf(fp, " %s,\n", str);
|
||||
++dv_idx; ++p_val;
|
||||
} while (dv_idx < ifs_table->num_default_values && !p_val->advance);
|
||||
|
||||
rc |= fprintf(fp, "};\n\n");
|
||||
p_param_cur->default_value_cnt = dv_idx - start_index;
|
||||
}
|
||||
|
||||
/* Check outputs */
|
||||
|
||||
if (rc < 0) {
|
||||
print_error("Writing of default param values failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Write the main parameter structure beginning. */
|
||||
|
||||
rc = 0;
|
||||
rc |= fprintf(fp,
|
||||
"\n"
|
||||
"static Mif_Param_Info_t MIFparamTable[] = {\n");
|
||||
|
||||
|
||||
/* Write out an entry for each parameter in the table */
|
||||
const Param_Info_t * const param = ifs_table->param;
|
||||
const int num_param = ifs_table->num_param;
|
||||
|
||||
for (i = 0; i < num_param; i++) {
|
||||
const Param_Info_t * const p_param_cur = param + i;
|
||||
|
||||
|
|
@ -713,14 +781,11 @@ static int write_param_info(
|
|||
rc |= fprintf(fp, " %s,\n",
|
||||
data_type_to_str(p_param_cur->type));
|
||||
|
||||
str = boolean_to_str(p_param_cur->has_default);
|
||||
rc |= fprintf(fp, " %s,\n", str);
|
||||
|
||||
if (p_param_cur->has_default == true)
|
||||
str = value_to_str(p_param_cur->type, p_param_cur->default_value);
|
||||
rc |= fprintf(fp, " %d,\n", p_param_cur->default_value_cnt);
|
||||
if (p_param_cur->default_value_cnt)
|
||||
rc |= fprintf(fp, " %s_default,\n", p_param_cur->name);
|
||||
else
|
||||
str = no_value_to_str();
|
||||
rc |= fprintf(fp, " %s,\n", str);
|
||||
rc |= fprintf(fp, " NULL,\n");
|
||||
|
||||
str = boolean_to_str(p_param_cur->has_lower_limit);
|
||||
rc |= fprintf(fp, " %s,\n", str);
|
||||
|
|
|
|||
|
|
@ -570,7 +570,7 @@ MIF_INP2A (
|
|||
if(mdfast->param[i]->is_null) {
|
||||
char* emessage;
|
||||
|
||||
if(! param_info->has_default) {
|
||||
if(param_info->default_value_siz == 0) {
|
||||
if (param_info->type == MIF_STRING)
|
||||
continue; // Allow NULL
|
||||
emessage = tprintf("Parameter %s on model %s has no default",
|
||||
|
|
|
|||
|
|
@ -135,7 +135,6 @@ MIFsetup(
|
|||
|
||||
for( ; model != NULL; model = MIFnextModel(model)) {
|
||||
|
||||
|
||||
/* For each parameter not given explicitly on the .model */
|
||||
/* card, default it */
|
||||
|
||||
|
|
@ -151,42 +150,66 @@ MIFsetup(
|
|||
model->param[i]->size = 1;
|
||||
model->param[i]->element = TMALLOC(Mif_Value_t, 1);
|
||||
} else { /* parameter is an array */
|
||||
/* MIF_INP2A() parser assures that there is an associated array connection */
|
||||
/* Since several instances may share this model, we have to create an array */
|
||||
/* big enough for the instance with the biggest connection array */
|
||||
max_size = 0;
|
||||
for(here = MIFinstances(model); here != NULL; here = MIFnextInstance(here)) {
|
||||
size = here->conn[param_info->conn_ref]->size;
|
||||
if(size > max_size)
|
||||
max_size = size;
|
||||
/* If there is an associated array connection, take the
|
||||
* size from there. Since several instances may share
|
||||
* this model, create an array big enough for the
|
||||
* instance with the biggest connection array.
|
||||
* Otherwise, use the size of the default.
|
||||
*/
|
||||
|
||||
if (param_info->has_conn_ref) {
|
||||
for (here = MIFinstances(model), max_size = 0;
|
||||
here != NULL;
|
||||
here = MIFnextInstance(here)) {
|
||||
size = here->conn[param_info->conn_ref]->size;
|
||||
if (size > max_size)
|
||||
max_size = size;
|
||||
}
|
||||
} else {
|
||||
max_size = param_info->default_value_siz;
|
||||
if (param_info->has_lower_bound &&
|
||||
param_info->lower_bound > max_size) {
|
||||
max_size = param_info->lower_bound;
|
||||
}
|
||||
}
|
||||
model->param[i]->size = max_size;
|
||||
model->param[i]->element = TMALLOC(Mif_Value_t, max_size);
|
||||
} /* end if parameter is an array */
|
||||
|
||||
/* set the parameter element(s) to default value */
|
||||
for(j = 0; j < model->param[i]->size; j++) {
|
||||
if (param_info->default_value_siz == 0)
|
||||
continue;
|
||||
|
||||
/* Set the parameter element(s) to default value(s). */
|
||||
|
||||
for(j = 0; j < model->param[i]->size; j++) {
|
||||
Mif_Parse_Value_t *dvp;
|
||||
|
||||
if (j >= param_info->default_value_siz) {
|
||||
dvp = param_info->default_values +
|
||||
param_info->default_value_siz - 1;
|
||||
} else {
|
||||
dvp = param_info->default_values + j;
|
||||
}
|
||||
switch(param_info->type) {
|
||||
|
||||
case MIF_BOOLEAN:
|
||||
model->param[i]->element[j].bvalue = param_info->default_value.bvalue;
|
||||
model->param[i]->element[j].bvalue = dvp->bvalue;
|
||||
break;
|
||||
|
||||
case MIF_INTEGER:
|
||||
model->param[i]->element[j].ivalue = param_info->default_value.ivalue;
|
||||
model->param[i]->element[j].ivalue = dvp->ivalue;
|
||||
break;
|
||||
|
||||
case MIF_REAL:
|
||||
model->param[i]->element[j].rvalue = param_info->default_value.rvalue;
|
||||
model->param[i]->element[j].rvalue = dvp->rvalue;
|
||||
break;
|
||||
|
||||
case MIF_COMPLEX:
|
||||
model->param[i]->element[j].cvalue = param_info->default_value.cvalue;
|
||||
model->param[i]->element[j].cvalue = dvp->cvalue;
|
||||
break;
|
||||
|
||||
case MIF_STRING:
|
||||
model->param[i]->element[j].svalue = param_info->default_value.svalue;
|
||||
model->param[i]->element[j].svalue = dvp->svalue;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
|||
Loading…
Reference in New Issue