From 6cad14c491916d99c9b922233e3fbee70a96f632 Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 9 May 2011 15:48:51 -0700 Subject: [PATCH 1/7] Add more comments to $table_model code, etc. This patch mostly just adds comments, it also changes calles to index() to strchr(). --- vpi/table_mod.c | 4 +- vpi/table_mod_parse.y | 111 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 101 insertions(+), 14 deletions(-) diff --git a/vpi/table_mod.c b/vpi/table_mod.c index ff2e09070..dc41ae03e 100644 --- a/vpi/table_mod.c +++ b/vpi/table_mod.c @@ -348,7 +348,7 @@ static unsigned initialize_control_fields(vpiHandle callh, p_table_mod table, table->have_ctl = 1; /* Look for the dependent data field. */ - cp = index(control, ';'); + cp = strchr(control, ';'); if (cp) { size_t len; unsigned long val; @@ -385,7 +385,7 @@ static unsigned initialize_control_fields(vpiHandle callh, p_table_mod table, /* Find the number of interpolation/extrapolation control fields. */ num_fields = 1; cp = control; - while ((cp = index(cp, ','))) { + while ((cp = strchr(cp, ','))) { cp += 1; num_fields += 1; } diff --git a/vpi/table_mod_parse.y b/vpi/table_mod_parse.y index d2c004c5a..700d1265c 100644 --- a/vpi/table_mod_parse.y +++ b/vpi/table_mod_parse.y @@ -24,21 +24,85 @@ #include "table_mod.h" #include "ivl_alloc.h" +/* + * The number of parse errors encountered while parsing the data file. + */ static unsigned errors = 0; + +/* + * The minimum number of columns needed in the data file to satisfy the + * control string/input variable requirements. + */ static unsigned minimum_columns; + +/* + * The number of independent values we expect to keep based on the control + * string/independent variables. + */ static unsigned indep_values; + +/* + * The total number of independent columns to expect. This includes any + * ignored columns. + */ static unsigned indep_columns; + +/* + * The zero based dependent column location. This is just minimum_columns - 1. + */ static unsigned dep_column; + +/* + * The number of columns to expect in this data file. This must be + * greater than or equal to the minimum_columns above. + */ static unsigned number_of_columns = 0; + +/* + * The number of columns that this point currently has. + */ static unsigned cur_columns; + +/* + * The zero based current independent value we are looking for. + */ static unsigned cur_value; + +/* + * The usable values for this point. The independent values are first and + * the dependent value is the last entry. + */ static double *values; + +/* + * The name of the file we are getting data from. + */ static const char *in_file_name; + +/* + * The table structure that we are getting data for. + */ static p_table_mod table_def; +/* + * The lexor and error routines. + */ extern int tblmodlex(void); static void yyerror(const char *fmt, ...); +static void process_point() +{ + assert(cur_value == indep_values); + #if 0 + unsigned idx; + fprintf(stderr, "%#g", values[0]); + for (idx = 1; idx < indep_values; idx += 1) { + fprintf(stderr, ", %#g", values[idx]); + } + fprintf(stderr, " => %#g\n", values[indep_values]); + #endif +} + %} %locations @@ -52,19 +116,23 @@ static void yyerror(const char *fmt, ...); %% + /* + * A table is just a bunch of points. The lexor ignores any comments. + */ table : point | table point + /* + * An individual point is just a bunch of columns followed by one or more + * end of line characters. + */ point : columns END_LINE { - #if 0 - unsigned idx; - fprintf(stderr, "%#g", values[0]); - for (idx = 1; idx < indep_values; idx += 1) { - fprintf(stderr, ", %#g", values[idx]); - } - fprintf(stderr, " => %#g\n", values[indep_values]); - #endif + /* + * If the number of columns has been defined then we must have + * enough columns and we expect every line to have the same + * number of columns. + */ if (number_of_columns) { if (cur_columns < minimum_columns) { yyerror("Found %u columns, need at least %u.", @@ -72,15 +140,26 @@ point : columns END_LINE } else if (cur_columns != number_of_columns) { yyerror("Found %u columns, expected %u.", cur_columns, number_of_columns); - } + } else process_point(); + /* + * If this is the first point then we must have enough columns. + * If there are enough then we define this to be the number of + * columns that the file must have. + */ } else { if (cur_columns < minimum_columns) { yyerror("Found %u columns, need at least %u.", cur_columns, minimum_columns); - } else number_of_columns = cur_columns; + } else { + number_of_columns = cur_columns; + process_point(); + } } } + /* + * Each column is a real value. We only save the columns we care about. + */ columns : REAL { if (table_def->control.info.interp[0] != IVL_IGNORE_COLUMN) { @@ -103,12 +182,17 @@ columns : REAL %% +/* + * Setup the various variables, then parse the input file and then cleanup + * the lexor and the allocated memory. + */ unsigned parse_table_model(FILE *fp, vpiHandle callh, p_table_mod table) { unsigned rtn = 0; assert(table); assert(table->fields > 0); assert(table->depend > 0); + /* Initialize the variables used by the parser. */ table_def = table; indep_values = table->dims; indep_columns = table->fields; @@ -117,7 +201,9 @@ unsigned parse_table_model(FILE *fp, vpiHandle callh, p_table_mod table) values = malloc(sizeof(double)*(indep_values+1)); assert(values); in_file_name = table->file.name; + /* Parse the input file. */ init_tblmod_lexor(fp); + /* If there are errors then print a message. */ if (yyparse()) errors += 1; if (errors) { vpi_printf("ERROR: %s:%u: ", vpi_get_str(vpiFile, callh), @@ -125,14 +211,15 @@ unsigned parse_table_model(FILE *fp, vpiHandle callh, p_table_mod table) vpi_printf("Had %u error(s) while reading table file.\n", errors); rtn = 1; } + /* Cleanup the lexor and allocated memory. */ destroy_tblmod_lexor(); free(values); return rtn; } /* - * Because every parse error is reported after the newline subtract one from - * the line count. + * Currently every parse error is reported after the newline so subtract + * one from the line count. */ void yyerror(const char *fmt, ...) { From 767bb87ee25dc6319cf582aa20e19e94c7fc599a Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 22 May 2011 14:26:08 +0100 Subject: [PATCH 2/7] Fix for pr3301924. If a relative path name is passed to the Windows LoadModule function, it is applied in turn to each path in the DLL search path. For the ivl_dlopen function, we actually want to mimic the Unix behaviour, where a relative path is relative to the current working directory. On systems where the KB2264107 security fix has been applied, the CWD is excluded from the DLL search path, so we no longer get the required behaviour. This patch reworks the ivl_dlopen function to give the correct behaviour under Windows. This patch also adds a flush of the stderr stream after reporting VPI call errors. This fixes a race between the stdout and stderr streams when running the regression tests in a MinGW shell. --- vvp/ivl_dlfcn.h | 12 ++++++++++-- vvp/vpi_tasks.cc | 3 ++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/vvp/ivl_dlfcn.h b/vvp/ivl_dlfcn.h index ef68d9bb0..1406482d7 100644 --- a/vvp/ivl_dlfcn.h +++ b/vvp/ivl_dlfcn.h @@ -1,7 +1,7 @@ #ifndef __ivl_dlfcn_H #define __ivl_dlfcn_H /* - * Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -33,7 +33,15 @@ typedef shl_t ivl_dll_t; #if defined(__MINGW32__) inline ivl_dll_t ivl_dlopen(const char *name, bool global_flag) -{ return (void *)LoadLibrary(name); } +{ + static char full_name[4096]; + unsigned long length = GetFullPathName(name, sizeof(full_name), + full_name, NULL); + if ((length == 0) || (length > sizeof(full_name))) + return 0; + + return (void *)LoadLibrary(full_name); +} inline void *ivl_dlsym(ivl_dll_t dll, const char *nm) { return (void *)GetProcAddress((HINSTANCE)dll,nm);} diff --git a/vvp/vpi_tasks.cc b/vvp/vpi_tasks.cc index e76789f7a..7eee8f9c7 100644 --- a/vvp/vpi_tasks.cc +++ b/vvp/vpi_tasks.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -742,6 +742,7 @@ void print_vpi_call_errors() free(vpi_call_error_lst[idx].name); } free(vpi_call_error_lst); + fflush(stderr); } #ifdef CHECK_WITH_VALGRIND From c69f4ef7e0cfd0dc3d570c89a1384d07fe1e5d24 Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 23 May 2011 16:15:04 -0700 Subject: [PATCH 3/7] Fix spelling problem reported in pr3301924 --- vvp/main.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vvp/main.cc b/vvp/main.cc index a81664e72..68e0ef42c 100644 --- a/vvp/main.cc +++ b/vvp/main.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -266,7 +266,7 @@ int main(int argc, char*argv[]) { char *s; char basepath[4096], tmp[4096]; GetModuleFileName(NULL, tmp, sizeof tmp); - /* Convert to a short na,e to remove any embedded spaces. */ + /* Convert to a short name to remove any embedded spaces. */ GetShortPathName(tmp, basepath, sizeof basepath); s = strrchr(basepath, '\\'); if (s) *s = 0; From 35488ac254c992b4e7789828d469da3f18a2aa00 Mon Sep 17 00:00:00 2001 From: Cary R Date: Sun, 22 May 2011 21:35:45 -0700 Subject: [PATCH 4/7] Fix bug in queue average with a very large number of entries. Icarus is not actually fast enough to run into this issue in a reasonable amount of time. I discovered this by thinking about the algorithm and verified the fix with custom code. --- vpi/sys_queue.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vpi/sys_queue.c b/vpi/sys_queue.c index 13b35e220..f7312c0fc 100644 --- a/vpi/sys_queue.c +++ b/vpi/sys_queue.c @@ -84,9 +84,12 @@ uint64_t calc_average_wait_time(uint64_t high, uint64_t low, uint64_t total) /* It's a big value so calculate the average the long way. */ do { + unsigned carry = 0U; /* Copy bits from low to high until we have a bit to place * in the result or there are no bits left. */ - while ((bit >= 0) && (high < total)) { + while ((bit >= 0) && (high < total) && !carry) { + /* If the MSB is set then we will have a carry. */ + if (high > (UINT64_MAX >> 1)) carry = 1U; high <<= 1; high |= (low & 0x8000000000000000) != 0; low <<= 1; From f3497e0c66d3991c726806de7e35a4e31334c2cb Mon Sep 17 00:00:00 2001 From: Cary R Date: Sun, 22 May 2011 21:40:54 -0700 Subject: [PATCH 5/7] Report the correct gate port number. The error message was reporting the error message as zero based instead of one based. --- elaborate.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elaborate.cc b/elaborate.cc index d5b97cb51..dcb561b49 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -852,7 +852,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const cerr << get_fileline() << ": error: " << "Expression width " << sig->vector_width() << " does not match width " << instance_width - << " of logic gate array port " << idx + << " of logic gate array port " << idx+1 << "." << endl; des->errors += 1; } From 6d0e5c2e893ec338ff437fe3d53720b908ba9081 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 23 May 2011 22:08:36 +0100 Subject: [PATCH 6/7] Fix width calculation for expressions containing a specparam. This patch adds code to properly calculate the type and width of a specparam when it is used in an expression. This patch also fixes a compiler crash when an unknown identifier is used in a delay expression. --- PDelays.cc | 3 +++ elab_expr.cc | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/PDelays.cc b/PDelays.cc index 8e9ea79fc..b7cecf0c6 100644 --- a/PDelays.cc +++ b/PDelays.cc @@ -124,6 +124,9 @@ static NetExpr*calculate_val(Design*des, NetScope*scope, PExpr*expr) static NetExpr* make_delay_nets(Design*des, NetScope*scope, NetExpr*expr) { + if (expr == 0) + return 0; + if (dynamic_cast (expr)) return expr; diff --git a/elab_expr.cc b/elab_expr.cc index 1146921a4..7a7c9fa70 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1868,6 +1868,36 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) return expr_width_; } + // The width of a specparam is the width of the specparam value + // (as evaluated earlier). Note that specparams aren't fully + // supported yet, so this code is likely to need rework when + // they are. + if (gn_specify_blocks_flag) { + map::const_iterator specp; + perm_string key = peek_tail_name(path_); + if (path_.size() == 1 + && ((specp = scope->specparams.find(key)) != scope->specparams.end())) { + NetScope::spec_val_t value = (*specp).second; + if (value.type == IVL_VT_REAL) { + expr_type_ = IVL_VT_REAL; + expr_width_ = 1; + min_width_ = 1; + signed_flag_ = true; + } else { + verinum val (value.integer); + expr_type_ = IVL_VT_BOOL; + expr_width_ = val.len(); + min_width_ = expr_width_; + signed_flag_ = true; + + if (mode < LOSSLESS) + mode = LOSSLESS; + + } + return expr_width_; + } + } + // Not a net, and not a parameter? Give up on the type, but // set the width to 0. expr_type_ = IVL_VT_NO_TYPE; From feba73119a7e5aeeb9335997551f14ab5a3d3b67 Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 27 May 2011 11:43:46 -0700 Subject: [PATCH 7/7] Update fstapi.c to match the latest from GTKWave --- vpi/fstapi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vpi/fstapi.c b/vpi/fstapi.c index 69278f6c6..8ed5af6f3 100644 --- a/vpi/fstapi.c +++ b/vpi/fstapi.c @@ -3357,6 +3357,7 @@ uint64_t previous_time = UINT64_MAX; uint64_t *time_table = NULL; uint64_t tsec_nitems; int secnum = 0; +int blocks_skipped = 0; off_t blkpos = 0; uint64_t seclen, beg_tim, end_tim; uint64_t frame_uclen, frame_clen, frame_maxhandle, vc_maxhandle; @@ -3419,6 +3420,7 @@ for(;;) { if(beg_tim < xc->limit_range_start) { + blocks_skipped++; blkpos += seclen; continue; } @@ -3506,7 +3508,7 @@ for(;;) if(secnum == 0) { - if(beg_tim != time_table[0]) + if((beg_tim != time_table[0]) || (blocks_skipped)) { unsigned char *mu = malloc(frame_uclen); uint32_t sig_offs = 0;