More $table_model code.

This patch adds the ability to process the control string and emit some
debug information.
This commit is contained in:
Cary R 2011-05-02 09:17:34 -07:00 committed by Stephen Williams
parent e85c43c232
commit 0597b56ba2
3 changed files with 486 additions and 34 deletions

View File

@ -19,12 +19,39 @@
#include "sys_priv.h"
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "table_mod.h"
#include "ivl_alloc.h"
/*
* Flag used to enable/disable debug output.
*/
static unsigned table_model_debug = 0;
// HERE: Should these just be defines?
/*
* Define the allowed interpolation control values.
*/
typedef enum interp_type_e {
IVL_CLOSEST_POINT = 0, /* D */
IVL_LINEAR_INTERP = 1, /* 1 - Default */
IVL_QUADRATIC_INTERP = 2, /* 2 */
IVL_CUBIC_INTERP = 3, /* 3 */
IVL_IGNORE_COLUMN = 4 /* I */
} interp_type_t;
/*
* Define the allowed extrapolation control values.
*/
typedef enum extrap_type_e {
IVL_CONSTANT_EXTRAP = 0, /* C */
IVL_LINEAR_EXTRAP = 1, /* L - Default */
IVL_ERROR_EXTRAP = 2 /* E */
} extrap_type_t;
/*
* This structure is saved for each table model instance.
*/
@ -35,14 +62,24 @@ typedef struct t_table_mod {
char *name;
vpiHandle arg;
} file;
unsigned have_fname; /* Has the file name been allocated? */
vpiHandle control; /* Control string argument. */
union { /* Control string argument. */
struct {
char *interp;
char *extrap_low;
char *extrap_high;
} info;
vpiHandle arg;
} control;
// HERE need a pointer to the dependent data and the final table.
unsigned dims; /* The number of independent variables. */
unsigned fields; /* The number of control fields. */
unsigned depend; /* Where the dependent column is located. */
char have_fname; /* Has the file name been allocated? */
char have_ctl; /* Has the file name been allocated? */
} s_table_mod, *p_table_mod;
static p_table_mod *tables = 0;
static unsigned table_count = 0U;
static unsigned table_count = 0;
/*
* Routine to cleanup the table model data at the end of simulation.
@ -56,11 +93,16 @@ static PLI_INT32 cleanup_table_mod(p_cb_data cause)
free(tables[idx]->indep);
free(tables[idx]->indep_val);
if (tables[idx]->have_fname) free(tables[idx]->file.name);
if (tables[idx]->have_ctl) {
free(tables[idx]->control.info.interp);
free(tables[idx]->control.info.extrap_low);
free(tables[idx]->control.info.extrap_high);
}
free(tables[idx]);
}
free(tables);
tables = 0;
table_count = 0U;
table_count = 0;
return 0;
}
@ -84,8 +126,11 @@ static p_table_mod create_table()
obj->indep = 0;
obj->indep_val = 0;
obj->have_fname = 0;
obj->control = 0;
obj->have_ctl = 0;
obj->control.arg = 0;
obj->depend = 0;
obj->dims = 0;
obj->fields = 0;
return obj;
}
@ -109,6 +154,29 @@ unsigned is_const_string_obj(vpiHandle arg)
return rtn;
}
/*
* Get any command line flags. For now we only have a debug flag.
*/
static void check_command_line_flags()
{
struct t_vpi_vlog_info vlog_info;
unsigned idx;
static unsigned command_line_processed = 0;
/* If we have already processed the arguments then just return. */
if (command_line_processed) return;
vpi_get_vlog_info(&vlog_info);
for (idx = 0; idx < vlog_info.argc; idx += 1) {
if (strcmp(vlog_info.argv[idx], "-table-model-debug") == 0) {
table_model_debug = 1;
}
}
command_line_processed = 1;
}
/*
* Check that the given $table_model() call has valid arguments.
*/
@ -119,6 +187,9 @@ static PLI_INT32 sys_table_model_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name)
vpiHandle arg;
p_table_mod table = create_table();
/* See if there are any table model arguments. */
check_command_line_flags();
/* Check that there are arguments. */
if (argv == 0) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
@ -171,7 +242,7 @@ static PLI_INT32 sys_table_model_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name)
}
check_for_extra_args(argv, callh, name, "N numeric and 1 or 2 "
" constant string arguments", 0);
table->control = arg;
table->control.arg = arg;
}
/* Save the table data information. */
@ -180,6 +251,339 @@ static PLI_INT32 sys_table_model_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name)
return 0;
}
/*
* Initialize the control string fields with the default value.
*/
static void initialize_control_fields_def(p_table_mod table)
{
char *val;
unsigned width = table->dims;
/* Set the default interpolation for each dimension. */
val = (char *) malloc(width);
assert(val);
table->control.info.interp = memset(val, IVL_LINEAR_INTERP, width);
/* Set the default low extrapolation for each dimension. */
val = (char *) malloc(width);
assert(val);
table->control.info.extrap_low = memset(val, IVL_LINEAR_EXTRAP, width);
/* Set the default low extrapolation for each dimension. */
val = (char *) malloc(width);
assert(val);
table->control.info.extrap_high = memset(val, IVL_LINEAR_EXTRAP, width);
/* By default the dependent data column is the first one after the
* independent data column(s). */
table->depend = 1;
/* Set the number of control fields. */
table->fields = width;
/* We have defined the interpolation/extrapolation fields. */
table->have_ctl = 1;
}
/*
* Parse the extrapolation control codes.
*/
static unsigned parse_extrap(vpiHandle callh, p_table_mod table, unsigned idx,
char **extrap, char *control)
{
/* Advance to the first extrapolation code. */
*extrap += 1;
/* By default both the low and high extrapolation is set by the
* first extrapolation character. We'll override the high value
* later if there is a second character. */
switch (**extrap) {
/* Clamp (no) extrapolation. */
case 'C':
table->control.info.extrap_low[idx] = IVL_CONSTANT_EXTRAP;
table->control.info.extrap_high[idx] = IVL_CONSTANT_EXTRAP;
break;
/* Linear extrapolation. */
case 'L':
table->control.info.extrap_low[idx] = IVL_LINEAR_EXTRAP;
table->control.info.extrap_high[idx] = IVL_LINEAR_EXTRAP;
break;
/* Error on extrapolation. */
case 'E':
table->control.info.extrap_low[idx] = IVL_ERROR_EXTRAP;
table->control.info.extrap_high[idx] = IVL_ERROR_EXTRAP;
break;
/* There are no extrapolation characters so use the default
* (linear extrapolation). */
case 0:
case ',':
table->control.info.extrap_low[idx] = IVL_LINEAR_EXTRAP;
table->control.info.extrap_high[idx] = IVL_LINEAR_EXTRAP;
return 0;
/* Anything else is an error. */
default:
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("Unknown extrapolation code '%c' for dimension "
"%u: %s\n", **extrap, idx+1, control);
vpi_control(vpiFinish, 1);
return 1;
}
/* Advance to the next (high) extrapolation code. */
*extrap += 1;
/* Override the high extrapolation value if needed. */
switch (**extrap) {
/* Clamp (no) extrapolation. */
case 'C':
table->control.info.extrap_high[idx] = IVL_CONSTANT_EXTRAP;
break;
/* Linear extrapolation. */
case 'L':
table->control.info.extrap_high[idx] = IVL_LINEAR_EXTRAP;
break;
/* Error on extrapolation. */
case 'E':
table->control.info.extrap_high[idx] = IVL_ERROR_EXTRAP;
break;
/* There is no high extrapolation character so just return. */
case 0:
case ',':
return 0;
/* Anything else is an error. */
default:
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("Unknown high extrapolation code '%c' for dimension "
"%u: %s\n", **extrap, idx+1, control);
vpi_control(vpiFinish, 1);
return 1;
}
/* Advance to the next field. */
*extrap += 1;
return 0;
}
/*
* Load the control string fields for the given string. Return 0 if there
* is a problem parsing the control string.
*/
static unsigned initialize_control_fields(vpiHandle callh, p_table_mod table,
char *control)
{
unsigned width, idx;
char *cp;
/* If we need to fail these must be defined to zero until memory
* has actually been allocated. */
table->control.info.interp = 0;
table->control.info.extrap_low = 0;
table->control.info.extrap_high = 0;
/* We have defined the interpolation/extrapolation fields. */
table->have_ctl = 1;
/* Look for the dependent data field. */
cp = index(control, ';');
if (cp) {
size_t len;
unsigned long val;
char *end;
/* NULL terminate the independent part of the string. */
*cp = 0;
cp += 1;
len = strlen(cp);
/* If the length is zero or not all digits then the string
* is invalid. */
// HERE: Do we need to support/ignore an underscore? What about in the file?
if ((! len) || (len != strspn(cp, "0123456789"))) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("Control string dependent selector is "
"invalid: %s.\n", cp);
vpi_control(vpiFinish, 1);
return 0;
}
val = strtoul(cp, &end, 10);
assert(*end == 0);
/* If the value is too big also report an error. */
if (val > UINT_MAX) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("Control string dependent value is "
"to large: %lu.\n", val);
vpi_control(vpiFinish, 1);
return 0;
}
table->depend = (unsigned) val;
} else table->depend = 1;
/* Find the number of interpolation/extrapolation control fields. */
width = 1;
cp = control;
while ((cp = index(cp, ','))) {
cp += 1;
width += 1;
}
/* We must have at least as many control fields as dimensions. */
if (width < table->dims) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("Not enough control field(s) (%u) for the dimension(s) "
"(%u).", width, table->dims);
vpi_control(vpiFinish, 1);
return 0;
}
/* Allocate space for the interpolation/extrapolation values. */
table->control.info.interp = (char *) malloc(width);
assert(table->control.info.interp);
table->control.info.extrap_low = (char *) malloc(width);
assert(table->control.info.extrap_low);
table->control.info.extrap_high = (char *) malloc(width);
assert(table->control.info.extrap_high);
/* Parse the individual dimension control string. */
cp = control;
for (idx = 0; idx < width; idx += 1) {
switch (*cp) {
/* Closest point interpolation. */
case 'D':
table->control.info.interp[idx] = IVL_CLOSEST_POINT;
if (parse_extrap(callh, table, idx, &cp, control)) return 0;
break;
/* Linear interpolation. */
case '1':
table->control.info.interp[idx] = IVL_LINEAR_INTERP;
if (parse_extrap(callh, table, idx, &cp, control)) return 0;
break;
/* Quadratic interpolation. */
case '2':
table->control.info.interp[idx] = IVL_QUADRATIC_INTERP;
if (parse_extrap(callh, table, idx, &cp, control)) return 0;
break;
/* Cubic interpolation. */
case '3':
table->control.info.interp[idx] = IVL_CUBIC_INTERP;
if (parse_extrap(callh, table, idx, &cp, control)) return 0;
break;
/* Ignore column. No extrapolation codes are allowed. */
case 'I':
table->control.info.interp[idx] = IVL_IGNORE_COLUMN;
break;
/* This field is not specified so use the default values.
* Linear interpolation and extrapolation. */
case 0:
assert(idx == width-1);
case ',':
table->control.info.interp[idx] = IVL_LINEAR_INTERP;
table->control.info.extrap_low[idx] = IVL_LINEAR_EXTRAP;
table->control.info.extrap_high[idx] = IVL_LINEAR_EXTRAP;
break;
/* Anything else is an error. */
default:
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("Unknown interpolation code '%c' for dimension "
"%u: %s\n", *cp, idx+1, control);
vpi_control(vpiFinish, 1);
return 0;
}
/* Verify that there is no extra junk at the end of the field. */
if (*cp && (*cp != ',')) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("Extra control characters found for dimension "
"%u: %s\n", idx+1, control);
vpi_control(vpiFinish, 1);
return 0;
}
/* Advance to the next field if we are not at the end of the
* control string. */
if (*cp == ',') cp += 1;
}
/* Return the number of fields plus the dependent offset as the
* minimum number of fields. */
return (width + table->depend);
}
/*
* Print out the interpolation code.
*/
static void dump_interp(char interp)
{
switch (interp) {
case IVL_CLOSEST_POINT: fprintf(stderr, "D"); break;
case IVL_LINEAR_INTERP: fprintf(stderr, "1"); break;
case IVL_QUADRATIC_INTERP: fprintf(stderr, "2"); break;
case IVL_CUBIC_INTERP: fprintf(stderr, "3"); break;
case IVL_IGNORE_COLUMN: fprintf(stderr, "I"); break;
default: fprintf(stderr, "<%d>", interp); break;
}
}
/*
* Print out the extrapolation code.
*/
static void dump_extrap(char extrap)
{
switch (extrap) {
case IVL_CONSTANT_EXTRAP: fprintf(stderr, "C"); break;
case IVL_LINEAR_EXTRAP: fprintf(stderr, "L"); break;
case IVL_ERROR_EXTRAP: fprintf(stderr, "E"); break;
default: fprintf(stderr, "<%d>", extrap); break;
}
}
/*
* Print some diagnostic information about the $table_model() call.
*/
static void dump_diag_info(vpiHandle callh, p_table_mod table)
{
unsigned idx;
char msg[64];
snprintf(msg, sizeof(msg), "%s:%d: DEBUG:", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
msg[sizeof(msg)-1] = 0;
fprintf(stderr, "%s Building %u variable table using \"%s\" and\n",
msg, table->dims, table->file.name);
fprintf(stderr, "%*s the following control string: ",
(int) strlen(msg), " ");
dump_interp(table->control.info.interp[0]);
dump_extrap(table->control.info.extrap_low[0]);
dump_extrap(table->control.info.extrap_high[0]);
for (idx = 1; idx < table->fields; idx += 1) {
fprintf(stderr, ",");
dump_interp(table->control.info.interp[idx]);
dump_extrap(table->control.info.extrap_low[idx]);
dump_extrap(table->control.info.extrap_high[idx]);
}
fprintf(stderr, ";%d\n", table->depend);
fprintf(stderr, "%*s The data file must have at least %u columns.\n",
(int) strlen(msg), " ", table->fields+table->depend);
}
/*
* Initialize the table model data structure.
*
@ -189,14 +593,13 @@ static PLI_INT32 sys_table_model_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name)
static unsigned initialize_table_model(vpiHandle callh, const char *name,
p_table_mod table)
{
s_vpi_value val;
FILE *fp;
/* Get the table file name. */
table->file.name = get_filename(callh, name, table->file.arg);
table->have_fname = 1;
if (table->file.name == 0) return 1U;
fprintf(stderr, "Building table \"%s\" with %u variables\n",
table->file.name, table->dims);
if (table->file.name == 0) return 1;
/* Open the file. */
fp = fopen(table->file.name, "r");
@ -205,41 +608,70 @@ static unsigned initialize_table_model(vpiHandle callh, const char *name,
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s() cannot open file \"%s\" for reading (%s).\n",
name, table->file.name, strerror(errno));
return 1U;
return 1;
}
// HERE: Need to process the control string.
/* Parse the given file and produce the basic data structure. */
// HERE: This is going to return a pointer to the data.
// We need to update the minimum cols when the control string has
// been processed.
if (! parse_table_model(fp, table->file.name, callh, table->dims+1)) {
return 1U;
/* Check to see if there is a control string. */
if (table->control.arg) {
val.format = vpiStringVal;
vpi_get_value(table->control.arg, &val);
if (*(val.value.str) == 0) {
/* If there is an empty control string field then we just
* use the default values for interpolation/extrapolation.
* We also assume that there only dimensions + 1 fields. */
initialize_control_fields_def(table);
} else {
if (initialize_control_fields(callh, table, val.value.str)) {
return 1;
}
}
} else {
/* If there is no control string field then we just use the
* default values for interpolation/extrapolation. We also
* assume that there only dimensions + 1 fields. */
initialize_control_fields_def(table);
}
/* If requested dump some diagnostic information. */
if (table_model_debug) dump_diag_info(callh, table);
/* Parse the given file and produce the basic data structure. We
* need to have columns for each control string field and for the
* dependent data. */
// HERE: This is going to return a pointer to the data.
if (! parse_table_model(fp, table->file.name, callh,
table->fields, table->depend)) {
return 1;
}
// HERE: once we are done with the control string should we build a table
// of function pointer for the interp/extrap?
/* Close the file now that we have loaded all the data. */
if (fclose(fp)) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s() cannot close file \"%s\" (%s).\n",
name, table->file.name, strerror(errno));
return 1U;
return 1;
}
/* Allocate space for the current argument values. */
table->indep_val = (double*) malloc(sizeof(double)*table->dims);
assert(table->indep_val);
return 0U;
return 0;
}
/*
* Routine to evalute the table model using the current input values.
*/
static double eval_table_model(vpiHandle callh, p_table_mod table)
{
unsigned idx;
fprintf(stderr, "Evaluating table \"%s\" with %u variables\n",
table->file.name, table->dims);
fprintf(stderr, "Evaluating table \"%s\" with %u variables\n",
table->file.name, table->dims);
for (idx = 0; idx < table->dims; idx += 1) {
fprintf(stderr, " Arg %u: %#g\n", idx, table->indep_val[idx]);
fprintf(stderr, " Arg %u: %#g\n", idx, table->indep_val[idx]);
}
return 0.0;

View File

@ -22,7 +22,7 @@
#include <vpi_user.h>
extern int parse_table_model(FILE *fp, const char *file_name, vpiHandle callh,
unsigned min_cols);
unsigned indep__cols, unsigned dep_col);
extern int tblmodlex();
extern void destroy_tblmod_lexor();

View File

@ -18,13 +18,18 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include "table_mod.h"
#include "ivl_alloc.h"
static unsigned minimum_columns;
static unsigned number_of_columns = 0U;
static unsigned indep_columns;
static unsigned dep_column;
static unsigned number_of_columns = 0;
static unsigned cur_columns;
static double *values;
static const char *in_file_name;
extern int tblmodlex(void);
@ -48,9 +53,17 @@ table : point
point : columns EOL
{
fprintf(stderr, "\n");
unsigned idx;
fprintf(stderr, "%#g", values[0]);
for (idx = 1; idx < indep_columns; idx += 1) {
fprintf(stderr, ", %#g", values[idx]);
}
fprintf(stderr, " => %#g\n", values[indep_columns]);
if (number_of_columns) {
if (cur_columns != number_of_columns) {
if (cur_columns < minimum_columns) {
yyerror("Found %u columns, need at least %u.",
cur_columns, minimum_columns);
} else if (cur_columns != number_of_columns) {
yyerror("Found %u columns, expected %u.",
cur_columns, number_of_columns);
}
@ -58,32 +71,39 @@ point : columns EOL
if (cur_columns < minimum_columns) {
yyerror("Found %u columns, need at least %u.",
cur_columns, minimum_columns);
}
number_of_columns = cur_columns;
} else number_of_columns = cur_columns;
}
}
columns : REAL
{
fprintf(stderr, "%#g", $1);
cur_columns = 1U;
values[0] = $1;
cur_columns = 1;
}
| columns REAL
{
fprintf(stderr, ", %#g", $2);
cur_columns += 1U;
if (cur_columns < indep_columns) values[cur_columns] = $2;
else if (cur_columns == dep_column) values[indep_columns] = $2;
cur_columns += 1;
}
%%
int parse_table_model(FILE *fp, const char *file_name, vpiHandle callh,
unsigned min_cols)
unsigned indep_cols, unsigned dep_col)
{
minimum_columns = min_cols;
assert(indep_cols > 1);
assert(dep_col > 0);
indep_columns = indep_cols;
minimum_columns = indep_cols + dep_col;
dep_column = minimum_columns - 1;
values = malloc(sizeof(double)*(indep_cols+1));
assert(values);
in_file_name = file_name;
init_tblmod_lexor(fp);
yyparse();
destroy_tblmod_lexor();
free(values);
// HERE: Need to handle errors.
return 1;
}