diff --git a/src/xspice/Makefile.am b/src/xspice/Makefile.am index 949cd8347..90ab4d779 100755 --- a/src/xspice/Makefile.am +++ b/src/xspice/Makefile.am @@ -9,7 +9,7 @@ EXTRA_DIST = README ## libs. It is currently compiled manually, last. ##SUBDIRS = mif cm enh evt ipc idn icm -SUBDIRS = mif cm enh evt ipc idn +SUBDIRS = mif cm enh evt ipc idn cmpp INCLUDES = -I$(top_srcdir)/src/include -I$(top_srcdir) diff --git a/src/xspice/cmpp/Makefile b/src/xspice/cmpp/Makefile new file mode 100755 index 000000000..7af86a0da --- /dev/null +++ b/src/xspice/cmpp/Makefile @@ -0,0 +1,36 @@ + +cmpp_OBJS=main.o pp_ifs.o pp_lst.o pp_mod.o read_ifs.o util.o writ_ifs.o \ + ifs_yacc.o ifs_lex.o mod_yacc.o mod_lex.o + +cmpp_GEN=ifs_yacc.c ifs_tok.h \ + ifs_lex.c ifs_lex.h \ + mod_lex.c mod_lex.h \ + mod_yacc.c mod_tok.h + +YACC=bison -d --yacc +#YACC=yacc -d + +CC=gcc -O2 -g + +LEX=flex -t + +all: cmpp + +cmpp: $(cmpp_OBJS) + $(CC) -o cmpp $(cmpp_OBJS) + +%.c : %.y + $(YACC) -p $(*:yacc=)yy $< + mv -f y.tab.c $*.c + mv -f y.tab.h $(*:yacc=)tok.h + +%.c : %.l + $(LEX) -P$(*:lex=)yy $< > $@ + +ifs_lex.c : ifs_lex.l + $(LEX) -i -P$(*:lex=)yy $< > $@ + + + +clean: + rm -f $(cmpp_OBJS) $(cmpp_GEN) cmpp diff --git a/src/xspice/cmpp/cmpp.h b/src/xspice/cmpp/cmpp.h new file mode 100755 index 000000000..0a15c0e68 --- /dev/null +++ b/src/xspice/cmpp/cmpp.h @@ -0,0 +1,285 @@ +/*============================================================================ +FILE cmpp.h + +MEMBER OF process cmpp + +Copyright 1991 +Georgia Tech Research Corporation +Atlanta, Georgia 30332 +All Rights Reserved + +PROJECT A-8503 + +AUTHORS + + 9/12/91 Bill Kuhn + +MODIFICATIONS + + + +SUMMARY + + This file contains shared constants, type definitions, + and function prototypes used in the cmpp process. + +INTERFACES + + None. + +REFERENCED FILES + + None. + +NON-STANDARD FEATURES + + None. + +============================================================================*/ + + +#include + +#define IFSPEC_FILENAME "ifspec.ifs" +#define UDNFUNC_FILENAME "udnfunc.c" +#define MODPATH_FILENAME "modpath.lst" +#define UDNPATH_FILENAME "udnpath.lst" + +/* *********************************************************************** */ + +typedef enum { + + OK, /* Returned with no error */ + ERROR, /* Returned with error */ + +} Status_t; + + + +#define GET_IFS_TABLE 0 /* Read the entire ifs table */ +#define GET_IFS_NAME 1 /* Get the C function name out of the table only */ + +#define MAX_PATH_LEN 1024 /* Maximum pathname length */ +#define MAX_NAME_LEN 1024 /* Maximum SPICE name length */ +#define MAX_FN_LEN 31 /* Maximum filename length */ + + +/* ******************************************************************** */ +/* Structures used by parser to check for valid connections/parameters */ +/* ******************************************************************** */ + +/* + * The boolean type + */ + +typedef enum { + FALSE, + TRUE, +} Boolean_t; + + +/* + * The direction of a connector + */ + +typedef enum { + IN, + OUT, + INOUT, +} Dir_t; + + +/* + * The type of a port + */ + +typedef enum { + VOLTAGE, /* v - Single-ended voltage */ + DIFF_VOLTAGE, /* vd - Differential voltage */ + CURRENT, /* i - Single-ended current */ + DIFF_CURRENT, /* id - Differential current */ + VSOURCE_CURRENT, /* vnam - Vsource name for input current */ + CONDUCTANCE, /* g - Single-ended VCIS */ + DIFF_CONDUCTANCE, /* gd - Differential VCIS */ + RESISTANCE, /* h - Single-ended ICVS */ + DIFF_RESISTANCE, /* hd - Differential ICVS */ + DIGITAL, /* d - Digital */ + USER_DEFINED, /* - Any user defined type */ +} Port_Type_t; + + + +/* + * The type of a parameter or Static_Var + */ + +typedef enum { + BOOLEAN, + INTEGER, + REAL, + COMPLEX, + STRING, + POINTER, /* NOTE: POINTER should not be used for Parameters - only + * Static_Vars - this is enforced by the cmpp. + */ + } Data_Type_t; + + + +/* + * The complex type + */ + +typedef struct { + double real; + double imag; +} Complex_t; + + + +/* + * Values of different types. + * + * Note that a struct is used instead of a union for conformity + * with the use of the Mif_Value_t type in the simulator where + * the type must be statically initialized. ANSI C does not + * support useful initialization of unions. + * + */ + +typedef struct { + + Boolean_t bvalue; /* For BOOLEAN parameters */ + int ivalue; /* For INTEGER parameters */ + double rvalue; /* For REAL parameters */ + Complex_t cvalue; /* For COMPLEX parameters */ + char *svalue; /* For STRING parameters */ + +} Value_t; + + + +/* + * Information about the model as a whole + */ + + +typedef struct { + + char *c_fcn_name; /* Name used in the C function */ + char *model_name; /* Name used in a spice deck */ + char *description; /* Description of the model */ + +} Name_Info_t; + + + + +/* + * Information about a connection + */ + + +typedef struct { + + char *name; /* Name of this connection */ + char *description; /* Description of this connection */ + Dir_t direction; /* IN, OUT, or INOUT */ + Port_Type_t default_port_type; /* The default port type */ + char *default_type; /* The default type in string form */ + int num_allowed_types; /* The size of the allowed type arrays */ + Port_Type_t *allowed_port_type; /* Array of allowed types */ + char **allowed_type; /* Array of allowed types in string form */ + Boolean_t is_array; /* True if connection is an array */ + Boolean_t has_conn_ref; /* True if there is associated with an array conn */ + int conn_ref; /* Subscript of the associated array conn */ + Boolean_t has_lower_bound; /* True if there is an array size lower bound */ + int lower_bound; /* Array size lower bound */ + Boolean_t has_upper_bound; /* True if there is an array size upper bound */ + int upper_bound; /* Array size upper bound */ + Boolean_t null_allowed; /* True if null is allowed for this connection */ + +} Conn_Info_t; + + + + +/* + * Information about a parameter + */ + +typedef struct { + + char *name; /* Name of this parameter */ + char *description; /* Description of this parameter */ + Data_Type_t type; /* Data type, e.g. REAL, INTEGER, ... */ + Boolean_t has_default; /* True if there is a default value */ + Value_t default_value; /* The default value */ + Boolean_t has_lower_limit; /* True if there is a lower limit */ + Value_t lower_limit; /* The lower limit for this parameter */ + Boolean_t has_upper_limit; /* True if there is a upper limit */ + Value_t upper_limit; /* The upper limit for this parameter */ + Boolean_t is_array; /* True if parameter is an array */ + Boolean_t has_conn_ref; /* True if there is associated with an array conn */ + int conn_ref; /* Subscript of the associated array conn */ + Boolean_t has_lower_bound; /* True if there is an array size lower bound */ + int lower_bound; /* Array size lower bound */ + Boolean_t has_upper_bound; /* True if there is an array size upper bound */ + int upper_bound; /* Array size upper bound */ + Boolean_t null_allowed; /* True if null is allowed for this parameter */ + +} Param_Info_t; + + +/* + * Information about an instance variable + */ + +typedef struct { + + char *name; /* Name of this parameter */ + char *description; /* Description of this parameter */ + Data_Type_t type; /* Data type, e.g. REAL, INTEGER, ... */ + Boolean_t is_array; /* True if parameter is an array */ + +} Inst_Var_Info_t; + + + +/* + * The all encompassing structure for the ifs table information + */ + +typedef struct { + + Name_Info_t name; /* The name table entries */ + int num_conn; /* Number of entries in the connection table(s) */ + Conn_Info_t *conn; /* Array of connection info structs */ + int num_param; /* Number of entries in the parameter table(s) */ + 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 */ + +} Ifs_Table_t; + + + +/* *********************************************************************** */ + + + +void preprocess_ifs_file(void); + +void preprocess_lst_files(void); + +void preprocess_mod_file(char *filename); + + +void print_error(char *message); + + +Status_t read_ifs_file(char *filename, int mode, Ifs_Table_t *ifs_table); + +Status_t write_ifs_c_file(char *filename, Ifs_Table_t *ifs_table); + + diff --git a/src/xspice/cmpp/ifs_lex.l b/src/xspice/cmpp/ifs_lex.l new file mode 100755 index 000000000..8a96365e9 --- /dev/null +++ b/src/xspice/cmpp/ifs_lex.l @@ -0,0 +1,176 @@ +%option yylineno +%option noyywrap +%{ /* $Id$ */ + +/*============================================================================ +FILE ifs_lex.l + +MEMBER OF process cmpp + +Copyright 1991 +Georgia Tech Research Corporation +Atlanta, Georgia 30332 +All Rights Reserved + +PROJECT A-8503 + +AUTHORS + + 9/12/91 Steve Tynor + +MODIFICATIONS + + 12/31/91 Bill Kuhn Change "array" to "vector" and "array_bounds" + to "vector_bounds". + +SUMMARY + + This file defines tokens applicable to parsing the ifspec.ifs + file, and actions to be taken on encountering those tokens. + +INTERFACES + + None. + +REFERENCED FILES + + ifs_yacc.y + +NON-STANDARD FEATURES + + None. + +============================================================================*/ + +#include "ifs_yacc.h" +#include "ifs_tok.h" + +int yyival; +double yydval; +extern int atoi(); +extern double atof(); + +/* + * IFS specs are case insensitive: + */ + +/* saj - use -i flex command line option +#undef input +#define input() (((yytchar=yysptr>yysbuf?U(*--yysptr):getc(yyin))==10?(yylineno++,yytchar):yytchar)==EOF?0:isupper(yytchar)?tolower(yytchar):yytchar) +*/ + +/*---------------------------------------------------------------------------*/ + +%} + +%start BOOL CTYPE DIR DTYPE + +%x comment stringl + +%p 5000 + +W [ \t\n] +A [_a-z] +D [0-9] +I [a-z_] +Z [0-9a-z_] +E [eE][+-]?{D}+ + +%% + +"/*" { BEGIN(comment); } + +[^*\n]* /* eat anything that's not a '*' */ + +"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ + +\n /* new line */ + +<> {ifs_yyerror ("Unterminated comment"); yyterminate(); } + +"*"+"/" { BEGIN(INITIAL); } + +"\"" { BEGIN(stringl); } + +[^\"]* { return TOK_STRING_LITERAL; } + +"\"" { BEGIN(INITIAL); } + +<> {ifs_yyerror ("Unterminated string literal"); + yyterminate(); } + +allowed_types{W}*: {BEGIN CTYPE; return TOK_ALLOWED_TYPES;} +vector{W}*: {BEGIN BOOL; return TOK_ARRAY;} +vector_bounds{W}*: {return TOK_ARRAY_BOUNDS;} +c_function_name{W}*: {return TOK_C_FUNCTION_NAME;} +port_name{W}*: {return TOK_PORT_NAME;} +port_table{W}*: {return TOK_PORT_TABLE;} +data_type{W}*: {BEGIN DTYPE; return TOK_DATA_TYPE;} +default_type{W}*: {BEGIN CTYPE; return TOK_DEFAULT_TYPE;} +default_value{W}*: {return TOK_DEFAULT_VALUE;} +description{W}*: {return TOK_DESCRIPTION;} +direction{W}*: {BEGIN DIR; return TOK_DIRECTION;} +static_var_name{W}*: {return TOK_STATIC_VAR_NAME;} +static_var_table{W}*: {return TOK_STATIC_VAR_TABLE;} +limits{W}*: {return TOK_LIMITS;} +name_table{W}*: {return TOK_NAME_TABLE;} +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;} + +yes {return TOK_BOOL_YES;} +no {return TOK_BOOL_NO;} +true {return TOK_BOOL_YES;} +false {return TOK_BOOL_NO;} + +v {return TOK_CTYPE_V;} +vd {return TOK_CTYPE_VD;} +vnam {return TOK_CTYPE_VNAM;} +i {return TOK_CTYPE_I;} +id {return TOK_CTYPE_ID;} +g {return TOK_CTYPE_G;} +gd {return TOK_CTYPE_GD;} +h {return TOK_CTYPE_H;} +hd {return TOK_CTYPE_HD;} +d {return TOK_CTYPE_D;} + +in {return TOK_DIR_IN;} +out {return TOK_DIR_OUT;} +inout {return TOK_DIR_INOUT;} + +real {return TOK_DTYPE_REAL;} +int {return TOK_DTYPE_INT;} +boolean {return TOK_DTYPE_BOOLEAN;} +complex {return TOK_DTYPE_COMPLEX;} +string {return TOK_DTYPE_STRING;} +pointer {return TOK_DTYPE_POINTER;} + +"<" {return TOK_LANGLE;} +">" {return TOK_RANGLE;} +"[" {return TOK_LBRACKET;} +"]" {return TOK_RBRACKET;} +"," {return TOK_COMMA;} +"-" {return TOK_DASH;} + + +{I}+{Z}* {return TOK_IDENTIFIER;} + +[+-]?{D}+ {yyival = atoi (yytext); + return TOK_INT_LITERAL;} + +[+-]?{D}+"."{D}*({E})? | +[+-]?{D}*"."{D}+({E})? | +[+-]?{D}+({E})? {yydval = atof (yytext); + return TOK_REAL_LITERAL;} + +. ; /* ignore anything else */ +\n ; /* ignore anything else */ + +%% + +/*--------------------------------------------------------------------------*/ +void reset_lex_context () +{ + BEGIN 0; +} diff --git a/src/xspice/cmpp/ifs_yacc.h b/src/xspice/cmpp/ifs_yacc.h new file mode 100755 index 000000000..611e9a786 --- /dev/null +++ b/src/xspice/cmpp/ifs_yacc.h @@ -0,0 +1,81 @@ +/* $Id$ */ + +/*============================================================================ +FILE ifs_yacc.h + +MEMBER OF process cmpp + +Copyright 1991 +Georgia Tech Research Corporation +Atlanta, Georgia 30332 +All Rights Reserved + +PROJECT A-8503 + +AUTHORS + + 9/12/91 Steve Tynor + +MODIFICATIONS + + + +SUMMARY + + Typedefs needed by the YYSTYPE union (%union operator) in the yacc + file. These are only used in the yacc file, but must be defined here since + the generated token.h file includes a definition of the union YYSTYPE. + +INTERFACES + + None. + +REFERENCED FILES + + None. + +NON-STANDARD FEATURES + + None. + +============================================================================*/ + +#include "cmpp.h" + +typedef struct { + Boolean_t has_value; + Data_Type_t kind; + union { + Boolean_t bvalue; + int ivalue; + double rvalue; + Complex_t cvalue; + char *svalue; + } u; +} My_Value_t; + +typedef struct { + Boolean_t has_bound; + My_Value_t bound; +} Bound_t; + +typedef struct { + Boolean_t is_named; + union { + char *name; + struct { + Bound_t upper; + Bound_t lower; + } bounds; + } u; +} Range_t; + +typedef struct { + Port_Type_t kind; + char *id; /* undefined unless kind == USER_DEFINED */ +} My_Port_Type_t; + +typedef struct ctype_list_s { + My_Port_Type_t ctype; + struct ctype_list_s *next; +} Ctype_List_t; diff --git a/src/xspice/cmpp/ifs_yacc.y b/src/xspice/cmpp/ifs_yacc.y new file mode 100755 index 000000000..03767a362 --- /dev/null +++ b/src/xspice/cmpp/ifs_yacc.y @@ -0,0 +1,901 @@ +%{ /* $Id$ */ + +/*============================================================================ +FILE ifs_yacc.y + +MEMBER OF process cmpp + +Copyright 1991 +Georgia Tech Research Corporation +Atlanta, Georgia 30332 +All Rights Reserved + +PROJECT A-8503 + +AUTHORS + + 9/12/91 Steve Tynor + +MODIFICATIONS + + 12/31/91 Bill Kuhn Fix bug in usage of strcmp in check_default_type() + +SUMMARY + + This file contains the BNF specification of the language used in + the ifspec.ifs file together with various support functions, + and parses the ifspec.ifs file to get the information from it + and place this information into a data structure + of type Ifs_Table_t. + +INTERFACES + + yyparse() - Generated automatically by UNIX 'yacc' utility. + +REFERENCED FILES + + ifs_lex.l + +NON-STANDARD FEATURES + + None. + +============================================================================*/ + +#include +#include "ifs_yacc.h" + +extern int yylineno; +extern int yyival; +extern double yydval; +extern char *ifs_yytext; +extern char *strdup(); + +Boolean_t parser_just_names; +static Boolean_t saw_model_name; +static Boolean_t saw_function_name; + +static char *dtype_to_str[] = { + "BOOLEAN", "INTEGER", "REAL", "COMPLEX", "STRING", "POINTER" + }; + +static Boolean_t did_default_type; +static Boolean_t did_allowed_types; + +static int num_items; +static int item; +static int item_offset; +static Boolean_t num_items_fixed; + +Ifs_Table_t *parser_ifs_table; +#define TBL parser_ifs_table + +static int alloced_size [4]; + +/* + * !!!!! 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 +#define GROW_SIZE 10 + +typedef enum { + TBL_NAME, + TBL_PORT, + TBL_PARAMETER, + TBL_STATIC_VAR, +} Table_t; + +typedef struct { + Table_t table; + int record; +} Context_t; + +Context_t context; + +#define ITEM_BUFFER_SIZE 20 /* number of items that can be put in a table + * before requiring a new xxx_TABLE: keyword + */ +#define FOR_ITEM(i) for (i = item_offset; i < num_items; i++) +#define ITEM_BUF(i) item_buffer[i-item_offset] + +#define ASSIGN_BOUNDS(struct_name, i) \ + if (ITEM_BUF(i).range.is_named) {\ + TBL->struct_name[i].has_conn_ref = TRUE;\ + TBL->struct_name[i].conn_ref = find_conn_ref (ITEM_BUF(i).range.u.name);\ + } else {\ + TBL->struct_name[i].has_conn_ref = FALSE;\ + TBL->struct_name[i].has_lower_bound =\ + ITEM_BUF(i).range.u.bounds.lower.has_bound;\ + TBL->struct_name[i].has_upper_bound =\ + ITEM_BUF(i).range.u.bounds.upper.has_bound;\ + if (TBL->struct_name[i].has_lower_bound) {\ + assert (ITEM_BUF(i).range.u.bounds.lower.bound.kind == INTEGER);\ + TBL->struct_name[i].lower_bound =\ + ITEM_BUF(i).range.u.bounds.lower.bound.u.ivalue;\ + }\ + if (TBL->struct_name[i].has_upper_bound) {\ + assert (ITEM_BUF(i).range.u.bounds.upper.bound.kind == INTEGER);\ + TBL->struct_name[i].upper_bound =\ + ITEM_BUF(i).range.u.bounds.upper.bound.u.ivalue;\ + }\ + } + +/*---------------------------------------------------------------------------*/ +static void fatal (char *str) +{ + yyerror (str); + exit(1); +} + +/*---------------------------------------------------------------------------*/ +static int find_conn_ref (name) + char *name; +{ + int i; + char str[130]; + + for (i = 0; i < TBL->num_conn; i++) { + if (strcmp (name, TBL->conn[i].name) == 0) { + return i; + } + } + sprintf (str, "Port `%s' not found", name); + yyerror (str); +} + +typedef enum {C_DOUBLE, C_BOOLEAN, C_POINTER, C_UNDEF} Ctype_Class_t; + +/*---------------------------------------------------------------------------*/ +static Ctype_Class_t get_ctype_class (Port_Type_t type) +{ + switch (type) { + case USER_DEFINED: + return C_POINTER; + break; + case DIGITAL: + return C_BOOLEAN; + break; + default: + return C_DOUBLE; + break; + } +} + +/*---------------------------------------------------------------------------*/ +static void check_port_type_direction (Dir_t dir, Port_Type_t port_type) +{ + switch (port_type) { + case VOLTAGE: + case DIFF_VOLTAGE: + case CURRENT: + case DIFF_CURRENT: + case DIGITAL: + case USER_DEFINED: + /* + * anything goes + */ + break; + case VSOURCE_CURRENT: + if (dir != IN) { + yyerror ("Port type `vnam' is only valid for `in' ports"); + } + break; + case CONDUCTANCE: + case DIFF_CONDUCTANCE: + case RESISTANCE: + case DIFF_RESISTANCE: + if (dir != INOUT) { + yyerror ("Port types `g', `gd', `h', `hd' are only valid for `inout' ports"); + } + break; + default: + assert (0); + } +} + +/*---------------------------------------------------------------------------*/ +static void check_dtype_not_pointer (Data_Type_t dtype) +{ + if (dtype == POINTER) { + yyerror("Invalid parameter type - POINTER type valid only for STATIC_VARs"); + } +} + +/*---------------------------------------------------------------------------*/ +static void check_default_type (Conn_Info_t conn) +{ + int i; + + for (i = 0; i < conn.num_allowed_types; i++) { + if (conn.default_port_type == conn.allowed_port_type[i]) { + if ((conn.default_port_type != USER_DEFINED) || + (strcmp (conn.default_type, conn.allowed_type[i]) == 0)) { + return; + } + } + } + yyerror ("Port default type is not an allowed type"); +} + +/*---------------------------------------------------------------------------*/ +static void assign_ctype_list (conn, ctype_list) + Conn_Info_t *conn; + Ctype_List_t *ctype_list; +{ + int i; + Ctype_List_t *p; + Ctype_Class_t class = C_UNDEF; + + conn->num_allowed_types = 0; + for (p = ctype_list; p; p = p->next) { + conn->num_allowed_types++; + } + conn->allowed_type = (char**) calloc (conn->num_allowed_types, + sizeof (char*)); + conn->allowed_port_type = (Port_Type_t*) calloc (conn->num_allowed_types, + sizeof (Port_Type_t)); + if (! (conn->allowed_type && conn->allowed_port_type)) { + fatal ("Could not allocate memory"); + } + for (i = conn->num_allowed_types-1, p = ctype_list; p; i--, p = p->next) { + if (class == C_UNDEF) { + class = get_ctype_class (p->ctype.kind); + } + if (class != get_ctype_class (p->ctype.kind)) { + yyerror ("Incompatible port types in `allowed_types' clause"); + } + check_port_type_direction (conn->direction, p->ctype.kind); + + conn->allowed_port_type[i] = p->ctype.kind; + conn->allowed_type[i] = p->ctype.id; + } +} + +/*---------------------------------------------------------------------------*/ +static void assign_value (type, dest_value, src_value) + Data_Type_t type; + Value_t *dest_value; + My_Value_t src_value; +{ + char str[200]; + if ((type == REAL) && (src_value.kind == INTEGER)) { + dest_value->rvalue = src_value.u.ivalue; + return; + } else if (type != src_value.kind) { + sprintf (str, "Invalid parameter type (saw %s - expected %s)", + dtype_to_str[src_value.kind], + dtype_to_str[type] ); + yyerror (str); + } + switch (type) { + case BOOLEAN: + dest_value->bvalue = src_value.u.bvalue; + break; + case INTEGER: + dest_value->ivalue = src_value.u.ivalue; + break; + case REAL: + dest_value->rvalue = src_value.u.rvalue; + break; + case COMPLEX: + dest_value->cvalue = src_value.u.cvalue; + break; + case STRING: + dest_value->svalue = src_value.u.svalue; + break; + default: + yyerror ("INTERNAL ERROR - unexpected data type in `assign_value'"); + } +} + +/*---------------------------------------------------------------------------*/ +static void assign_limits (type, param, range) + Data_Type_t type; + Param_Info_t *param; + Range_t range; +{ + if (range.is_named) { + yyerror ("Named range not allowed for limits"); + } + param->has_lower_limit = range.u.bounds.lower.has_bound; + if (param->has_lower_limit) { + assign_value (type, ¶m->lower_limit, range.u.bounds.lower.bound); + } + param->has_upper_limit = range.u.bounds.upper.has_bound; + if (param->has_upper_limit) { + assign_value (type, ¶m->upper_limit, range.u.bounds.upper.bound); + } +} + +/*---------------------------------------------------------------------------*/ +static void check_item_num () +{ + if (item-item_offset >= ITEM_BUFFER_SIZE) { + fatal ("Too many items in table - split into sub-tables"); + } + if (item > alloced_size [context.table] ) { + switch (context.table) { + case TBL_NAME: + break; + case TBL_PORT: + alloced_size[context.table] += GROW_SIZE; + TBL->conn = (Conn_Info_t*) + realloc (TBL->conn, + alloced_size [context.table] * sizeof (Conn_Info_t)); + if (! TBL->conn) { + fatal ("Error allocating memory for port definition"); + } + break; + case TBL_PARAMETER: + alloced_size [context.table] += GROW_SIZE; + TBL->param = (Param_Info_t*) + realloc (TBL->param, + alloced_size [context.table] * sizeof (Param_Info_t)); + if (! TBL->param) { + fatal ("Error allocating memory for parameter definition"); + } + break; + case TBL_STATIC_VAR: + alloced_size [context.table] += GROW_SIZE; + TBL->inst_var = (Inst_Var_Info_t*) + realloc (TBL->inst_var, + alloced_size [context.table] * sizeof (Inst_Var_Info_t)); + if (! TBL->inst_var) { + fatal ("Error allocating memory for static variable definition"); + } + break; + } + } + item++; +} + +/*---------------------------------------------------------------------------*/ +static void check_end_item_num () +{ + if (num_items_fixed) { + if (item != num_items) { + char buf[200]; + sprintf + (buf, + "Wrong number of elements in sub-table (saw %d - expected %d)", + item - item_offset, + num_items - item_offset); + fatal (buf); + } + } else { + num_items = item; + num_items_fixed = TRUE; + switch (context.table) { + case TBL_NAME: + break; + case TBL_PORT: + TBL->num_conn = num_items; + break; + case TBL_PARAMETER: + TBL->num_param = num_items; + break; + case TBL_STATIC_VAR: + TBL->num_inst_var = num_items; + break; + } + } + item = item_offset; +} + +#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() + +%} + +%token TOK_ALLOWED_TYPES +%token TOK_ARRAY +%token TOK_ARRAY_BOUNDS +%token TOK_BOOL_NO +%token TOK_BOOL_YES +%token TOK_COMMA +%token TOK_PORT_NAME +%token TOK_PORT_TABLE +%token TOK_CTYPE_D +%token TOK_CTYPE_G +%token TOK_CTYPE_GD +%token TOK_CTYPE_H +%token TOK_CTYPE_HD +%token TOK_CTYPE_I +%token TOK_CTYPE_ID +%token TOK_CTYPE_V +%token TOK_CTYPE_VD +%token TOK_CTYPE_VNAM +%token TOK_C_FUNCTION_NAME +%token TOK_DASH +%token TOK_DATA_TYPE +%token TOK_DEFAULT_TYPE +%token TOK_DEFAULT_VALUE +%token TOK_DESCRIPTION +%token TOK_DIRECTION +%token TOK_DIR_IN +%token TOK_DIR_INOUT +%token TOK_DIR_OUT +%token TOK_DTYPE_BOOLEAN +%token TOK_DTYPE_COMPLEX +%token TOK_DTYPE_INT +%token TOK_DTYPE_POINTER +%token TOK_DTYPE_REAL +%token TOK_DTYPE_STRING +%token TOK_IDENTIFIER +%token TOK_STATIC_VAR_NAME +%token TOK_STATIC_VAR_TABLE +%token TOK_INT_LITERAL +%token TOK_LANGLE +%token TOK_LBRACKET +%token TOK_LIMITS +%token TOK_NAME_TABLE +%token TOK_NULL_ALLOWED +%token TOK_PARAMETER_NAME +%token TOK_PARAMETER_TABLE +%token TOK_RANGLE +%token TOK_RBRACKET +%token TOK_REAL_LITERAL +%token TOK_SPICE_MODEL_NAME +%token TOK_STRING_LITERAL + +%union { + Ctype_List_t *ctype_list; + Dir_t dir; + Boolean_t bool; + Range_t range; + Data_Type_t dtype; + My_Port_Type_t ctype; + My_Value_t value; + char *str; + Bound_t bound; + int ival; + double rval; + Complex_t cval; +} + +%type ctype_list delimited_ctype_list +%type direction +%type ctype +%type dtype +%type range int_range +%type value number integer_value value_or_dash +%type identifier string +%type bool +%type int_or_dash number_or_dash +%type integer +%type real +%type complex + +%start ifs_file + +%{ +/* + * resuse the Yacc union for our buffer: + */ +YYSTYPE item_buffer [ITEM_BUFFER_SIZE]; + +/* + * Shorthand for refering to the current element of the item buffer: + */ +#define BUF ITEM_BUF(item-1) + +%} + +%% + +ifs_file : {TBL->num_conn = 0; + TBL->num_param = 0; + TBL->num_inst_var = 0; + + saw_function_name = FALSE; + saw_model_name = FALSE; + + alloced_size [TBL_PORT] = DEFAULT_SIZE_CONN; + alloced_size [TBL_PARAMETER] = DEFAULT_SIZE_PARAM; + alloced_size [TBL_STATIC_VAR] = + DEFAULT_SIZE_INST_VAR; + + 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)); + 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) ) { + fatal ("Could not allocate enough memory"); + } + } + list_of_tables + ; + +list_of_tables : table + | list_of_tables table + ; + +table : TOK_NAME_TABLE + {context.table = TBL_NAME;} + name_table + | TOK_PORT_TABLE + {context.table = TBL_PORT; + did_default_type = FALSE; + did_allowed_types = FALSE; + INIT (TBL->num_conn);} + port_table + {TBL->num_conn = num_items;} + | TOK_PARAMETER_TABLE + {context.table = TBL_PARAMETER; + INIT (TBL->num_param);} + parameter_table + {TBL->num_param = num_items;} + | TOK_STATIC_VAR_TABLE + {context.table = TBL_STATIC_VAR; + INIT (TBL->num_inst_var);} + static_var_table + {TBL->num_inst_var = num_items;} + ; + +name_table : /* empty */ + | name_table name_table_item + ; + +name_table_item : TOK_C_FUNCTION_NAME identifier + {TBL->name.c_fcn_name =strdup (ifs_yytext); + saw_function_name = TRUE; + if (parser_just_names && saw_model_name) return 0;} + | TOK_SPICE_MODEL_NAME identifier + {TBL->name.model_name = strdup (ifs_yytext); + saw_model_name = TRUE; + if (parser_just_names && saw_function_name) return 0;} + | TOK_DESCRIPTION string + {TBL->name.description = strdup (ifs_yytext);} + ; + +port_table : /* empty */ + | port_table port_table_item + ; + +port_table_item : TOK_PORT_NAME list_of_ids + {int i; + END; + FOR_ITEM (i) { + TBL->conn[i].name = ITEM_BUF(i).str; + }} + | TOK_DESCRIPTION list_of_strings + {int i; + END; + FOR_ITEM (i) { + TBL->conn[i].description = ITEM_BUF(i).str; + }} + | TOK_DIRECTION list_of_directions + {int i; + END; + FOR_ITEM (i) { + TBL->conn[i].direction = ITEM_BUF(i).dir; + }} + | TOK_DEFAULT_TYPE list_of_ctypes + {int i; + END; + did_default_type = TRUE; + FOR_ITEM (i) { + TBL->conn[i].default_port_type = + ITEM_BUF(i).ctype.kind; + TBL->conn[i].default_type = ITEM_BUF(i).ctype.id; + if (did_allowed_types) { + check_default_type (TBL->conn[i]); + } + }} + | TOK_ALLOWED_TYPES list_of_ctype_lists + {int i; + END; + did_allowed_types = TRUE; + FOR_ITEM (i) { + assign_ctype_list (&TBL->conn[i], + ITEM_BUF(i).ctype_list); + if (did_default_type) { + check_default_type (TBL->conn[i]); + } + }} + | TOK_ARRAY list_of_bool + {int i; + END; + FOR_ITEM (i) { + TBL->conn[i].is_array = ITEM_BUF(i).bool; + }} + | TOK_ARRAY_BOUNDS list_of_array_bounds + {int i; + END; + FOR_ITEM (i) { + ASSIGN_BOUNDS (conn, i); + assert (!TBL->conn[i].has_conn_ref); + }} + | TOK_NULL_ALLOWED list_of_bool + {int i; + END; + FOR_ITEM (i) { + TBL->conn[i].null_allowed = ITEM_BUF(i).bool; + }} + ; + +parameter_table : /* empty */ + | parameter_table parameter_table_item + ; + +parameter_table_item : TOK_PARAMETER_NAME list_of_ids + {int i; + END; + FOR_ITEM (i) { + TBL->param[i].name = ITEM_BUF(i).str; + }} + | TOK_DESCRIPTION list_of_strings + {int i; + END; + FOR_ITEM (i) { + TBL->param[i].description = ITEM_BUF(i).str; + }} + | TOK_DATA_TYPE list_of_dtypes + {int i; + END; + FOR_ITEM (i) { + 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_LIMITS list_of_ranges + {int i; + END; + FOR_ITEM (i) { + assign_limits (TBL->param[i].type, + &TBL->param[i], + ITEM_BUF(i).range); + }} + | TOK_ARRAY list_of_bool + {int i; + END; + FOR_ITEM (i) { + TBL->param[i].is_array = ITEM_BUF(i).bool; + }} + | TOK_ARRAY_BOUNDS list_of_array_bounds + {int i; + END; + FOR_ITEM (i) { + ASSIGN_BOUNDS (param, i); + }} + | TOK_NULL_ALLOWED list_of_bool + {int i; + END; + FOR_ITEM (i) { + TBL->param[i].null_allowed = ITEM_BUF(i).bool; + }} + ; + +static_var_table : /* empty */ + | static_var_table static_var_table_item + ; + +static_var_table_item : TOK_STATIC_VAR_NAME list_of_ids + {int i; + END; + FOR_ITEM (i) { + TBL->inst_var[i].name = ITEM_BUF(i).str; + }} + | TOK_DESCRIPTION list_of_strings + {int i; + END; + FOR_ITEM (i) { + TBL->inst_var[i].description = ITEM_BUF(i).str; + }} + | TOK_DATA_TYPE list_of_dtypes + {int i; + END; + FOR_ITEM (i) { + TBL->inst_var[i].type = ITEM_BUF(i).dtype; + }} + | TOK_ARRAY list_of_bool + {int i; + END; + FOR_ITEM (i) { + TBL->inst_var[i].is_array = ITEM_BUF(i).bool; + }} + ; + +list_of_ids : /* empty */ + | list_of_ids identifier {ITEM; BUF.str = $2;} + ; + +list_of_array_bounds : /* empty */ + | list_of_array_bounds int_range + {ITEM; + BUF.range = $2;} + | list_of_array_bounds identifier + {ITEM; + BUF.range.is_named = TRUE; + BUF.range.u.name = $2;} + ; + +list_of_strings : /* empty */ + | list_of_strings string {ITEM; BUF.str = $2;} + ; + +list_of_directions : /* empty */ + | list_of_directions direction {ITEM; BUF.dir = $2;} + ; + +direction : TOK_DIR_IN {$$ = IN;} + | TOK_DIR_OUT {$$ = OUT;} + | TOK_DIR_INOUT {$$ = INOUT;} + ; + +list_of_bool : /* empty */ + | list_of_bool bool {ITEM; BUF.bool = $2;} + ; + +list_of_ctypes : /* empty */ + | list_of_ctypes ctype {ITEM; BUF.ctype = $2;} + ; + +ctype : TOK_CTYPE_V {$$.kind = VOLTAGE;} + | TOK_CTYPE_VD {$$.kind = DIFF_VOLTAGE;} + | TOK_CTYPE_VNAM {$$.kind = VSOURCE_CURRENT;} + | TOK_CTYPE_I {$$.kind = CURRENT;} + | TOK_CTYPE_ID {$$.kind = DIFF_CURRENT;} + | TOK_CTYPE_G {$$.kind = CONDUCTANCE;} + | TOK_CTYPE_GD {$$.kind = DIFF_CONDUCTANCE;} + | TOK_CTYPE_H {$$.kind = RESISTANCE;} + | TOK_CTYPE_HD {$$.kind = DIFF_RESISTANCE;} + | TOK_CTYPE_D {$$.kind = DIGITAL;} + | identifier {$$.kind = USER_DEFINED; + $$.id = $1;} + ; + +list_of_dtypes : /* empty */ + | list_of_dtypes dtype {ITEM; BUF.dtype = $2;} + ; + +dtype : TOK_DTYPE_REAL {$$ = REAL;} + | TOK_DTYPE_INT {$$ = INTEGER;} + | TOK_DTYPE_BOOLEAN {$$ = BOOLEAN;} + | TOK_DTYPE_COMPLEX {$$ = COMPLEX;} + | TOK_DTYPE_STRING {$$ = STRING;} + | TOK_DTYPE_POINTER {$$ = POINTER;} + ; + +list_of_ranges : /* empty */ + | list_of_ranges range {ITEM; BUF.range = $2;} + ; + +int_range : TOK_DASH {$$.is_named = FALSE; + $$.u.bounds.lower.has_bound = FALSE; + $$.u.bounds.upper.has_bound = FALSE;} + | TOK_LBRACKET int_or_dash maybe_comma int_or_dash + TOK_RBRACKET + {$$.is_named = FALSE; + $$.u.bounds.lower = $2; + $$.u.bounds.upper = $4;} + ; + +maybe_comma : /* empty */ + | TOK_COMMA + ; + +int_or_dash : TOK_DASH {$$.has_bound = FALSE;} + | integer_value {$$.has_bound = TRUE; + $$.bound = $1;} + ; + +range : TOK_DASH {$$.is_named = FALSE; + $$.u.bounds.lower.has_bound = FALSE; + $$.u.bounds.upper.has_bound = FALSE;} + | TOK_LBRACKET number_or_dash maybe_comma + number_or_dash TOK_RBRACKET + {$$.is_named = FALSE; + $$.u.bounds.lower = $2; + $$.u.bounds.upper = $4;} + ; + +number_or_dash : TOK_DASH {$$.has_bound = FALSE;} + | number {$$.has_bound = TRUE; + $$.bound = $1;} + ; + +list_of_values : /* empty */ + | list_of_values value_or_dash {ITEM; BUF.value = $2;} + ; + +value_or_dash : TOK_DASH {$$.has_value = FALSE;} + | value + ; + +value : string {$$.has_value = TRUE; + $$.kind = STRING; + $$.u.svalue = $1;} + | bool {$$.has_value = TRUE; + $$.kind = BOOLEAN; + $$.u.bvalue = $1;} + | complex {$$.has_value = TRUE; + $$.kind = COMPLEX; + $$.u.cvalue = $1;} + | number + ; + +complex : TOK_LANGLE real maybe_comma real TOK_RANGLE + {$$.real = $2; + $$.imag = $4;} + ; + +list_of_ctype_lists : /* empty */ + | list_of_ctype_lists delimited_ctype_list + {ITEM; BUF.ctype_list = $2;} + ; + +delimited_ctype_list : TOK_LBRACKET ctype_list TOK_RBRACKET {$$ = $2;} + ; + +ctype_list : ctype + {$$ = (Ctype_List_t*)calloc (1, + sizeof (Ctype_List_t)); + if (!$$) { + fatal ("Error allocating memory"); + } + $$->ctype = $1; + $$->next = (Ctype_List_t*)0;} + | ctype_list maybe_comma ctype + {$$ = (Ctype_List_t*)calloc (1, + sizeof (Ctype_List_t)); + if (!$$) { + fatal ("Error allocating memory"); + } + $$->ctype = $3; + $$->next = $1; + /*$$->next = (Ctype_List_t*)0; + assert ($1); + $1->next = $$;*/} + ; + +bool : TOK_BOOL_YES {$$ = TRUE;} + | TOK_BOOL_NO {$$ = FALSE;} + ; + +string : TOK_STRING_LITERAL {$$ = strdup(ifs_yytext);} + ; + +identifier : TOK_IDENTIFIER {$$ = strdup(ifs_yytext);} + ; + +number : real {$$.has_value = TRUE; + $$.kind = REAL; + $$.u.rvalue = $1;} + | integer_value + ; + +integer_value : integer {$$.has_value = TRUE; + $$.kind = INTEGER; + $$.u.ivalue = $1;} + ; + +real : TOK_REAL_LITERAL {$$ = yydval;} + ; + +integer : TOK_INT_LITERAL {$$ = yyival;} + ; + +%% diff --git a/src/xspice/cmpp/main.c b/src/xspice/cmpp/main.c new file mode 100755 index 000000000..20d796fb2 --- /dev/null +++ b/src/xspice/cmpp/main.c @@ -0,0 +1,125 @@ +/*============================================================================ +FILE main.c + +MEMBER OF process cmpp + +Copyright 1991 +Georgia Tech Research Corporation +Atlanta, Georgia 30332 +All Rights Reserved + +PROJECT A-8503 + +AUTHORS + + 9/12/91 Bill Kuhn + +MODIFICATIONS + + + +SUMMARY + + This file contains the top-level function for the Code Model + PreProcessor (cmpp). It handles reading the command-line + arguments, and then vectors to an appropriate function. + +INTERFACES + + main() + +REFERENCED FILES + + None. + +NON-STANDARD FEATURES + + None. + +============================================================================*/ + +#include +#include "cmpp.h" + + +#define USAGE_MSG "Usage: cmpp [-ifs] [-mod []] [-lst]" +#define TOO_FEW_ARGS "ERROR - Too few arguments" +#define TOO_MANY_ARGS "ERROR - Too many arguments" +#define UNRECOGNIZED_ARGS "ERROR - Unrecognized argument" + + + +/* *********************************************************************** */ + + +/* +main + +Function main checks the validity of the command-line arguments +supplied when the program is invoked and calls one of the three +major functions as appropriate: + + preprocess_ifs_file Process Interface Specification File. + preprocess_mod_file Process Model Definition File. + preprocess_lst_file Process Pathname List Files. + +depending on the argument. +*/ + +main( + int argc, /* Number of command line arguments */ + char *argv[]) /* Command line argument text */ +{ + + init_error (argv[0]); + + /* Process command line arguments and vector to appropriate function */ + + if(argc < 2) { + print_error(TOO_FEW_ARGS); + print_error(USAGE_MSG); + exit(1); + } + + if(strcmp(argv[1],"-ifs") == 0) { + if(argc == 2) { + preprocess_ifs_file(); + } + else { + print_error(TOO_MANY_ARGS); + print_error(USAGE_MSG); + exit(1); + } + } + else if(strcmp(argv[1],"-lst") == 0) { + if(argc == 2) { + preprocess_lst_files(); + } + else { + print_error(TOO_MANY_ARGS); + print_error(USAGE_MSG); + exit(1); + } + } + else if(strcmp(argv[1],"-mod") == 0) { + if(argc == 2) { + preprocess_mod_file("cfunc.mod"); + } + else if(argc == 3) { + preprocess_mod_file(argv[2]); + } + else { + print_error(TOO_MANY_ARGS); + print_error(USAGE_MSG); + exit(1); + } + } + else { + print_error(UNRECOGNIZED_ARGS); + print_error(USAGE_MSG); + exit(1); + } + + exit(0); +} + diff --git a/src/xspice/cmpp/mod_lex.l b/src/xspice/cmpp/mod_lex.l new file mode 100755 index 000000000..f6d8c450b --- /dev/null +++ b/src/xspice/cmpp/mod_lex.l @@ -0,0 +1,108 @@ +%option yylineno +%option noyywrap +%array +%{ /* $Id$ */ + +/*============================================================================ +FILE mod_lex.l + +MEMBER OF process cmpp + +Copyright 1991 +Georgia Tech Research Corporation +Atlanta, Georgia 30332 +All Rights Reserved + +PROJECT A-8503 + +AUTHORS + + 9/12/91 Steve Tynor + +MODIFICATIONS + + + +SUMMARY + + This file defines tokens applicable to parsing the cfunc.mod + file, and actions to be taken on encountering those tokens. + +INTERFACES + + None. + +REFERENCED FILES + + mod_yacc.y + +NON-STANDARD FEATURES + + None. + +============================================================================*/ + +#include "mod_yacc.h" +#include "mod_tok.h" + +%} + +I [A-Za-z_] +Z [0-9A-Za-z_] + +%% + +"/*" {char ch, last_ch; + ECHO; /* a comment - repeat it */ + ch = '\0'; + do { + last_ch = ch; + ch = input(); + fputc(ch,mod_yyout); + } while (ch && !((last_ch == '*') && (ch == '/'))); + if (!ch) {mod_yyerror ("Unterminated comment");}} + +ARGS {return TOK_ARGS;} +INIT {return TOK_INIT;} +ANALYSIS {return TOK_ANALYSIS;} +NEW_TIMEPOINT {return TOK_NEW_TIMEPOINT;} +CALL_TYPE {return TOK_CALL_TYPE;} +TIME {return TOK_TIME;} +RAD_FREQ {return TOK_RAD_FREQ;} +TEMPERATURE {return TOK_TEMPERATURE;} +T {return TOK_T;} +LOAD {return TOK_LOAD;} +TOTAL_LOAD {return TOK_TOTAL_LOAD;} +MESSAGE {return TOK_MESSAGE;} +PARAM {return TOK_PARAM;} +PARAM_SIZE {return TOK_PARAM_SIZE;} +PARAM_NULL {return TOK_PARAM_NULL;} +PORT_SIZE {return TOK_PORT_SIZE;} +PORT_NULL {return TOK_PORT_NULL;} +PARTIAL {return TOK_PARTIAL;} +AC_GAIN {return TOK_AC_GAIN;} +OUTPUT_DELAY {return TOK_OUTPUT_DELAY;} +STATIC_VAR {return TOK_STATIC_VAR;} +STATIC_VAR_SIZE {return TOK_STATIC_VAR_SIZE;} +INPUT {return TOK_INPUT;} +INPUT_STATE {return TOK_INPUT_STATE;} +INPUT_TYPE {return TOK_INPUT_TYPE;} +INPUT_STRENGTH {return TOK_INPUT_STRENGTH;} +OUTPUT {return TOK_OUTPUT;} +OUTPUT_STATE {return TOK_OUTPUT_STATE;} +OUTPUT_STRENGTH {return TOK_OUTPUT_STRENGTH;} +OUTPUT_TYPE {return TOK_OUTPUT_TYPE;} +OUTPUT_CHANGED {return TOK_OUTPUT_CHANGED;} + +"(" {return TOK_LPAREN;} +")" {return TOK_RPAREN;} +"[" {return TOK_LBRACKET;} +"]" {return TOK_RBRACKET;} +"," {return TOK_COMMA;} + +{I}+{Z}* {return TOK_IDENTIFIER;} +[ \t] ECHO; /* just eat non-newline whitespace */ +\n ECHO; /* echo newlines */ +. {return TOK_MISC_C;} + +%% diff --git a/src/xspice/cmpp/mod_yacc.h b/src/xspice/cmpp/mod_yacc.h new file mode 100755 index 000000000..4e1a1bca4 --- /dev/null +++ b/src/xspice/cmpp/mod_yacc.h @@ -0,0 +1,49 @@ +/* $Id$ */ + +/*============================================================================ +FILE mod_yacc.h + +MEMBER OF process cmpp + +Copyright 1991 +Georgia Tech Research Corporation +Atlanta, Georgia 30332 +All Rights Reserved + +PROJECT A-8503 + +AUTHORS + + 9/12/91 Steve Tynor + +MODIFICATIONS + + + +SUMMARY + + Typedefs needed by the YYSTYPE union (%union operator) in the yacc + file. These are only used in the yacc file, but must be defined here since + the generated token.h file includes a definition of the union YYSTYPE. + +INTERFACES + + None. + +REFERENCED FILES + + None. + +NON-STANDARD FEATURES + + None. + +============================================================================*/ + +#include "cmpp.h" + +typedef struct { + char *id; + Boolean_t has_subscript; + char *subscript; +} Sub_Id_t; diff --git a/src/xspice/cmpp/mod_yacc.y b/src/xspice/cmpp/mod_yacc.y new file mode 100755 index 000000000..b16e6df35 --- /dev/null +++ b/src/xspice/cmpp/mod_yacc.y @@ -0,0 +1,566 @@ +%{ /* $Id$ */ + +/*============================================================================ +FILE mod_yacc.y + +MEMBER OF process cmpp + +Copyright 1991 +Georgia Tech Research Corporation +Atlanta, Georgia 30332 +All Rights Reserved + +PROJECT A-8503 + +AUTHORS + + 9/12/91 Steve Tynor + +MODIFICATIONS + + + +SUMMARY + + This file contains a BNF specification of the translation of + cfunc.mod files to cfunc.c files, together with various support + functions. + +INTERFACES + + mod_yyparse() - Function 'yyparse()' is generated automatically + by UNIX 'yacc' utility and then converted to + 'mod_yyparse()' by UNIX 'sed' utility under + direction of Makefile. + +REFERENCED FILES + + mod_lex.l + +NON-STANDARD FEATURES + + Names of functions generated by 'yacc' are translated by 'sed' + under direction of the Makefile to prevent collisions with + functions generated from ifs_yacc.y. + +============================================================================*/ + + +#include +#include +#include "mod_yacc.h" + +Ifs_Table_t *mod_ifs_table; + +extern char mod_yytext[]; +extern FILE* mod_yyout; + +/* saj - use standard includes */ +#include +#include +/* +extern char *strdup(char*); +extern int strlen(char*); +extern char *strcat(char*, char*); +*/ + +int mod_num_errors; + +#define BUFFER_SIZE 3000 +static char buffer [BUFFER_SIZE]; +static int buf_len; + +typedef enum {CONN, PARAM, STATIC_VAR} Id_Kind_t; + +/*--------------------------------------------------------------------------*/ +static char *subscript (Sub_Id_t sub_id) +{ + if (sub_id.has_subscript) { + return sub_id.subscript; + } else { + return "0"; + } +} + +/*--------------------------------------------------------------------------*/ +int strcmpi(s, t) + char *s; + char *t; + /* string compare - case insensitive */ +{ + for (; *s && t && tolower(*s) == tolower(*t); s++, t++); + if (*s && !*t) { + return 1; + } + if (!*s && *t) { + return -1; + } + if (! (*s || *t)) { + return 0; + } + return (tolower(*s) - tolower(*t)); +} + +/*---------------------------------------------------------------------------*/ +static void put_type (FILE *fp, Data_Type_t type) +{ + char ch; + + switch (type) { + case INTEGER: + ch = 'i'; + break; + case REAL: + ch = 'r'; + break; + case COMPLEX: + ch = 'c'; + break; + case BOOLEAN: + ch = 'b'; + break; + case STRING: + ch = 's'; + break; + case POINTER: + ch = 'p'; + break; + } + fprintf (fp, ".%cvalue", ch); +} + +/*---------------------------------------------------------------------------*/ +static void put_conn_type (FILE *fp, Port_Type_t type) +{ + char ch; + + switch (type) { + case USER_DEFINED: + ch = 'p'; + break; + case DIGITAL: + ch = 'p'; + break; + default: + ch = 'r'; + break; + } + fprintf (fp, ".%cvalue", ch); +} + +/*---------------------------------------------------------------------------*/ +static void check_dir (int conn_number, Dir_t dir, char *context) +{ + Dir_t conn_dir; + + if (conn_number >= 0) { + /* + * If negative, this is an invalid port ID and we've already issued + * an error. + */ + conn_dir = mod_ifs_table->conn[conn_number].direction; + if ((conn_dir != dir) && (conn_dir != INOUT)) { + char error_str[200]; + + sprintf (error_str, + "Direction of port `%s' in %s() is not %s or INOUT", + mod_ifs_table->conn[conn_number].name, context, + (dir == IN) ? "IN" : "OUT"); + yyerror (error_str); + mod_num_errors++; + } + } +} + +/*---------------------------------------------------------------------------*/ +static void check_subscript (Boolean_t formal, Boolean_t actual, + Boolean_t missing_actual_ok, + char *context, char *id) +{ + char error_str[200]; + + if ((formal && !actual) && !missing_actual_ok) { + sprintf (error_str, + "%s `%s' is an array - subscript required", + context, id); + yyerror (error_str); + mod_num_errors++; + return; + } else if (!formal && actual) { + sprintf (error_str, + "%s `%s' is not an array - subscript prohibited", + context, id); + yyerror (error_str); + mod_num_errors++; + return; + } +} + +/*---------------------------------------------------------------------------*/ +static int check_id (Sub_Id_t sub_id, Id_Kind_t kind, Boolean_t do_subscript) +{ + int i; + char error_str[200]; + + switch (kind) { + case CONN: + for (i = 0; i < mod_ifs_table->num_conn; i++) { + if (0 == strcmpi (sub_id.id, mod_ifs_table->conn[i].name)) { + if (do_subscript) { + check_subscript (mod_ifs_table->conn[i].is_array, + sub_id.has_subscript, FALSE, "Port", + sub_id.id); + } + return i; + } + } + break; + case PARAM: + for (i = 0; i < mod_ifs_table->num_param; i++) { + if (0 == strcmpi (sub_id.id, mod_ifs_table->param[i].name)) { + if (do_subscript) { + check_subscript (mod_ifs_table->param[i].is_array, + sub_id.has_subscript, FALSE, "Parameter", + sub_id.id); + } + return i; + } + } + break; + case STATIC_VAR: + for (i = 0; i < mod_ifs_table->num_inst_var; i++) { + if (0 == strcmpi (sub_id.id, mod_ifs_table->inst_var[i].name)) { + if (do_subscript) { + check_subscript (mod_ifs_table->inst_var[i].is_array, + sub_id.has_subscript, TRUE, + "Static Variable", + sub_id.id); + } + return i; + } + } + break; + } + + sprintf (error_str, "No %s named '%s'", + ((kind==CONN) + ? "port" + : ((kind==PARAM) + ? "parameter" + :"static variable")), + sub_id.id); + yyerror (error_str); + mod_num_errors++; + abort(); + return -1; +} + +/*---------------------------------------------------------------------------*/ +static int valid_id (Sub_Id_t sub_id, Id_Kind_t kind) +{ + return check_id (sub_id, kind, FALSE); +} + +/*---------------------------------------------------------------------------*/ +static int valid_subid (Sub_Id_t sub_id, Id_Kind_t kind) +{ + return check_id (sub_id, kind, TRUE); +} + +/*---------------------------------------------------------------------------*/ +static init_buffer () +{ + buf_len = 0; + buffer[0] = '\0'; +} + +/*---------------------------------------------------------------------------*/ +static append (char *str) +{ + int len = strlen (str); + if (len + buf_len > BUFFER_SIZE) { + yyerror ("Buffer overflow - try reducing the complexity of CM-macro array subscripts"); + exit (1); + } + (void)strcat (buffer,str); +} + +%} + +%union { + char *str; + Sub_Id_t sub_id; +} + +%type buffered_c_code +%type subscriptable_id id + +%token TOK_ARGS +%token TOK_INIT +%token TOK_ANALYSIS +%token TOK_NEW_TIMEPOINT +%token TOK_TIME +%token TOK_RAD_FREQ +%token TOK_TEMPERATURE +%token TOK_T +%token TOK_PARAM +%token TOK_PARAM_SIZE +%token TOK_PARAM_NULL +%token TOK_PORT_SIZE +%token TOK_PORT_NULL +%token TOK_PARTIAL +%token TOK_AC_GAIN +%token TOK_CHANGED +%token TOK_OUTPUT_DELAY +%token TOK_STATIC_VAR +%token TOK_STATIC_VAR_SIZE +%token TOK_INPUT +%token TOK_INPUT_STRENGTH +%token TOK_INPUT_STATE +%token TOK_INPUT_TYPE +%token TOK_OUTPUT +%token TOK_OUTPUT_CHANGED +%token TOK_OUTPUT_STRENGTH +%token TOK_OUTPUT_STATE +%token TOK_OUTPUT_TYPE +%token TOK_COMMA +%token TOK_LPAREN +%token TOK_RPAREN +%token TOK_LBRACKET +%token TOK_RBRACKET +%token TOK_MISC_C +%token TOK_IDENTIFIER +%token TOK_LOAD +%token TOK_TOTAL_LOAD +%token TOK_MESSAGE +%token TOK_CALL_TYPE + +%start mod_file + +%% + +mod_file : /* empty */ + | mod_file c_code + ; + +c_code : /* empty */ + | c_code c_char + | c_code macro + /*| TOK_RPAREN {yyerror ("Unmatched )"); YYERROR;} + | TOK_RBRACKET {yyerror ("Unmatched ]"); YYERROR;}*/ + ; + +buffered_c_code : {init_buffer();} buffered_c_code2 + {$$ = strdup (buffer);} + ; + +buffered_c_code2 : /* empty */ + | buffered_c_code2 buffered_c_char + ; + +buffered_c_char : TOK_IDENTIFIER {append (mod_yytext);} + | TOK_MISC_C {append (mod_yytext);} + | TOK_COMMA {append (mod_yytext);} + | TOK_LBRACKET + {append("[");} + buffered_c_code2 TOK_RBRACKET + {append("]");} + | TOK_LPAREN + {append("(");} + buffered_c_code2 TOK_RPAREN + {append(")");} + ; + +c_char : TOK_IDENTIFIER {fputs (mod_yytext, mod_yyout);} + | TOK_MISC_C {fputs (mod_yytext, mod_yyout);} + | TOK_COMMA {fputs (mod_yytext, mod_yyout);} + | TOK_LBRACKET + {putc ('[', mod_yyout);} + c_code TOK_RBRACKET + {putc (']', mod_yyout);} + | TOK_LPAREN + {putc ('(', mod_yyout);} + c_code TOK_RPAREN + {putc (')', mod_yyout);} + ; + +macro : TOK_INIT + {fprintf (mod_yyout, "private->circuit.init");} + | TOK_ARGS + {fprintf (mod_yyout, "Mif_Private_t *private");} + | TOK_ANALYSIS + {fprintf (mod_yyout, "private->circuit.anal_type");} + | TOK_NEW_TIMEPOINT + {fprintf (mod_yyout, "private->circuit.anal_init");} + | TOK_CALL_TYPE + {fprintf (mod_yyout, "private->circuit.call_type");} + | TOK_TIME + {fprintf (mod_yyout, "private->circuit.time");} + | TOK_RAD_FREQ + {fprintf (mod_yyout, "private->circuit.frequency");} + | TOK_TEMPERATURE + {fprintf (mod_yyout, "private->circuit.temperature");} + | TOK_T TOK_LPAREN buffered_c_code TOK_RPAREN + {fprintf (mod_yyout, "private->circuit.t[%s]", $3);} + | TOK_PARAM TOK_LPAREN subscriptable_id TOK_RPAREN + {int i = valid_subid ($3, PARAM); + fprintf (mod_yyout, "private->param[%d]->element[%s]", + i, subscript ($3)); + put_type (mod_yyout, mod_ifs_table->param[i].type); + } + | TOK_PARAM_SIZE TOK_LPAREN id TOK_RPAREN + {int i = valid_id ($3, PARAM); + fprintf (mod_yyout, "private->param[%d]->size", i);} + | TOK_PARAM_NULL TOK_LPAREN id TOK_RPAREN + {int i = valid_id ($3, PARAM); + fprintf (mod_yyout, "private->param[%d]->is_null", i);} + | TOK_PORT_SIZE TOK_LPAREN id TOK_RPAREN + {int i = valid_id ($3, CONN); + fprintf (mod_yyout, "private->conn[%d]->size", i);} + | TOK_PORT_NULL TOK_LPAREN id TOK_RPAREN + {int i = valid_id ($3, CONN); + fprintf (mod_yyout, "private->conn[%d]->is_null", i);} + | TOK_PARTIAL TOK_LPAREN subscriptable_id TOK_COMMA + subscriptable_id TOK_RPAREN + {int i = valid_subid ($3, CONN); + int j = valid_subid ($5, CONN); + check_dir (i, OUT, "PARTIAL"); + check_dir (j, IN, "PARTIAL"); + fprintf (mod_yyout, "private->conn[%d]->port[%s]->partial[%d].port[%s]", + i, subscript($3), j, subscript($5));} + | TOK_AC_GAIN TOK_LPAREN subscriptable_id TOK_COMMA + subscriptable_id TOK_RPAREN + {int i = valid_subid ($3, CONN); + int j = valid_subid ($5, CONN); + check_dir (i, OUT, "AC_GAIN"); + check_dir (j, IN, "AC_GAIN"); + fprintf (mod_yyout, + "private->conn[%d]->port[%s]->ac_gain[%d].port[%s]", + i, subscript($3), j, subscript($5));} + | TOK_STATIC_VAR TOK_LPAREN subscriptable_id TOK_RPAREN + {int i = valid_subid ($3, STATIC_VAR); + fprintf (mod_yyout, + "private->inst_var[%d]->element[%s]", + i, subscript($3)); + if (mod_ifs_table->inst_var[i].is_array + && !($3.has_subscript)) { + /* null - eg. for malloc lvalue */ + } else { + put_type (mod_yyout, + mod_ifs_table->inst_var[i].type); + } } + | TOK_STATIC_VAR_SIZE TOK_LPAREN id TOK_RPAREN + {int i = valid_subid ($3, STATIC_VAR); + fprintf (mod_yyout, "private->inst_var[%d]->size", + i, subscript($3));} + | TOK_OUTPUT_DELAY TOK_LPAREN subscriptable_id TOK_RPAREN + {int i = valid_subid ($3, CONN); + check_dir (i, OUT, "OUTPUT_DELAY"); + fprintf (mod_yyout, + "private->conn[%d]->port[%s]->delay", i, + subscript($3));} + | TOK_CHANGED TOK_LPAREN subscriptable_id TOK_RPAREN + {int i = valid_subid ($3, CONN); + check_dir (i, OUT, "CHANGED"); + fprintf (mod_yyout, + "private->conn[%d]->port[%s]->changed", i, + subscript($3));} + | TOK_INPUT TOK_LPAREN subscriptable_id TOK_RPAREN + {int i = valid_subid ($3, CONN); + check_dir (i, IN, "INPUT"); + fprintf (mod_yyout, + "private->conn[%d]->port[%s]->input", + i, subscript($3)); + put_conn_type (mod_yyout, + mod_ifs_table->conn[i].allowed_port_type[0]);} + | TOK_INPUT_TYPE TOK_LPAREN subscriptable_id TOK_RPAREN + {int i = valid_subid ($3, CONN); + check_dir (i, IN, "INPUT_TYPE"); + fprintf (mod_yyout, + "private->conn[%d]->port[%s]->type_str", + i, subscript($3)); } + | TOK_OUTPUT_TYPE TOK_LPAREN subscriptable_id TOK_RPAREN + {int i = valid_subid ($3, CONN); + check_dir (i, OUT, "OUTPUT_TYPE"); + fprintf (mod_yyout, + "private->conn[%d]->port[%s]->type_str", + i, subscript($3)); } + | TOK_INPUT_STRENGTH TOK_LPAREN subscriptable_id TOK_RPAREN + {int i = valid_subid ($3, CONN); + check_dir (i, IN, "INPUT_STRENGTH"); + fprintf (mod_yyout, + "((Digital_t*)(private->conn[%d]->port[%s]->input", + i, subscript($3)); + put_conn_type (mod_yyout, + mod_ifs_table->conn[i].allowed_port_type[0]); + fprintf (mod_yyout, "))->strength");} + | TOK_INPUT_STATE TOK_LPAREN subscriptable_id TOK_RPAREN + {int i = valid_subid ($3, CONN); + check_dir (i, IN, "INPUT_STATE"); + fprintf (mod_yyout, + "((Digital_t*)(private->conn[%d]->port[%s]->input", + i, subscript($3)); + put_conn_type (mod_yyout, + mod_ifs_table->conn[i].allowed_port_type[0]); + fprintf (mod_yyout, "))->state");} + | TOK_OUTPUT TOK_LPAREN subscriptable_id TOK_RPAREN + {int i = valid_subid ($3, CONN); + check_dir (i, OUT, "OUTPUT"); + fprintf (mod_yyout, + "private->conn[%d]->port[%s]->output", + i, subscript($3)); + put_conn_type (mod_yyout, + mod_ifs_table->conn[i].allowed_port_type[0]);} + | TOK_OUTPUT_STRENGTH TOK_LPAREN subscriptable_id TOK_RPAREN + {int i = valid_subid ($3, CONN); + check_dir (i, OUT, "OUTPUT_STRENGTH"); + fprintf (mod_yyout, + "((Digital_t*)(private->conn[%d]->port[%s]->output", + i, subscript($3)); + put_conn_type (mod_yyout, + mod_ifs_table->conn[i].allowed_port_type[0]); + fprintf (mod_yyout, "))->strength");} + | TOK_OUTPUT_STATE TOK_LPAREN subscriptable_id TOK_RPAREN + {int i = valid_subid ($3, CONN); + check_dir (i, OUT, "OUTPUT_STATE"); + fprintf (mod_yyout, + "((Digital_t*)(private->conn[%d]->port[%s]->output", + i, subscript($3)); + put_conn_type (mod_yyout, + mod_ifs_table->conn[i].allowed_port_type[0]); + fprintf (mod_yyout, "))->state");} + | TOK_OUTPUT_CHANGED TOK_LPAREN subscriptable_id TOK_RPAREN + {int i = valid_subid ($3, CONN); + fprintf (mod_yyout, + "private->conn[%d]->port[%s]->changed", i, + subscript($3));} + | TOK_LOAD TOK_LPAREN subscriptable_id TOK_RPAREN + {int i = valid_subid ($3, CONN); + fprintf (mod_yyout, + "private->conn[%d]->port[%s]->load", i, + subscript($3));} + | TOK_TOTAL_LOAD TOK_LPAREN subscriptable_id TOK_RPAREN + {int i = valid_subid ($3, CONN); + fprintf (mod_yyout, + "private->conn[%d]->port[%s]->total_load", i, + subscript($3));} + | TOK_MESSAGE TOK_LPAREN subscriptable_id TOK_RPAREN + {int i = valid_subid ($3, CONN); + fprintf (mod_yyout, + "private->conn[%d]->port[%s]->msg", i, + subscript($3));} + ; + +subscriptable_id : id + | id TOK_LBRACKET buffered_c_code TOK_RBRACKET + {$$ = $1; + $$.has_subscript = TRUE; + $$.subscript = $3;} + ; + +id : TOK_IDENTIFIER + {$$.has_subscript = FALSE; + $$.id = strdup (mod_yytext);} + ; + +%% diff --git a/src/xspice/cmpp/pp_ifs.c b/src/xspice/cmpp/pp_ifs.c new file mode 100755 index 000000000..c92d5adb7 --- /dev/null +++ b/src/xspice/cmpp/pp_ifs.c @@ -0,0 +1,88 @@ +/*============================================================================ +FILE pp_ifs.c + +MEMBER OF process cmpp + +Copyright 1991 +Georgia Tech Research Corporation +Atlanta, Georgia 30332 +All Rights Reserved + +PROJECT A-8503 + +AUTHORS + + 9/12/91 Bill Kuhn + +MODIFICATIONS + + + +SUMMARY + + This file contains the main function for processing an Interface Spec + File (ifspec.ifs). + +INTERFACES + + preprocess_ifs_file() + +REFERENCED FILES + + None. + +NON-STANDARD FEATURES + + None. + +============================================================================*/ + +#include "cmpp.h" + + + +/* *********************************************************************** */ + + +/* +preprocess_ifs_file + +Function preprocess_ifs_file is the top-level driver function for +preprocessing an Interface Specification file (ifspec.ifs). This +function calls read_ifs_file() requesting it to read and parse +the Interface Specification file and place the information +contained in it into an internal data structure. Then +write_ifs_c_file() is called to write the information out in a C +file that will be compiled and linked with the simulator. +*/ + + +void preprocess_ifs_file(void) +{ + + Ifs_Table_t ifs_table; /* Repository for info read from ifspec.ifs file */ + + Status_t status; /* Return status */ + + + /* Read the entire ifspec.ifs file and load the data into ifs_table */ + + status = read_ifs_file(IFSPEC_FILENAME,GET_IFS_TABLE,&ifs_table); + + if(status != OK) { + exit(1); + } + + + /* Write the ifspec.c file required by the spice simulator */ + + status = write_ifs_c_file("ifspec.c",&ifs_table); + + if(status != OK) { + exit(1); + } + +} + + + diff --git a/src/xspice/cmpp/pp_lst.c b/src/xspice/cmpp/pp_lst.c new file mode 100755 index 000000000..99f9495d5 --- /dev/null +++ b/src/xspice/cmpp/pp_lst.c @@ -0,0 +1,1082 @@ +/*============================================================================ +FILE pp_lst.c + +MEMBER OF process cmpp + +Copyright 1991 +Georgia Tech Research Corporation +Atlanta, Georgia 30332 +All Rights Reserved + +PROJECT A-8503 + +AUTHORS + + 9/12/91 Bill Kuhn + +MODIFICATIONS + + + +SUMMARY + + This file contains functions used in processing the files: + + modpath.lst + udnpath.lst + + The files 'modpath.lst' and 'udnpath.lst' are read to get + the pathnames to directories containing the models and node types + desired in the simulator to be built. Files in each of these + directories are then examined to get the names of functions and/or + data structures that the simulator must know about. The names + are then checked for uniqueness, and finally, a collection of + files needed in the 'make' for the simulator are written. + +INTERFACES + + preprocess_lst_files() + +REFERENCED FILES + + None. + +NON-STANDARD FEATURES + + None. + +============================================================================*/ + +#include "cmpp.h" +#include +#include + + +void *malloc(unsigned size); +void *realloc(void *ptr, unsigned size); + +/* *********************************************************************** */ + +/* + * Information for processing the pathname files + */ + +typedef struct { + char *path_name; /* Pathname read from model path file */ + char *spice_name; /* Name of model from ifspec.ifs */ + char *cfunc_name; /* Name of C fcn from ifspec.ifs */ + Boolean_t spice_unique; /* True if spice name unique */ + Boolean_t cfunc_unique; /* True if C fcn name unique */ +} Model_Info_t; + + +typedef struct { + char *path_name; /* Pathname read from udn path file */ + char *node_name; /* Name of node type */ + Boolean_t unique; /* True if node type name unique */ +} Node_Info_t; + + + +/* *********************************************************************** */ + + +static Status_t read_modpath(int *num_models, Model_Info_t **model_info); +static Status_t read_udnpath(int *num_nodes, Node_Info_t **node_info); +static Status_t read_model_names(int num_models, Model_Info_t *model_info); +static Status_t read_node_names(int num_nodes, Node_Info_t *node_info); +static Status_t check_uniqueness(int num_models, Model_Info_t *model_info, + int num_nodes, Node_Info_t *node_info); +static Status_t write_CMextrn(int num_models, Model_Info_t *model_info); +static Status_t write_CMinfo(int num_models, Model_Info_t *model_info); +static Status_t write_UDNextrn(int num_nodes, Node_Info_t *node_info); +static Status_t write_UDNinfo(int num_nodes, Node_Info_t *node_info); +static Status_t write_objects_inc(int num_models, Model_Info_t *model_info, + int num_nodes, Node_Info_t *node_info); +static Status_t read_udn_type_name(char *path, char **node_name); + + +/* *********************************************************************** */ + + +/* +preprocess_lst_files + +Function preprocess_lst_files is the top-level driver function for +preprocessing a simulator model path list file (modpath.lst). +This function calls read_ifs_file() requesting it to read and +parse the Interface Specification file (ifspec.ifs) to extract +the model name and associated C function name and place this +information into an internal data structure. It then calls +check_uniqueness() to verify that the model names and function +names are unique with respect to each other and to the models and +functions internal to SPICE 3C1. Following this check, it calls +write_CMextrn(), write_CMinfo(), and write_make_include() to +write out the C include files CMextrn.h and CMinfo.h required by +SPICE function SPIinit.c to define the models known to the +simulator, and to write out a make include file used by the make +utility to locate the object modules necessary to link the models +into the simulator. +*/ + +void preprocess_lst_files(void) +{ + Status_t status; /* Return status */ + Model_Info_t *model_info; /* Info about each model */ + Node_Info_t *node_info; /* Info about each user-defined node type */ + int num_models; /* The number of models */ + int num_nodes; /* The number of user-defined nodes */ + + + /* Get list of models from model pathname file */ + status = read_modpath(&num_models, &model_info); + if(status != OK) { + exit(1); + } + + /* Get list of node types from udn pathname file */ + status = read_udnpath(&num_nodes, &node_info); + if(status != OK) { + exit(1); + } + + + /* Get the spice and C function names from the ifspec.ifs files */ + status = read_model_names(num_models, model_info); + if(status != OK) { + exit(1); + } + + /* Get the user-defined node type names */ + status = read_node_names(num_nodes, node_info); + if(status != OK) { + exit(1); + } + + + /* Check to be sure the names are unique */ + status = check_uniqueness(num_models, model_info, + num_nodes, node_info); + if(status != OK) { + exit(1); + } + + + /* Write out the CMextrn.h file used to compile SPIinit.c */ + status = write_CMextrn(num_models, model_info); + if(status != OK) { + exit(1); + } + + /* Write out the CMinfo.h file used to compile SPIinit.c */ + status = write_CMinfo(num_models, model_info); + if(status != OK) { + exit(1); + } + + + /* Write out the UDNextrn.h file used to compile SPIinit.c */ + status = write_UDNextrn(num_nodes, node_info); + if(status != OK) { + exit(1); + } + + /* Write out the UDNinfo.h file used to compile SPIinit.c */ + status = write_UDNinfo(num_nodes, node_info); + if(status != OK) { + exit(1); + } + + + /* Write the make_include file used to link the models and */ + /* user-defined node functions with the simulator */ + status = write_objects_inc(num_models, model_info, + num_nodes, node_info); + if(status != OK) { + exit(1); + } + +} + + + +/* *********************************************************************** */ + + +/* +read_modpath + +This function opens the modpath.lst file, reads the pathnames from the +file, and puts them into an internal data structure for future +processing. +*/ + + +static Status_t read_modpath( + int *num_models, /* Number of model pathnames found */ + Model_Info_t **model_info /* Info about each model */ +) +{ + FILE *fp; /* Model pathname file pointer */ + char msg[MAX_PATH_LEN+257]; /* space for an error message */ + char path[MAX_PATH_LEN+2]; /* space to read pathnames into */ + Model_Info_t *model; /* temporary pointer to model info */ + + int n; + int i; + int j; + int len; + int line_num; + + static char *filename = MODPATH_FILENAME; + + + /* Initialize number of models to zero in case of error */ + *num_models = 0; + + /* Open the model pathname file */ + fp = fopen(filename, "r"); + + if(fp == NULL) { + sprintf(msg, "ERROR - File not found: %s", filename); + print_error(msg); + return(ERROR); + } + + /* Read the pathnames from the file, one line at a time until EOF */ + n = 0; + line_num = 0; + while( fgets(path, sizeof(path), fp) ) { + + line_num++; + len = strlen(path); + + /* If line was too long for buffer, exit with error */ + if(len > MAX_PATH_LEN) { + sprintf(msg, "ERROR - Line %d of %s exceeds %d characters", + line_num, filename, MAX_PATH_LEN); + print_error(msg); + return(ERROR); + } + + /* Strip white space including newline */ + for(i = 0, j = 0; i < len; ) { + if(isspace(path[i])) { + i++; + } + else { + path[j] = path[i]; + i++; + j++; + } + } + path[j] = '\0'; + len = j; + + /* Strip trailing '/' if any */ + if(path[len - 1] == '/') + path[--len] = '\0'; + + /* If blank line, continue */ + if(len == 0) + continue; + + /* Make sure pathname is short enough to add a filename at the end */ + if(len > (MAX_PATH_LEN - (MAX_FN_LEN + 1)) ) { + sprintf(msg, "ERROR - Pathname on line %d of %s exceeds %d characters", + line_num, filename, (MAX_PATH_LEN - (MAX_FN_LEN + 1))); + print_error(msg); + return(ERROR); + } + + /* Allocate and initialize a new model info structure */ + if(n == 0) + model = (void *) malloc(sizeof(Model_Info_t)); + else + model = (void *) realloc(model, (n + 1) * sizeof(Model_Info_t)); + model[n].path_name = NULL; + model[n].spice_name = NULL; + model[n].cfunc_name = NULL; + model[n].spice_unique = TRUE; + model[n].cfunc_unique = TRUE; + + /* Put pathname into info structure */ + model[n].path_name = malloc(len); + strcpy(model[n].path_name, path); + + /* Increment count of paths read */ + n++; + } + + + /* Close model pathname file and return data read */ + fclose(fp); + + *num_models = n; + *model_info = model; + + return(OK); + +} + + +/* *********************************************************************** */ + + +/* +read_udnpath + +This function opens the udnpath.lst file, reads the pathnames from the +file, and puts them into an internal data structure for future +processing. +*/ + + +static Status_t read_udnpath( + int *num_nodes, /* Number of node pathnames found */ + Node_Info_t **node_info /* Info about each node */ +) +{ + FILE *fp; /* Udn pathname file pointer */ + char msg[MAX_PATH_LEN+257]; /* space for an error message */ + char path[MAX_PATH_LEN+2]; /* space to read pathnames into */ + Node_Info_t *node; /* temporary pointer to node info */ + + int n; + int i; + int j; + int len; + int line_num; + + static char *filename = UDNPATH_FILENAME; + + + /* Initialize number of nodes to zero in case of error */ + *num_nodes = 0; + + /* Open the node pathname file */ + fp = fopen(filename, "r"); + + /* For backward compatibility, return with WARNING only if file not found */ + if(fp == NULL) { + sprintf(msg, "WARNING - File not found: %s", filename); + print_error(msg); + return(OK); + } + + /* Read the pathnames from the file, one line at a time until EOF */ + n = 0; + line_num = 0; + while( fgets(path, sizeof(path), fp) ) { + + line_num++; + len = strlen(path); + + /* If line was too long for buffer, exit with error */ + if(len > MAX_PATH_LEN) { + sprintf(msg, "ERROR - Line %d of %s exceeds %d characters", + line_num, filename, MAX_PATH_LEN); + print_error(msg); + return(ERROR); + } + + /* Strip white space including newline */ + for(i = 0, j = 0; i < len; ) { + if(isspace(path[i])) { + i++; + } + else { + path[j] = path[i]; + i++; + j++; + } + } + path[j] = '\0'; + len = j; + + /* Strip trailing '/' if any */ + if(path[len - 1] == '/') + path[--len] = '\0'; + + /* If blank line, continue */ + if(len == 0) + continue; + + /* Make sure pathname is short enough to add a filename at the end */ + if(len > (MAX_PATH_LEN - (MAX_FN_LEN + 1)) ) { + sprintf(msg, "ERROR - Pathname on line %d of %s exceeds %d characters", + line_num, filename, (MAX_PATH_LEN - (MAX_FN_LEN + 1))); + print_error(msg); + return(ERROR); + } + + /* Allocate and initialize a new node info structure */ + if(n == 0) + node = (void *) malloc(sizeof(Node_Info_t)); + else + node = (void *) realloc(node, (n + 1) * sizeof(Node_Info_t)); + node[n].path_name = NULL; + node[n].node_name = NULL; + node[n].unique = TRUE; + + /* Put pathname into info structure */ + node[n].path_name = malloc(len); + strcpy(node[n].path_name, path); + + /* Increment count of paths read */ + n++; + } + + + /* Close node pathname file and return data read */ + fclose(fp); + + *num_nodes = n; + *node_info = node; + + return(OK); + +} + + + +/* *********************************************************************** */ + + +/* +read_model_names + +This function opens each of the models and gets the names of the model +and the C function into the internal model information structure. +*/ + +static Status_t read_model_names( + int num_models, /* Number of model pathnames */ + Model_Info_t *model_info /* Info about each model */ +) +{ + Boolean_t all_found; /* True if all ifspec files read */ + int i; /* A temporary counter */ + char msg[MAX_PATH_LEN+257]; /* space for an error message */ + char path[MAX_PATH_LEN+1]; /* full pathname to ifspec file */ + Status_t status; /* Return status */ + Ifs_Table_t ifs_table; /* Repository for info read from ifspec file */ + + + /* For each model found in model pathname file, read the interface */ + /* spec file to get the SPICE and C function names into model_info */ + + for(i = 0, all_found = TRUE; i < num_models; i++) { + + /* Form the full pathname to the interface spec file */ + strcpy(path, model_info[i].path_name); + strcat(path, "/"); + strcat(path, IFSPEC_FILENAME); + + /* Read the SPICE and C function names from the interface spec file */ + status = read_ifs_file(path, GET_IFS_NAME, &ifs_table); + + /* Transfer the names into the model_info structure */ + if(status == OK) { + model_info[i].spice_name = ifs_table.name.model_name; + model_info[i].cfunc_name = ifs_table.name.c_fcn_name; + } + else { + all_found = FALSE; + sprintf(msg, "ERROR - Problems reading %s in directory %s", + IFSPEC_FILENAME, model_info[i].path_name); + print_error(msg); + } + } + + if(all_found) + return(OK); + else + return(ERROR); + +} + + +/* *********************************************************************** */ + + +/* +read_node_names + +This function opens each of the user-defined node definition files +and gets the names of the node into the internal information structure. +*/ + + +static Status_t read_node_names( + int num_nodes, /* Number of node pathnames */ + Node_Info_t *node_info /* Info about each node */ +) +{ + Boolean_t all_found; /* True if all files read OK */ + int i; /* A temporary counter */ + char msg[MAX_PATH_LEN+257]; /* space for an error message */ + char path[MAX_PATH_LEN+1]; /* full pathname to file */ + Status_t status; /* Return status */ + char *node_name; /* Name of node type read from file */ + + /* For each node found in node pathname file, read the udnfunc.c */ + /* file to get the node type names into node_info */ + + for(i = 0, all_found = TRUE; i < num_nodes; i++) { + + /* Form the full pathname to the interface spec file */ + strcpy(path, node_info[i].path_name); + strcat(path, "/"); + strcat(path, UDNFUNC_FILENAME); + + /* Read the udn node type name from the file */ + status = read_udn_type_name(path, &node_name); + + /* Transfer the names into the node_info structure */ + if(status == OK) { + node_info[i].node_name = node_name; + } + else { + all_found = FALSE; + sprintf(msg, "ERROR - Problems reading %s in directory %s", + UDNFUNC_FILENAME, node_info[i].path_name); + print_error(msg); + } + } + + if(all_found) + return(OK); + else + return(ERROR); + +} + + + +/* *********************************************************************** */ + + +/* +check_uniqueness + +Function check_uniqueness determines if model names and function +names are unique with respect to each other and to the models and +functions internal to SPICE 3C1. +*/ + +static Status_t check_uniqueness( + int num_models, /* Number of model pathnames */ + Model_Info_t *model_info, /* Info about each model */ + int num_nodes, /* Number of node type pathnames */ + Node_Info_t *node_info /* Info about each node type */ +) +{ + int i; /* A temporary counter */ + int j; /* A temporary counter */ + char msg[MAX_PATH_LEN+257]; /* space for an error message */ + Boolean_t all_unique; /* true if names are unique */ + + /* Define a list of model names used internally by XSPICE */ + /* These names (except 'poly') are defined in src/sim/INP/INPdomodel.c and */ + /* are case insensitive */ + static char *SPICEmodel[] = { "npn", + "pnp", + "d", + "njf", + "pjf", + "nmf", + "pmf", + "urc", + "nmos", + "pmos", + "r", + "c", + "sw", + "csw", + "poly" }; + static int numSPICEmodels = sizeof(SPICEmodel) / sizeof(char *); + + + /* Define a list of node type names used internally by the simulator */ + /* These names are defined in src/sim/include/MIFtypes.h and are case */ + /* insensitive */ + static char *UDNidentifier[] = { "v", + "vd", + "i", + "id", + "vnam", + "g", + "gd", + "h", + "hd", + "d" }; + static int numUDNidentifiers = sizeof(UDNidentifier) / sizeof(char *); + + + + /* First, normalize case of all model and node names to lower since */ + /* SPICE is case insensitive in parsing decks */ + for(i = 0; i < num_models; i++) + str_to_lower(model_info[i].spice_name); + for(i = 0; i < num_nodes; i++) + str_to_lower(node_info[i].node_name); + + /* Then, loop through all model names and report errors if same as SPICE */ + /* model name or same as another model name in list */ + for(i = 0, all_unique = TRUE; i < num_models; i++) { + + /* First check against list of SPICE internal names */ + for(j = 0; j < numSPICEmodels; j++) { + if(strcmp(model_info[i].spice_name, SPICEmodel[j]) == 0) { + all_unique = FALSE; + sprintf(msg, + "ERROR - Model name '%s' is same as internal SPICE model name\n", + model_info[i].spice_name); + print_error(msg); + } + } + + /* Skip if already seen once */ + if(model_info[i].spice_unique == FALSE) + continue; + + /* Then check against other names in list */ + for(j = 0; j < num_models; j++) { + + /* Skip checking against itself */ + if(i == j) + continue; + + /* Compare the names */ + if(strcmp(model_info[i].spice_name, model_info[j].spice_name) == 0) { + all_unique = FALSE; + model_info[i].spice_unique = FALSE; + model_info[j].spice_unique = FALSE; + sprintf(msg, + "ERROR - Model name '%s' in directory: %s", + model_info[i].spice_name, + model_info[i].path_name); + print_error(msg); + print_error(" is same as"); + sprintf(msg, + " model name '%s' in directory: %s\n", + model_info[j].spice_name, + model_info[j].path_name); + print_error(msg); + } + } + + } + + /* Loop through all C function names and report errors if duplicates found */ + for(i = 0; i < num_models; i++) { + + /* Skip if already seen once */ + if(model_info[i].cfunc_unique == FALSE) + continue; + + /* Check against other names in list only, not against SPICE identifiers */ + /* Let linker catch collisions with SPICE identifiers for now */ + for(j = 0; j < num_models; j++) { + + /* Skip checking against itself */ + if(i == j) + continue; + + /* Compare the names */ + if(strcmp(model_info[i].cfunc_name, model_info[j].cfunc_name) == 0) { + all_unique = FALSE; + model_info[i].cfunc_unique = FALSE; + model_info[j].cfunc_unique = FALSE; + sprintf(msg, + "ERROR - C function name '%s' in directory: %s", + model_info[i].cfunc_name, + model_info[i].path_name); + print_error(msg); + print_error(" is same as"); + sprintf(msg, + " C function name '%s' in directory: %s\n", + model_info[j].cfunc_name, + model_info[j].path_name); + print_error(msg); + } + } + + } + + /* Loop through all node type names and report errors if same as internal */ + /* name or same as another name in list */ + for(i = 0; i < num_nodes; i++) { + + /* First check against list of internal names */ + for(j = 0; j < numUDNidentifiers; j++) { + if(strcmp(node_info[i].node_name, UDNidentifier[j]) == 0) { + all_unique = FALSE; + sprintf(msg, + "ERROR - Node type '%s' is same as internal node type\n", + node_info[i].node_name); + print_error(msg); + } + } + + /* Skip if already seen once */ + if(node_info[i].unique == FALSE) + continue; + + /* Then check against other names in list */ + for(j = 0; j < num_nodes; j++) { + + /* Skip checking against itself */ + if(i == j) + continue; + + /* Compare the names */ + if(strcmp(node_info[i].node_name, node_info[j].node_name) == 0) { + all_unique = FALSE; + node_info[i].unique = FALSE; + node_info[j].unique = FALSE; + sprintf(msg, + "ERROR - Node type '%s' in directory: %s", + node_info[i].node_name, + node_info[i].path_name); + print_error(msg); + print_error(" is same as"); + sprintf(msg, + " node type '%s' in directory: %s\n", + node_info[j].node_name, + node_info[j].path_name); + print_error(msg); + } + } + } + + + /* Return error status */ + if(all_unique) + return(OK); + else + return(ERROR); + +} + + +/* *********************************************************************** */ + + +/* +write_CMextrn + +Function write_CMextrn writes the CMextrn.h file used in +compiling SPIinit.c immediately prior to linking the simulator +and code models. This SPICE source file uses the structures +mentioned in the include file to define the models known to the +simulator. +*/ + +static Status_t write_CMextrn( + int num_models, /* Number of model pathnames */ + Model_Info_t *model_info /* Info about each model */ +) +{ + int i; /* A temporary counter */ + FILE *fp; /* File pointer for writing CMextrn.h */ + + + /* Open the file to be written */ + fp = fopen("CMextrn.h", "w"); + if(fp == NULL) { + print_error("ERROR - Problems opening CMextrn.h for write"); + return(ERROR); + } + + /* Write out the data */ + for(i = 0; i < num_models; i++) { + fprintf(fp, "extern SPICEdev %s_info;\n", model_info[i].cfunc_name); + } + + /* Close the file and return */ + fclose(fp); + return(OK); +} + + +/* *********************************************************************** */ + + +/* +write_CMinfo + +Function write_CMinfo writes the CMinfo.h file used in compiling +SPIinit.c immediately prior to linking the simulator and code +models. This SPICE source file uses the structures mentioned in +the include file to define the models known to the simulator. +*/ + + +static Status_t write_CMinfo( + int num_models, /* Number of model pathnames */ + Model_Info_t *model_info /* Info about each model */ +) +{ + int i; /* A temporary counter */ + FILE *fp; /* File pointer for writing CMinfo.h */ + + + /* Open the file to be written */ + fp = fopen("CMinfo.h", "w"); + if(fp == NULL) { + print_error("ERROR - Problems opening CMinfo.h for write"); + return(ERROR); + } + + /* Write out the data */ + for(i = 0; i < num_models; i++) { + fprintf(fp, "&%s_info,\n", model_info[i].cfunc_name); + } + + /* Close the file and return */ + fclose(fp); + return(OK); +} + + + +/* *********************************************************************** */ + + + +/* +write_UDNextrn + +Function write_UDNextrn writes the UDNextrn.h file used in +compiling SPIinit.c immediately prior to linking the simulator +and user-defined nodes. This SPICE source file uses the structures +mentioned in the include file to define the node types known to the +simulator. +*/ + + + +static Status_t write_UDNextrn( + int num_nodes, /* Number of node pathnames */ + Node_Info_t *node_info /* Info about each node */ +) +{ + int i; /* A temporary counter */ + FILE *fp; /* File pointer for writing UDNextrn.h */ + + + /* Open the file to be written */ + fp = fopen("UDNextrn.h", "w"); + if(fp == NULL) { + print_error("ERROR - Problems opening UDNextrn.h for write"); + return(ERROR); + } + + /* Write out the data */ + for(i = 0; i < num_nodes; i++) { + fprintf(fp, "extern Evt_Udn_Info_t udn_%s_info;\n", node_info[i].node_name); + } + + /* Close the file and return */ + fclose(fp); + return(OK); +} + + +/* *********************************************************************** */ + + +/* +write_UDNinfo + +Function write_UDNinfo writes the UDNinfo.h file used in +compiling SPIinit.c immediately prior to linking the simulator +and user-defined nodes. This SPICE source file uses the structures +mentioned in the include file to define the node types known to the +simulator. +*/ + + + +static Status_t write_UDNinfo( + int num_nodes, /* Number of node pathnames */ + Node_Info_t *node_info /* Info about each node */ +) +{ + int i; /* A temporary counter */ + FILE *fp; /* File pointer for writing UDNinfo.h */ + + + /* Open the file to be written */ + fp = fopen("UDNinfo.h", "w"); + if(fp == NULL) { + print_error("ERROR - Problems opening UDNinfo.h for write"); + return(ERROR); + } + + /* Write out the data */ + for(i = 0; i < num_nodes; i++) { + fprintf(fp, "&udn_%s_info,\n", node_info[i].node_name); + } + + /* Close the file and return */ + fclose(fp); + return(OK); +} + + +/* *********************************************************************** */ + +/* +write_objects_inc + +Function write_objects_inc writes a make include file used by +the make utility to locate the object modules needed to link the +simulator with the code models and user-defined node types. +*/ + +static Status_t write_objects_inc( + int num_models, /* Number of model pathnames */ + Model_Info_t *model_info, /* Info about each model */ + int num_nodes, /* Number of udn pathnames */ + Node_Info_t *node_info /* Info about each node type */ +) +{ + int i; /* A temporary counter */ + FILE *fp; /* File pointer for writing make_include */ + + + /* Open the file to be written */ + fp = fopen("objects.inc", "w"); + if(fp == NULL) { + print_error("ERROR - Problems opening objects.inc file for write"); + return(ERROR); + } + + /* Write out the data */ + for(i = 0; i < num_models; i++) { + fprintf(fp, "%s/*.o", model_info[i].path_name); + if((i < (num_models - 1)) || (num_nodes > 0)) + fprintf(fp, " \\\n"); + else + fprintf(fp, "\n"); + } + for(i = 0; i < num_nodes; i++) { + fprintf(fp, "%s/*.o", node_info[i].path_name); + if(i < (num_nodes - 1)) + fprintf(fp, " \\\n"); + else + fprintf(fp, "\n"); + } + + /* Close the file and return */ + fclose(fp); + return(OK); +} + + +/* +read_udn_type_name + +This function reads a User-Defined Node Definition File until +the definition of the Evt_Udn_Info_t struct +is found, and then gets the name of the node type from the first +member of the structure. +*/ + +static Status_t read_udn_type_name( + char *path, /* the path to the node definition file */ + char **node_name /* the node type name found in the file */ +) +{ + FILE *fp; /* file pointer for opened file */ + char msg[MAX_PATH_LEN+257]; /* space for an error message */ + Boolean_t found; /* true if name found successfully */ + Boolean_t in_struct; /* true if found struct with name */ + char name[MAX_NAME_LEN + 1]; /* temporary storage for name read */ + int c; /* a character read from the file */ + int i; /* a counter */ + + static char *struct_type = "Evt_Udn_Info_t"; + + /* Open the file from which the node type name will be read */ + fp = fopen(path, "r"); + if(fp == NULL) + return(ERROR); + + /* Read the file until the definition of the Evt_Udn_Info_t struct */ + /* is found, then get the name of the node type from the first */ + /* member of the structure */ + found = FALSE; + do { + /* read the next character */ + c = fgetc(fp); + + /* check for and gobble up comments */ + if(c == '/') { + c = fgetc(fp); + if(c == '*') { + do { + c = fgetc(fp); + if(c == '*') { + c = fgetc(fp); + if((c == '/') || (c == EOF)) + break; + else + ungetc(c, fp); + } + } while(c != EOF); + } + } + if(c == EOF) + break; + + /* read until "Evt_Udn_Info_t" is encountered */ + for(i = 0, in_struct = FALSE; ; i++) { + if(c != struct_type[i]) + break; + else if(i == (sizeof(struct_type) - 2)) { + in_struct = TRUE; + break; + } + else + c = fgetc(fp); + } + /* if found it, read until open quote found */ + /* and then read the name until the closing quote is found */ + if(in_struct) { + do { + c = fgetc(fp); + if(c == '"') { + i = 0; + do { + c = fgetc(fp); + if(c == '"') { + found = TRUE; + name[i] = '\0'; + } + else if(c != EOF) + name[i++] = c; + } while((c != EOF) && (! found)); + } + } while((c != EOF) && (! found)); + } + + } while((c != EOF) && (! found)); + + /* Close the file and return */ + fclose(fp); + + if(found) { + *node_name = malloc(strlen(name) + 1); + strcpy(*node_name, name); + return(OK); + } + else { + *node_name = NULL; + return(ERROR); + } +} + diff --git a/src/xspice/cmpp/pp_mod.c b/src/xspice/cmpp/pp_mod.c new file mode 100755 index 000000000..845a88322 --- /dev/null +++ b/src/xspice/cmpp/pp_mod.c @@ -0,0 +1,180 @@ +/*============================================================================ +FILE pp_mod.c + +MEMBER OF process cmpp + +Copyright 1991 +Georgia Tech Research Corporation +Atlanta, Georgia 30332 +All Rights Reserved + +PROJECT A-8503 + +AUTHORS + + 9/12/91 Steve Tynor + +MODIFICATIONS + + + +SUMMARY + + This file contains the top-level driver function for preprocessing the + "cfunc.mod" file. First, the "ifspec.ifs" file is opened and parsed to + get the data that will be needed in the .mod to .c translation (See + read_ifs.c). Then the .mod file is translated. Most of the work of the + translation is handled by the UNIX 'lex' and 'yacc' utilities. This + translation is begun at the call to mod_yyparse() below. See also files: + + mod_lex.l + mod_yacc.y + + Note that to allow lex/yacc to be used twice (once for the ifspec.ifs + file, and then again for the cfunc.mod file), the functions created by + lex/yacc for the latter are translated using the UNIX text editor 'sed' + under the direction of the Makefile and the following 'sed scripts': + + mod_lex.sed + mod_yacc.sed + + Hence the call to 'mod_yyparse()' rather than 'yyparse()' below. + +INTERFACES + + preprocess_mod_file() + +REFERENCED FILES + + None. + +NON-STANDARD FEATURES + + None. + +============================================================================*/ + +#include "cmpp.h" + +/*---------------------------------------------------------------------------*/ +static void change_extension (char *filename, char *ext, char *new_filename) +{ + int i = strlen (filename); + + strcpy (new_filename, filename); + + for (; i >= 0; i--) { + if (new_filename[i] == '.') { + new_filename[i+1] = '\0'; + break; + } + } + strcat (new_filename, ext); +} + +/*---------------------------------------------------------------------------*/ + +/* +preprocess_mod_file + +Function preprocess_mod_file is the top-level driver function for +preprocessing a code model file (cfunc.mod). This function calls +read_ifs_file() requesting it to read and parse the Interface +Specification file (ifspec.ifs) and place the information +contained in it into an internal data structure. It then calls +mod_yyparse() to read the cfunc.mod file and translate it +according to the Interface Specification information. Function +mod_yyparse() is automatically generated by UNIX lex/yacc +utilities. +*/ + + +void preprocess_mod_file ( + char *filename) /* The file to read */ +{ + extern FILE *mod_yyin; + extern FILE *mod_yyout; + extern char *current_filename; + extern int mod_yylineno; + extern int mod_num_errors; + extern Ifs_Table_t *mod_ifs_table; + + Ifs_Table_t ifs_table; /* info read from ifspec.ifs file */ + Status_t status; /* Return status */ + char error_str[200]; + char output_filename[200]; + + /* + * Read the entire ifspec.ifs file and load the data into ifs_table + */ + + status = read_ifs_file (IFSPEC_FILENAME, GET_IFS_TABLE, &ifs_table); + + if (status != OK) { + exit(1); + } + + mod_yyin = fopen (filename, "r"); + if (mod_yyin == NULL) { + sprintf(error_str, "ERROR - Could not open input .mod file: %s", + filename); + print_error(error_str); + return; + } + + current_filename = filename; + + change_extension (filename, "c", output_filename); + mod_yyout = fopen (output_filename, "w"); + + if (mod_yyout == NULL) { + sprintf(error_str, "ERROR - Could not open output .c: %s", + output_filename); + print_error(error_str); + return; + } + + mod_ifs_table = &ifs_table; + mod_num_errors = 0; + + fprintf (mod_yyout, "#line 1 \"%s\"\n", filename); + fprintf (mod_yyout, "#include \"cm.h\"\n"); + fprintf (mod_yyout, "#line 1 \"%s\"\n", filename); + + mod_yylineno = 1; + if (!mod_yyin) { + sprintf (error_str, "Could not open .mod file: \"%s\"", filename); + print_error (error_str); + unlink (output_filename); + exit(1); + } + if (!mod_yyout) { + sprintf (error_str, "Could not create .c file: \"%s\"", + output_filename); + print_error (error_str); + unlink (output_filename); + exit(1); + } + + if (mod_yyparse() || (mod_num_errors > 0)) { + sprintf (error_str, "Error parsing .mod file: \"%s\"", filename); + print_error (error_str); + unlink (output_filename); + exit (1); + } + fclose (mod_yyout); +} + +/*---------------------------------------------------------------------------*/ +int mod_yyerror (str) + char *str; +{ + extern int mod_yylineno; + extern char mod_yytext[]; + extern char *current_filename; + extern char *prog_name; + + fprintf (stderr, "%s: Error: \"%s\": line %d (near \'%s\'):\n\t%s.\n", + prog_name, current_filename, mod_yylineno, mod_yytext, str); +} + diff --git a/src/xspice/cmpp/read_ifs.c b/src/xspice/cmpp/read_ifs.c new file mode 100755 index 000000000..40071f5ce --- /dev/null +++ b/src/xspice/cmpp/read_ifs.c @@ -0,0 +1,173 @@ +/*============================================================================ +FILE read_ifs.c + +MEMBER OF process cmpp + +Copyright 1991 +Georgia Tech Research Corporation +Atlanta, Georgia 30332 +All Rights Reserved + +PROJECT A-8503 + +AUTHORS + + 9/12/91 Bill Kuhn and Steve Tynor + +MODIFICATIONS + + + +SUMMARY + + This file contains top-level functions used in reading information + from the ifspec.ifs file and building an internal data structure that + holds the information. Most of the work in parsing of the + ifspec.ifs file and in building the structure is handled by + the UNIX 'lex' and 'yacc' utilities. This processing is begun + at the call to yyparse() in read_ifs_table() below. See also files: + + ifs_lex.l + ifs_yacc.y + +INTERFACES + + read_ifs_file() + yywrap() + yyerror() + +REFERENCED FILES + + None. + +NON-STANDARD FEATURES + + None. + +============================================================================*/ + +#include +#include "cmpp.h" + +extern char *prog_name; + +void *malloc(unsigned size); + +static Status_t read_ifs_table(FILE *fp, int mode, Ifs_Table_t *ifs_table); + +char *current_filename; + +/* *********************************************************************** */ + + +/* + NOTE + + The following function may be called either by cmpp -ifs or cmpp -lst with + mode set to GET_IFS_TABLE or GET_IFS_NAME respectively. + */ + + +/* +read_ifs_file + +Function read_ifs_file() opens the Interface Specification file +(ifspec.ifs) for read access and calls read_ifs_table() with the +assigned file pointer to read and parse the file. Upon return +from read_ifs_table(), the file is closed. +*/ + + + +Status_t read_ifs_file( + char *filename, /* File to read */ + int mode, /* Get names only or get everything? */ + Ifs_Table_t *ifs_table) /* Table to put info in */ +{ + + FILE *fp; /* Ifs file pointer */ + + char msg[MAX_PATH_LEN+257]; /* space for an error message */ + + Status_t status; /* returned status from function */ + + + /* Open the ifs file for read access */ + + fp = fopen(filename, "r"); + + if(fp == NULL) { + perror (prog_name); + sprintf(msg, "ERROR - File not found: %s", filename); + print_error(msg); + return(ERROR); + } + + current_filename = filename; + + /* Get the stuff from the file into the ifs_table struct */ + + status = read_ifs_table(fp, mode, ifs_table); + + /* Close file and return */ + + fclose(fp); + + return(status); + +} + + + + +/* *********************************************************************** */ + + +/* +read_ifs_table + +Function read_ifs_table() calls yyparse() to read and parse the +Interface Specification file contents and place the information +into an internal data structure. Function yyparse() is +automatically generated by UNIX lex/yacc. +*/ + + + +static Status_t read_ifs_table( + FILE *fp, /* File to read from */ + int mode, /* Get names only or get everything? */ + Ifs_Table_t *ifs_table) /* Table to put info in */ +{ + + extern FILE *ifs_yyin; + extern Ifs_Table_t *parser_ifs_table; + extern Boolean_t parser_just_names; + extern int ifs_yylineno; + + assert (ifs_table); + assert (fp); + + ifs_yylineno = 1; + ifs_yyin = fp; + parser_just_names = (mode == GET_IFS_NAME); + parser_ifs_table = ifs_table; + + if (ifs_yyparse()) { + print_error ("Error parsing interface specification file"); + return ERROR; + } + return OK; +} + +/*---------------------------------------------------------------------------*/ +int ifs_yyerror (str) + char *str; +{ + extern int ifs_yylineno; + extern char ifs_yytext[]; + + fprintf (stderr, "%s: Error: \"%s\": line %d (near \'%s\'):\n\t%s.\n", + prog_name, current_filename, ifs_yylineno, ifs_yytext, str); +} + diff --git a/src/xspice/cmpp/util.c b/src/xspice/cmpp/util.c new file mode 100755 index 000000000..9ff8b6dd1 --- /dev/null +++ b/src/xspice/cmpp/util.c @@ -0,0 +1,87 @@ +/*============================================================================ +FILE util.c + +MEMBER OF process cmpp + +Copyright 1991 +Georgia Tech Research Corporation +Atlanta, Georgia 30332 +All Rights Reserved + +PROJECT A-8503 + +AUTHORS + + 9/12/91 Bill Kuhn and Steve Tynor + +MODIFICATIONS + + + +SUMMARY + + This file contains miscellaneous utility functions used in cmpp. + +INTERFACES + + init_error() + print_error() + str_to_lower() + +REFERENCED FILES + + None. + +NON-STANDARD FEATURES + + None. + +============================================================================*/ + +#include "cmpp.h" +#include +#include +#include + + + +/* *********************************************************************** */ + +char *prog_name; + + +/* Initialize print_error() with the name of the program */ + +void init_error (char *program_name) +{ + prog_name = program_name; +} + + + +/* Print an error message to stderr */ + +void print_error( + char *msg) /* The message to write */ +{ + fprintf(stderr, "%s: %s\n", prog_name, msg); +} + + + +/* Convert a string to all lower case */ + +str_to_lower(s) + +char *s; /* The string to convert */ +{ + int i; + char c; + + for(i = 0; (c = s[i]) != '\0'; i++) + if(isalpha(c)) + if(isupper(c)) + s[i] = tolower(c); +} + + diff --git a/src/xspice/cmpp/writ_ifs.c b/src/xspice/cmpp/writ_ifs.c new file mode 100755 index 000000000..2608f0ae3 --- /dev/null +++ b/src/xspice/cmpp/writ_ifs.c @@ -0,0 +1,1291 @@ +/*============================================================================ +FILE writ_ifs.c + +MEMBER OF process cmpp + +Copyright 1991 +Georgia Tech Research Corporation +Atlanta, Georgia 30332 +All Rights Reserved + +PROJECT A-8503 + +AUTHORS + + 9/12/91 Bill Kuhn + +MODIFICATIONS + + + +SUMMARY + + This file contains functions used to write out the file "ifspec.c" + based on information read from "ifspec.ifs", which is now held in + structure 'ifs_table' passed to write_ifs_c_file(). + +INTERFACES + + write_ifs_c_file() + +REFERENCED FILES + + None. + +NON-STANDARD FEATURES + + None. + +============================================================================*/ + + +#include +#include "cmpp.h" + +/* Explicitly prototype malloc and free. BSD has no header file for this */ + +void *malloc(unsigned size); +void *realloc(void *ptr, unsigned size); +void free(void *ptr); + + +/* Local function prototypes */ + +static void write_comment(FILE *fp, Ifs_Table_t *ifs_table); + +static void write_includes(FILE *fp); + +static void write_mPTable(FILE *fp, Ifs_Table_t *ifs_table); + +static void write_pTable(FILE *fp, Ifs_Table_t *ifs_table); + +static void write_conn_info(FILE *fp, Ifs_Table_t *ifs_table); + +static void write_param_info(FILE *fp, Ifs_Table_t *ifs_table); + +static void write_inst_var_info(FILE *fp, Ifs_Table_t *ifs_table); + +static void write_SPICEdev(FILE *fp, Ifs_Table_t *ifs_table); + + + +static char *data_type_to_str(Data_Type_t type); + +static char *port_type_to_str(Port_Type_t port); + +static char *dir_to_str(Dir_t dir); + +static char *value_to_str(Data_Type_t type, Value_t value); + +static char *no_value_to_str(void); + +static char *boolean_to_str(Boolean_t value); + +static char *integer_to_str(int value); + +static char *gen_port_type_str(Port_Type_t port); + + + +/* *********************************************************************** */ + + + +/* +write_ifs_c_file + +Function write_ifs_c_file is a top-level driver function for +creating a C file (ifspec.c) that defines the model Interface +Specification in a form usable by the simulator. The ifspec.c +output file is opened for writing, and then each of the following +functions is called in order to write the necessary statements +and data structures into the file: + + write_comment + write_includes + write_mPTable + write_conn_info + write_param_info + write_inst_var_info + write_SPICEdev + +The output file is then closed. +*/ + + + +Status_t write_ifs_c_file( + char *filename, /* File to write to */ + Ifs_Table_t *ifs_table) /* Table of Interface Specification data */ +{ + FILE *fp; /* File pointer */ + char msg[MAX_PATH_LEN+257]; /* space for an error message */ + int int_status; /* returned status from fclose */ + + + /* Open the ifspec.c file for write access */ + + fp = fopen(filename, "w"); + + if(fp == NULL) { + sprintf(msg, "ERROR - Can't create file: %s", filename); + print_error(msg); + return(ERROR); + } + + + /* Write out a comment section at the top of the file */ + write_comment(fp, ifs_table); + + /* Put in the # includes */ + write_includes(fp); + + /* Write the SPICE3 required XXXmPTable structure */ + write_mPTable(fp, ifs_table); + + /* Write the SPICE3 required XXXpTable structure */ + write_pTable(fp, ifs_table); + + /* Write out the connector table required for the code model element parser */ + write_conn_info(fp, ifs_table); + + /* Write out the parameter table required for the code model element parser */ + write_param_info(fp, ifs_table); + + /* Write out the instance variable table required for the code model element parser */ + write_inst_var_info(fp, ifs_table); + + /* Write out the externally visible structure for this model */ + write_SPICEdev(fp, ifs_table); + + + /* Close the ifspec.c file and return */ + + int_status = fclose(fp); + + if(int_status == 0) + return(OK); + else + return(ERROR); +} + + + +/* *********************************************************************** */ + + +/* +write_comment + +Function write_comment places a comment at the top of the +ifspec.c file warning the user that this file is automatically +generated and should not be edited. +*/ + + +static void write_comment( + FILE *fp, /* File to write to */ + Ifs_Table_t *ifs_table) /* Table of Interface Specification data */ +{ + fprintf(fp, "\n"); + fprintf(fp, "/*\n"); + fprintf(fp, " * Structures for model: %s\n", ifs_table->name.model_name); + fprintf(fp, " *\n"); + fprintf(fp, " * Automatically generated by cmpp preprocessor\n"); + fprintf(fp, " *\n"); + fprintf(fp, " * !!! DO NOT EDIT !!!\n"); + fprintf(fp, " *\n"); + fprintf(fp, " */\n"); + fprintf(fp, "\n"); +} + + +/* *********************************************************************** */ + +/* +write_includes + +Function write_includes writes the C header files required in +ifspec.c. +*/ + + +static void write_includes( + FILE *fp) /* File to write to */ +{ + fprintf(fp, "\n"); + fprintf(fp, "#include \"ngspice.h\" \n"); +/* fprintf(fp, "#include \"prefix.h\" \n");*/ + fprintf(fp, "#include \n"); + fprintf(fp, "#include \"devdefs.h\" \n"); + fprintf(fp, "#include \"ifsim.h\" \n"); + fprintf(fp, "#include \"mifdefs.h\" \n"); + fprintf(fp, "#include \"mifproto.h\" \n"); + fprintf(fp, "#include \"mifparse.h\" \n"); +/* fprintf(fp, "#include \"suffix.h\" \n");*/ + fprintf(fp, "\n"); +} + + +/* *********************************************************************** */ + + + +/* +write_pTable + +Function write_pTable writes the instance parameter information +using SPICE's IFparm structure type. This table defines the +parameters as output only variables using SPICE's ``OP'' macro. +These instance parameters are derived from the Interface +Specification file's STATIC_VAR table and define the parameters +that can be queried using the SPICE 3C1 .save feature. +*/ + + +static void write_pTable( + FILE *fp, /* File to write to */ + Ifs_Table_t *ifs_table) /* Table of Interface Specification data */ +{ + + int i; + char str[80]; + Boolean_t is_array; + Data_Type_t type; + + + /* 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) + return; + + + /* Write the structure beginning */ + + fprintf(fp, "\n"); + fprintf(fp, "static IFparm MIFpTable[] = {\n"); + + + /* Write out an entry for each instance variable in the table */ + + /* Use the index of the element in the instance variable info array */ + /* ADDED TO the number of parameters as the SPICE3 integer tag. */ + + for(i = 0; i < ifs_table->num_inst_var; i++) { + + /* Use the SPICE3 OP macro since instance vars are output-only */ + + fprintf(fp, " OP("); + + /* Put in the name of the parameter and the integer tag */ + + fprintf(fp, "\"%s\", ", ifs_table->inst_var[i].name); + fprintf(fp, "%d, ", i + ifs_table->num_param); + + /* Format SPICE3 type according to parameter type field */ + + type = ifs_table->inst_var[i].type; + is_array = ifs_table->inst_var[i].is_array; + + strcpy(str,""); + + if(is_array == TRUE) { + strcat(str,"("); + } + + if(type == BOOLEAN) { + strcat(str,"IF_FLAG"); /* There is no BOOLEAN in SPICE3 */ + } + else if(type == INTEGER) { + strcat(str,"IF_INTEGER"); + } + else if(type == REAL) { + strcat(str,"IF_REAL"); + } + else if(type == COMPLEX) { + strcat(str,"IF_COMPLEX"); + } + else if(type == STRING) { + strcat(str,"IF_STRING"); + } + else if(type == POINTER) { + strcat(str,"IF_STRING"); + } + else { + print_error("INTERNAL ERROR - write_pTable() - Impossible data type."); + } + + if(is_array == TRUE) { + strcat(str,"|IF_VECTOR)"); + } + + fprintf(fp, "%s, ", str); + + /* Put in the description string and finish this line off */ + + fprintf(fp, "\"%s\"", ifs_table->inst_var[i].description); + fprintf(fp, "),\n"); + + } + + /* Finish off the structure */ + + fprintf(fp, "};\n"); + fprintf(fp, "\n"); +} + + +/* *********************************************************************** */ + + +/* +write_mPTable + +Function write_mPTable writes the model parameter information +using SPICE's IFparm structure type. This table defines the +parameters to be input/output variables using SPICE's ``IOP'' macro +so that these variables can be set or queried from SPICE. These +model parameters are derived from the Interface Specification's +PARAMETER table. +*/ + +static void write_mPTable( + FILE *fp, /* File to write to */ + Ifs_Table_t *ifs_table) /* Table of Interface Specification data */ +{ + + int i; + char str[80]; + Boolean_t is_array; + Data_Type_t type; + + + /* Only write the mPTable 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) + return; + + + /* Write the structure beginning */ + + fprintf(fp, "\n"); + fprintf(fp, "static IFparm MIFmPTable[] = {\n"); + + + /* Write out an entry for each parameter in the table */ + + /* Use the index of the element in the parameter info array */ + /* as the SPICE3 integer tag. */ + + for(i = 0; i < ifs_table->num_param; i++) { + + /* Use the SPICE3 IOP macro since model parameters are input/output */ + + fprintf(fp, " IOP("); + + /* Put in the name of the parameter and the integer tag */ + + fprintf(fp, "\"%s\", ", ifs_table->param[i].name); + fprintf(fp, "%d, ", i); + + /* Format SPICE3 type according to parameter type field */ + + type = ifs_table->param[i].type; + is_array = ifs_table->param[i].is_array; + + strcpy(str,""); + + if(is_array == TRUE) { + strcat(str,"("); + } + + if(type == BOOLEAN) { + strcat(str,"IF_FLAG"); /* There is no BOOLEAN in SPICE3 */ + } + else if(type == INTEGER) { + strcat(str,"IF_INTEGER"); + } + else if(type == REAL) { + strcat(str,"IF_REAL"); + } + else if(type == COMPLEX) { + strcat(str,"IF_COMPLEX"); + } + else if(type == STRING) { + strcat(str,"IF_STRING"); + } + else { + print_error("INTERNAL ERROR - write_mPTable() - Impossible data type."); + } + + if(is_array == TRUE) { + strcat(str,"|IF_VECTOR)"); + } + + fprintf(fp, "%s, ", str); + + /* Put in the description string and finish this line off */ + + fprintf(fp, "\"%s\"", ifs_table->param[i].description); + fprintf(fp, "),\n"); + + } + + /* Finish off the structure */ + + fprintf(fp, "};\n"); + fprintf(fp, "\n"); + +} + + +/* *********************************************************************** */ + + +/* +write_conn_info + +Function write_conn_info writes information used by the +Simulator's new MIF package to interpret and error check a +model's connection list in a SPICE deck. This information is +derived from the Interface Specification file's PORT table. +*/ + + + +static void write_conn_info( + FILE *fp, /* File to write to */ + Ifs_Table_t *ifs_table) /* Table of Interface Specification data */ +{ + + int i; + int j; + char *str; + Boolean_t is_array; + Data_Type_t type; + + + /* Only write the connTable if there is something to put in it. */ + /* Otherwise, we will put NULL in the SPICEdev structure in its slot */ + + if(ifs_table->num_conn == 0) /* An unlikely condition for sure ... */ + return; + + /* First, we must define arrays of port types */ + + /* Note that there should be always at least one allowed port type */ + /* so we don't have to worry about arrays with no elements */ + + for(i = 0; i < ifs_table->num_conn; i++) { + + fprintf(fp, "\n"); + fprintf(fp, "static Mif_Port_Type_t MIFportEnum%d[] = {\n", i); + + if(ifs_table->conn[i].num_allowed_types < 1) + print_error("ERROR - write_conn_info() - Number of allowed types cannot be zero"); + + for(j = 0; j < ifs_table->conn[i].num_allowed_types; j++) { + + str = port_type_to_str(ifs_table->conn[i].allowed_port_type[j]); + fprintf(fp, "\t%s,\n", str); + + } /* for number of allowed types */ + + fprintf(fp, "};\n"); + fprintf(fp, "\n"); + + + fprintf(fp, "\n"); + fprintf(fp, "static char *MIFportStr%d[] = {\n", i); + + for(j = 0; j < ifs_table->conn[i].num_allowed_types; j++) { + if(ifs_table->conn[i].allowed_port_type[j] == USER_DEFINED) + fprintf(fp, "\t\"%s\",\n", ifs_table->conn[i].allowed_type[j]); + else { + str = gen_port_type_str(ifs_table->conn[i].allowed_port_type[j]); + fprintf(fp, "\t\"%s\",\n", str); + } + } /* for number of allowed types */ + + fprintf(fp, "};\n"); + fprintf(fp, "\n"); + + } /* for number of connections */ + + + + /* Now write the structure */ + + fprintf(fp, "\n"); + fprintf(fp, "static Mif_Conn_Info_t MIFconnTable[] = {\n"); + + + /* Write out an entry for each parameter in the table */ + + for(i = 0; i < ifs_table->num_conn; i++) { + + fprintf(fp, " {\n"); + fprintf(fp, " \"%s\",\n",ifs_table->conn[i].name); + fprintf(fp, " \"%s\",\n",ifs_table->conn[i].description); + + str = dir_to_str(ifs_table->conn[i].direction); + fprintf(fp, " %s,\n", str); + + str = port_type_to_str(ifs_table->conn[i].default_port_type); + fprintf(fp, " %s,\n", str); + + fprintf(fp, " \"%s\",\n", + (ifs_table->conn[i].default_port_type == USER_DEFINED) + ? ifs_table->conn[i].default_type + : gen_port_type_str (ifs_table->conn[i].default_port_type)); + + fprintf(fp," %d,\n",ifs_table->conn[i].num_allowed_types); + + fprintf(fp, " MIFportEnum%d,\n", i); + fprintf(fp, " MIFportStr%d,\n", i); + + + str = boolean_to_str(ifs_table->conn[i].is_array); + fprintf(fp, " %s,\n", str); + + if(ifs_table->conn[i].is_array == FALSE) { + + str = boolean_to_str(FALSE); /* has_lower_bound */ + fprintf(fp, " %s,\n", str); + + str = integer_to_str(0); /* lower_bound */ + fprintf(fp, " %s,\n", str); + + str = boolean_to_str(FALSE); /* has_upper_bound */ + fprintf(fp, " %s,\n", str); + + str = integer_to_str(0); /* upper_bound */ + fprintf(fp, " %s,\n", str); + } + else { /* is_array == TRUE */ + + str = boolean_to_str(ifs_table->conn[i].has_lower_bound); + fprintf(fp, " %s,\n", str); + + if(ifs_table->conn[i].has_lower_bound == TRUE) + str = integer_to_str(ifs_table->conn[i].lower_bound); + else + str = integer_to_str(0); + fprintf(fp, " %s,\n", str); + + str = boolean_to_str(ifs_table->conn[i].has_upper_bound); + fprintf(fp, " %s,\n", str); + + if(ifs_table->conn[i].has_upper_bound == TRUE) + str = integer_to_str(ifs_table->conn[i].upper_bound); + else + str = integer_to_str(0); + fprintf(fp, " %s,\n", str); + + } /* if is_array */ + + str = boolean_to_str(ifs_table->conn[i].null_allowed); + fprintf(fp, " %s,\n", str); + + fprintf(fp, " },\n"); + + } /* for number of parameters */ + + + /* Finish off the structure */ + + fprintf(fp, "};\n"); + fprintf(fp, "\n"); +} + + +/* *********************************************************************** */ + + +/* +write_param_info + +Function write_param_info writes information used by the +Simulator's new MIF package to interpret and error check a +model's parameter list in an XSPICE deck. This information is +derived from the Interface Specification file's PARAMETER table. +It is essentially a superset of the IFparm information written by +write_mPTable(). The IFparm information written by +write_mPTable() is required to work with SPICE's device set and +query functions. The information written by write_param_info is +more extensive and is required to parse and error check the XSPICE +input deck. +*/ + + + +static void write_param_info( + FILE *fp, /* File to write to */ + Ifs_Table_t *ifs_table) /* Table of Interface Specification data */ +{ + + int i; + char *str; + Boolean_t is_array; + Data_Type_t type; + + + /* 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) + return; + + + /* Write the structure beginning */ + + fprintf(fp, "\n"); + fprintf(fp, "static Mif_Param_Info_t MIFparamTable[] = {\n"); + + + /* Write out an entry for each parameter in the table */ + + for(i = 0; i < ifs_table->num_param; i++) { + + fprintf(fp, " {\n"); + fprintf(fp, " \"%s\",\n",ifs_table->param[i].name); + fprintf(fp, " \"%s\",\n",ifs_table->param[i].description); + + str = data_type_to_str(ifs_table->param[i].type); + fprintf(fp, " %s,\n", str); + + str = boolean_to_str(ifs_table->param[i].has_default); + fprintf(fp, " %s,\n", str); + + if(ifs_table->param[i].has_default == TRUE) + str = value_to_str(ifs_table->param[i].type, ifs_table->param[i].default_value); + else + str = no_value_to_str(); + fprintf(fp, " %s,\n", str); + + str = boolean_to_str(ifs_table->param[i].has_lower_limit); + fprintf(fp, " %s,\n", str); + + if(ifs_table->param[i].has_lower_limit == TRUE) + str = value_to_str(ifs_table->param[i].type, ifs_table->param[i].lower_limit); + else + str = no_value_to_str(); + fprintf(fp, " %s,\n", str); + + str = boolean_to_str(ifs_table->param[i].has_upper_limit); + fprintf(fp, " %s,\n", str); + + if(ifs_table->param[i].has_upper_limit == TRUE) + str = value_to_str(ifs_table->param[i].type, ifs_table->param[i].upper_limit); + else + str = no_value_to_str(); + fprintf(fp, " %s,\n", str); + + str = boolean_to_str(ifs_table->param[i].is_array); + fprintf(fp, " %s,\n", str); + + if(ifs_table->param[i].is_array == FALSE) { + + str = boolean_to_str(FALSE); /* has_conn_ref */ + fprintf(fp, " %s,\n", str); + + str = integer_to_str(0); /* conn_ref */ + fprintf(fp, " %s,\n", str); + + str = boolean_to_str(FALSE); /* has_lower_bound */ + fprintf(fp, " %s,\n", str); + + str = integer_to_str(0); /* lower_bound */ + fprintf(fp, " %s,\n", str); + + str = boolean_to_str(FALSE); /* has_upper_bound */ + fprintf(fp, " %s,\n", str); + + str = integer_to_str(0); /* upper_bound */ + fprintf(fp, " %s,\n", str); + } + else { /* is_array == TRUE */ + + str = boolean_to_str(ifs_table->param[i].has_conn_ref); + fprintf(fp, " %s,\n", str); + + if(ifs_table->param[i].has_conn_ref == TRUE) { + + str = integer_to_str(ifs_table->param[i].conn_ref); + fprintf(fp, " %s,\n", str); + + str = boolean_to_str(FALSE); /* has_lower_bound */ + fprintf(fp, " %s,\n", str); + + str = integer_to_str(0); /* lower_bound */ + fprintf(fp, " %s,\n", str); + + str = boolean_to_str(FALSE); /* has_upper_bound */ + fprintf(fp, " %s,\n", str); + + str = integer_to_str(0); /* upper_bound */ + fprintf(fp, " %s,\n", str); + } + else { /* has_conn_ref == FALSE */ + + str = integer_to_str(0); /* conn_ref */ + fprintf(fp, " %s,\n", str); + + str = boolean_to_str(ifs_table->param[i].has_lower_bound); + fprintf(fp, " %s,\n", str); + + if(ifs_table->param[i].has_lower_bound == TRUE) + str = integer_to_str(ifs_table->param[i].lower_bound); + else + str = integer_to_str(0); + fprintf(fp, " %s,\n", str); + + str = boolean_to_str(ifs_table->param[i].has_upper_bound); + fprintf(fp, " %s,\n", str); + + if(ifs_table->param[i].has_upper_bound == TRUE) + str = integer_to_str(ifs_table->param[i].upper_bound); + else + str = integer_to_str(0); + fprintf(fp, " %s,\n", str); + + } /* if has_conn_ref */ + + } /* if is_array */ + + str = boolean_to_str(ifs_table->param[i].null_allowed); + fprintf(fp, " %s,\n", str); + + fprintf(fp, " },\n"); + + } /* for number of parameters */ + + + /* Finish off the structure */ + + fprintf(fp, "};\n"); + fprintf(fp, "\n"); + +} + + + +/* *********************************************************************** */ + + +/* +write_inst_var_info + +Function write_inst_var_info writes information used by the +Simulator's new MIF package to allocate space for and to output +(using SPICE's .save feature) variables defined in the Interface +Specification file's STATIC_VAR table. It is essentially a +superset of the IFparm information written by write_mPTable(). +The IFparm information written by write_pTable() is required to +work with SPICE's device query functions. The information +written by write_inst_var_info is more extensive. +*/ + + + +static void write_inst_var_info( + FILE *fp, /* File to write to */ + Ifs_Table_t *ifs_table) /* Table of Interface Specification data */ +{ + + int i; + char *str; + Boolean_t is_array; + Data_Type_t type; + + + /* Only write the inst_varTable 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) + return; + + + /* Write the structure beginning */ + + fprintf(fp, "\n"); + fprintf(fp, "static Mif_Inst_Var_Info_t MIFinst_varTable[] = {\n"); + + + /* Write out an entry for each parameter in the table */ + + for(i = 0; i < ifs_table->num_inst_var; i++) { + + fprintf(fp, " {\n"); + fprintf(fp, " \"%s\",\n",ifs_table->inst_var[i].name); + fprintf(fp, " \"%s\",\n",ifs_table->inst_var[i].description); + + str = data_type_to_str(ifs_table->inst_var[i].type); + fprintf(fp, " %s,\n", str); + + str = boolean_to_str(ifs_table->inst_var[i].is_array); + fprintf(fp, " %s,\n", str); + + fprintf(fp, " },\n"); + + } /* for number of parameters */ + + + /* Finish off the structure */ + + fprintf(fp, "};\n"); + fprintf(fp, "\n"); + +} + + + + +/* *********************************************************************** */ + + +/* +write_SPICEdev + +Function write_SPICEdev writes the global XXX_info structure used +by SPICE to define a model. Here ``XXX'' is the name of the code +model. This structure contains the name of the +model, a pointer to the C function that implements the model, and +pointers to all of the above data structures. +*/ + + + +static void write_SPICEdev( + FILE *fp, /* File to write to */ + Ifs_Table_t *ifs_table) /* Table of Interface Specification data */ +{ + + /* Extern the code model function name */ + fprintf(fp, "\n"); + fprintf(fp, "extern void %s(Mif_Private_t *);\n", + ifs_table->name.c_fcn_name); + + /* Write out the structure beginning */ + + /* Use the c function external identifier appended with _info as the */ + /* external identifier for the structure. */ + + fprintf(fp, "\n"); + fprintf(fp, "SPICEdev %s_info = {\n", ifs_table->name.c_fcn_name); + + /* Write the IFdevice structure */ + + fprintf(fp, " { \"%s\",\n", ifs_table->name.model_name); + fprintf(fp, " \"%s\",\n", ifs_table->name.description); + fprintf(fp, " 0,\n"); + fprintf(fp, " 0,\n"); + fprintf(fp, " NULL,\n"); + + fprintf(fp, " %d,\n", ifs_table->num_inst_var); + if(ifs_table->num_inst_var > 0) + fprintf(fp, " MIFpTable,\n"); + else + fprintf(fp, " NULL,\n"); + + fprintf(fp, " %d,\n", ifs_table->num_param); + if(ifs_table->num_param > 0) + fprintf(fp, " MIFmPTable,\n"); + else + fprintf(fp, " NULL,\n"); + + fprintf(fp, " %s,\n", ifs_table->name.c_fcn_name); + + fprintf(fp, " %d,\n", ifs_table->num_conn); + if(ifs_table->num_conn > 0) + fprintf(fp, " MIFconnTable,\n"); + else + fprintf(fp, " NULL,\n"); + + fprintf(fp, " %d,\n", ifs_table->num_param); + if(ifs_table->num_param > 0) + fprintf(fp, " MIFparamTable,\n"); + else + fprintf(fp, " NULL,\n"); + + fprintf(fp, " %d,\n", ifs_table->num_inst_var); + if(ifs_table->num_inst_var > 0) + fprintf(fp, " MIFinst_varTable,\n"); + else + fprintf(fp, " NULL,\n"); + + fprintf(fp, " },\n"); + + /* Write the names of the generic code model functions */ + + fprintf(fp, "NULL, \n"); /* DEVparam */ + fprintf(fp, "MIFmParam, \n"); /* DEVmodParam */ + fprintf(fp, "MIFload, \n"); /* DEVload */ + fprintf(fp, "MIFsetup, \n"); /* DEVsetup */ + fprintf(fp, "NULL, \n"); /* DEVpzSetup */ + fprintf(fp, "NULL, \n"); /* DEVtemperature */ + fprintf(fp, "MIFtrunc, \n"); /* DEVtrunc */ + fprintf(fp, "NULL, \n"); /* DEVfindBranch */ + fprintf(fp, "MIFload, \n"); /* DEVacLoad */ + fprintf(fp, "NULL, \n"); /* DEVaccept */ + fprintf(fp, "MIFdestroy, \n"); /* DEVdestroy */ + fprintf(fp, "MIFmDelete, \n"); /* DEVmodDelete */ + fprintf(fp, "MIFdelete, \n"); /* DEVdelete */ + fprintf(fp, "NULL, \n"); /* DEVsetic */ + fprintf(fp, "MIFask, \n"); /* DEVask */ + fprintf(fp, "MIFmAsk, \n"); /* DEVmodAsk */ + fprintf(fp, "NULL, \n"); /* DEVpzLoad */ + fprintf(fp, "MIFconvTest, \n"); /* DEVconvTest */ + fprintf(fp, "NULL, \n"); /* DEVsenSetup */ + fprintf(fp, "NULL, \n"); /* DEVsenLoad */ + fprintf(fp, "NULL, \n"); /* DEVSenUpdate */ + fprintf(fp, "NULL, \n"); /* DEVsenAcLoad */ + fprintf(fp, "NULL, \n"); /* DEVsenPrint */ + fprintf(fp, "NULL, \n"); /* DEVsenTrunc */ + + /* Write the sizeof stuff used in dynamic allocation of inst/model structs */ + + fprintf(fp, "sizeof(MIFinstance),\n"); + fprintf(fp, "sizeof(MIFmodel),\n"); + fprintf(fp, "\n"); + fprintf(fp, "};\n"); + fprintf(fp, "\n"); + +} + + + + +/* *********************************************************************** */ + + +/* +The following functions are utility routines used to convert internal +enums and data to ASCII form for placing into the .c file +being created. +*/ + + +#define BASE_STR_LEN 80 + + +static char *data_type_to_str(Data_Type_t type) +{ + static char *str = NULL; + + if(str == NULL) + str = malloc(BASE_STR_LEN+1); + + switch(type) { + + case BOOLEAN: + strcpy(str,"MIF_BOOLEAN"); + break; + + case INTEGER: + strcpy(str,"MIF_INTEGER"); + break; + + case REAL: + strcpy(str,"MIF_REAL"); + break; + + case COMPLEX: + strcpy(str,"MIF_COMPLEX"); + break; + + case STRING: + strcpy(str,"MIF_STRING"); + break; + + case POINTER: + strcpy(str,"MIF_STRING"); + break; + + default: + print_error("INTERNAL ERROR - data_type_to_str() - Impossible data type."); + } + + return(str); +} + + +/* *********************************************************************** */ + +static char *port_type_to_str(Port_Type_t port) +{ + static char *str = NULL; + + if(str == NULL) + str = malloc(BASE_STR_LEN+1); + + switch(port) { + + case VOLTAGE: + strcpy(str,"MIF_VOLTAGE"); + break; + + case DIFF_VOLTAGE: + strcpy(str,"MIF_DIFF_VOLTAGE"); + break; + + case CURRENT: + strcpy(str,"MIF_CURRENT"); + break; + + case DIFF_CURRENT: + strcpy(str,"MIF_DIFF_CURRENT"); + break; + + case VSOURCE_CURRENT: + strcpy(str,"MIF_VSOURCE_CURRENT"); + break; + + case CONDUCTANCE: + strcpy(str,"MIF_CONDUCTANCE"); + break; + + case DIFF_CONDUCTANCE: + strcpy(str,"MIF_DIFF_CONDUCTANCE"); + break; + + case RESISTANCE: + strcpy(str,"MIF_RESISTANCE"); + break; + + case DIFF_RESISTANCE: + strcpy(str,"MIF_DIFF_RESISTANCE"); + break; + + case DIGITAL: + strcpy(str,"MIF_DIGITAL"); + break; + + case USER_DEFINED: + strcpy(str,"MIF_USER_DEFINED"); + break; + + default: + print_error("INTERNAL ERROR - port_type_to_str() - Impossible port type."); + } + + return(str); + +} + +/* *********************************************************************** */ + +static char *gen_port_type_str(Port_Type_t port) +{ + static char *str = NULL; + + if(str == NULL) + str = malloc(BASE_STR_LEN+1); + + switch(port) { + + case VOLTAGE: + strcpy(str,"v"); + break; + + case DIFF_VOLTAGE: + strcpy(str,"vd"); + break; + + case CURRENT: + strcpy(str,"i"); + break; + + case DIFF_CURRENT: + strcpy(str,"id"); + break; + + case VSOURCE_CURRENT: + strcpy(str,"vnam"); + break; + + case CONDUCTANCE: + strcpy(str,"g"); + break; + + case DIFF_CONDUCTANCE: + strcpy(str,"gd"); + break; + + case RESISTANCE: + strcpy(str,"h"); + break; + + case DIFF_RESISTANCE: + strcpy(str,"hd"); + break; + + case DIGITAL: + strcpy(str,"d"); + break; + + case USER_DEFINED: + strcpy(str,""); + break; + + default: + print_error("INTERNAL ERROR - gen_port_type_str() - Impossible port type."); + } + + return(str); + +} + + +/* *********************************************************************** */ + +static char *dir_to_str(Dir_t dir) +{ + static char *str = NULL; + + if(str == NULL) + str = malloc(BASE_STR_LEN+1); + + switch(dir) { + + case IN: + strcpy(str,"MIF_IN"); + break; + + case OUT: + strcpy(str,"MIF_OUT"); + break; + + case INOUT: + strcpy(str,"MIF_INOUT"); + break; + + default: + print_error("INTERNAL ERROR - dir_to_str() - Impossible direction type."); + } + + return(str); +} + + + +/* *********************************************************************** */ + +static char *value_to_str(Data_Type_t type, Value_t value) +{ + static char *str = NULL; + static int max_len = 0; + + char *bool_str; + int str_len; + + + if(str == NULL) { + str = malloc(2 * BASE_STR_LEN + 1); + max_len = 2 * BASE_STR_LEN; + } + + switch(type) { + + case BOOLEAN: + bool_str = boolean_to_str(value.bvalue); + sprintf(str, "{%s, 0, 0.0, {0.0, 0.0}, NULL}", bool_str); + break; + + case INTEGER: + sprintf(str, "{MIF_FALSE, %d, 0.0, {0.0, 0.0}, NULL}", value.ivalue); + break; + + case REAL: + sprintf(str, "{MIF_FALSE, 0, %e, {0.0, 0.0}, NULL}", value.rvalue); + break; + + case COMPLEX: + sprintf(str, "{MIF_FALSE, 0, 0.0, {%e, %e}, NULL}", + value.cvalue.real, value.cvalue.imag); + break; + + case STRING: + /* be careful, the string could conceivably be very long... */ + str_len = strlen(value.svalue); + if((str_len + BASE_STR_LEN) > max_len) { + str = realloc(str, (max_len + str_len +1)); + max_len += str_len; + } + sprintf(str, "{MIF_FALSE, 0, 0.0, {0.0, 0.0}, \"%s\"}", value.svalue); + break; + + default: + print_error("INTERNAL ERROR - value_to_str() - Impossible data type."); + + } + + return(str); +} + + +/* *********************************************************************** */ + +static char *boolean_to_str(Boolean_t value) +{ + static char *str = NULL; + + if(str == NULL) + str = malloc(BASE_STR_LEN+1); + + switch(value) { + + case TRUE: + strcpy(str,"MIF_TRUE"); + break; + + case FALSE: + strcpy(str,"MIF_FALSE"); + break; + + default: + print_error("INTERNAL ERROR - boolean_to_str() - Impossible boolean value."); + { + char *p = 0; *p = 0; + } + } + + return(str); +} + + +/* *********************************************************************** */ + +static char *integer_to_str(int value) +{ + static char *str = NULL; + + if(str == NULL) { + str = malloc(BASE_STR_LEN + 1); + } + + sprintf(str, "%d", value); + + return(str); +} + + +/* *********************************************************************** */ + +static char *no_value_to_str(void) +{ + static char *str = NULL; + + if(str == NULL) { + str = malloc(BASE_STR_LEN + 1); + } + + sprintf(str, "{MIF_FALSE, 0, 0.0, {0.0, 0.0}, NULL}"); + + return(str); +} + + +