diff --git a/StringHeap.cc b/StringHeap.cc index dc2909e69..5ac7006da 100644 --- a/StringHeap.cc +++ b/StringHeap.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2004 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2009 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 @@ -25,6 +25,11 @@ # include # include +#ifdef CHECK_WITH_VALGRIND +static char **string_pool = NULL; +static unsigned string_pool_count = 0; +#endif + StringHeap::StringHeap() { cell_base_ = 0; @@ -46,6 +51,12 @@ const char* StringHeap::add(const char*text) unsigned rem = HEAPCELL - cell_ptr_; if (rem < (len+1)) { cell_base_ = (char*)malloc(HEAPCELL); +#ifdef CHECK_WITH_VALGRIND + string_pool_count += 1; + string_pool = (char **) realloc(string_pool, + string_pool_count*sizeof(char **)); + string_pool[string_pool_count-1] = cell_base_; +#endif cell_ptr_ = 0; cell_count_ += 1; assert(cell_base_ != 0); @@ -80,6 +91,22 @@ StringHeapLex::~StringHeapLex() { } +void StringHeapLex::cleanup() +{ +#ifdef CHECK_WITH_VALGRIND + for (unsigned idx = 0 ; idx < string_pool_count ; idx += 1) { + free(string_pool[idx]); + } + free(string_pool); + string_pool = NULL; + string_pool_count = 0; + + for (unsigned idx = 0 ; idx < HASH_SIZE ; idx += 1) { + hash_table_[idx] = 0; + } +#endif +} + unsigned StringHeapLex::add_hit_count() const { return hit_count_; @@ -175,4 +202,3 @@ bool operator < (perm_string a, perm_string b) return false; } - diff --git a/StringHeap.h b/StringHeap.h index a8d76ed7d..664483d83 100644 --- a/StringHeap.h +++ b/StringHeap.h @@ -1,7 +1,7 @@ #ifndef __StringHeap_H #define __StringHeap_H /* - * Copyright (c) 2002-2004 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2009 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 @@ -104,6 +104,7 @@ class StringHeapLex : private StringHeap { unsigned add_count() const; unsigned add_hit_count() const; + void cleanup(); private: enum { HASH_SIZE = 4096 }; diff --git a/compiler.h b/compiler.h index 5ced0b0b0..934344b74 100644 --- a/compiler.h +++ b/compiler.h @@ -202,5 +202,6 @@ struct sfunc_return_type { extern const struct sfunc_return_type* lookup_sys_func(const char*name); extern int load_sys_func_table(const char*path); +extern void cleanup_sys_func_table(); #endif diff --git a/config.h.in b/config.h.in index 7ba02b763..d8f3c9161 100644 --- a/config.h.in +++ b/config.h.in @@ -1,7 +1,7 @@ #ifndef __config_H /* -*- c++ -*- */ #define __config_H /* - * Copyright (c) 2001 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2009 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 @@ -50,4 +50,10 @@ # include #endif +/* + * Define this if you want to compile vvp with memory freeing and + * special valgrind hooks for the memory pools. + */ +# undef CHECK_WITH_VALGRIND + #endif /* __config_H */ diff --git a/elaborate.cc b/elaborate.cc index 3dec83463..935d1b846 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3786,14 +3786,12 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const /* Do not elaborate specify delay paths if this feature is turned off. */ - if (!gn_specify_blocks_flag) - return; + if (!gn_specify_blocks_flag) return; ivl_assert(*this, conditional || (condition==0)); ndelays = delays.size(); - if (ndelays > 12) - ndelays = 12; + if (ndelays > 12) ndelays = 12; /* Print a warning if we find default and `timescale based * delays in the design, since this is likely an error. */ @@ -4453,6 +4451,7 @@ Design* elaborate(listroots) NetScope *scope = root_elems[i]->scope; rc &= rmod->elaborate(des, scope); + delete root_elems[i]; } if (rc == false) { diff --git a/lexor.lex b/lexor.lex index d62325d87..954a2ab61 100644 --- a/lexor.lex +++ b/lexor.lex @@ -1374,3 +1374,17 @@ void reset_lexor() /* Announce the first file name. */ yylloc.text = set_file_name(strdupnew(vl_file.c_str())); } + +/* + * Modern version of flex (>=2.5.9) can clean up the scanner data. + */ +void destroy_lexor() +{ +# ifdef FLEX_SCANNER +# if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5 +# if defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION >= 9 + yylex_destroy(); +# endif +# endif +# endif +} diff --git a/main.cc b/main.cc index ad4de617a..c80b2baed 100644 --- a/main.cc +++ b/main.cc @@ -77,7 +77,7 @@ extern "C" const char*optarg; /* Count errors detected in flag processing. */ unsigned flag_errors = 0; -const char*basedir = "."; +const char*basedir = strdup("."); /* * These are the language support control flags. These support which @@ -280,7 +280,7 @@ static void parm_to_flagmap(const string&flag) unsigned off = flag.find('='); if (off > flag.size()) { key = flag; - value = ""; + value = strdup(""); } else { key = flag.substr(0, off); @@ -399,6 +399,7 @@ static void read_iconfig_file(const char*ipath) } if (strcmp(buf, "basedir") == 0) { + free((char *)basedir); basedir = strdup(cp); } else if (strcmp(buf, "debug") == 0) { @@ -472,6 +473,7 @@ static void read_iconfig_file(const char*ipath) flags["VPI_MODULE_LIST"] = vpi_module_list; } else if (strcmp(buf, "out") == 0) { + free((char *)flags["-o"]); flags["-o"] = strdup(cp); } else if (strcmp(buf, "sys_func") == 0) { @@ -529,6 +531,7 @@ static void read_iconfig_file(const char*ipath) } } + fclose(ifile); } extern Design* elaborate(list root); @@ -555,6 +558,30 @@ inline static void times(struct tms *) { } inline static double cycles_diff(struct tms *a, struct tms *b) { return 0; } #endif // ! defined(HAVE_TIMES) +static void EOC_cleanup(void) +{ + cleanup_sys_func_table(); + + for (list::iterator suf = library_suff.begin() ; + suf != library_suff.end() ; suf ++ ) { + free((char *)*suf); + } + library_suff.clear(); + + free((char *) basedir); + free(ivlpp_string); + free(depfile_name); + + for (map::iterator flg = flags.begin() ; + flg != flags.end() ; flg ++ ) { + free((char *)flg->second); + } + flags.clear(); + + lex_strings.cleanup(); + filename_strings.cleanup(); +} + int main(int argc, char*argv[]) { bool help_flag = false; @@ -567,11 +594,11 @@ int main(int argc, char*argv[]) struct tms cycles[5]; - library_suff.push_back(".v"); + library_suff.push_back(strdup(".v")); vpi_module_list = strdup("system"); flags["VPI_MODULE_LIST"] = vpi_module_list; - flags["-o"] = "a.out"; + flags["-o"] = strdup("a.out"); min_typ_max_flag = TYP; min_typ_max_warn = 10; @@ -933,6 +960,8 @@ int main(int argc, char*argv[]) << endl; } + delete des; + EOC_cleanup(); return 0; errors_summary: diff --git a/net_nex_input.cc b/net_nex_input.cc index aeddc73eb..a1f81829c 100644 --- a/net_nex_input.cc +++ b/net_nex_input.cc @@ -114,6 +114,11 @@ NexusSet* NetESelect::nex_input(bool rem_out) } result->add(*tmp); delete tmp; + /* See the comment for NetESignal below. */ + if (base_) { + cerr << get_fileline() << ": warning: @* is sensitive to all " + "bits in '" << *expr_ << "'." << endl; + } return result; } @@ -133,7 +138,23 @@ NexusSet* NetESFunc::nex_input(bool rem_out) NexusSet* NetESignal::nex_input(bool rem_out) { + /* + * This is not what I would expect for the various selects (bit, + * part, index, array). This code adds all the bits/array words + * instead of building the appropriate select and then using it + * as the trigger. Other simulators also add everything. + */ NexusSet*result = new NexusSet; + /* If we have an array index add it to the sensitivity list. */ + if (word_) { + NexusSet*tmp; + tmp = word_->nex_input(rem_out); + result->add(*tmp); + delete tmp; + cerr << get_fileline() << ": warning: @* is sensitive to all " + << net_->array_count() << " words in array '" + << name() << "'." << endl; + } for (unsigned idx = 0 ; idx < net_->pin_count() ; idx += 1) result->add(net_->pin(idx).nexus()); diff --git a/parse.y b/parse.y index d25591943..44f09da35 100644 --- a/parse.y +++ b/parse.y @@ -719,6 +719,7 @@ delay_value_simple description : module | udp_primitive + | config_declaration | nature_declaration | discipline_declaration | KK_attribute '(' IDENTIFIER ',' STRING ',' STRING ')' @@ -783,6 +784,54 @@ nature_item { delete[] $3; } ; +config_declaration + : K_config IDENTIFIER ';' + K_design lib_cell_identifiers ';' + list_of_config_rule_statements + K_endconfig + { cerr << @1 << ": sorry: config declarations are not supported and " + "will be skipped." << endl; + delete[] $2; + } + ; + +lib_cell_identifiers + : /* The BNF implies this can be blank, but I'm not sure exactly what + * this means. */ + | lib_cell_identifiers lib_cell_id + ; + +list_of_config_rule_statements + : /* config rules are optional. */ + | list_of_config_rule_statements config_rule_statement + ; + +config_rule_statement + : K_default K_liblist list_of_libraries ';' + | K_instance hierarchy_identifier K_liblist list_of_libraries ';' + { delete $2; } + | K_instance hierarchy_identifier K_use lib_cell_id opt_config ';' + { delete $2; } + | K_cell lib_cell_id K_liblist list_of_libraries ';' + | K_cell lib_cell_id K_use lib_cell_id opt_config ';' + ; + +opt_config + : /* The use clause takse an optional :config. */ + | ':' K_config + +lib_cell_id + : IDENTIFIER + { delete[] $1; } + | IDENTIFIER '.' IDENTIFIER + { delete[] $1; delete[] $3; } + ; + +list_of_libraries + : /* A NULL library means use the parents cell library. */ + | list_of_libraries IDENTIFIER + { delete[] $2; } + drive_strength : '(' dr_strength0 ',' dr_strength1 ')' { $$.str0 = $2.str0; diff --git a/parse_misc.h b/parse_misc.h index 0a33c6999..8b58aa4e8 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -60,6 +60,8 @@ extern void VLerror(const YYLTYPE&loc, const char*msg); #define yywarn VLwarn extern void VLwarn(const YYLTYPE&loc, const char*msg); +extern void destroy_lexor(); + extern ostream& operator << (ostream&, const YYLTYPE&loc); extern unsigned error_count, warn_count; diff --git a/pform.cc b/pform.cc index 69ca9de36..1e881c80f 100644 --- a/pform.cc +++ b/pform.cc @@ -2170,6 +2170,7 @@ int pform_parse(const char*path, FILE*file) error_count += 1; } + destroy_lexor(); return error_count; } diff --git a/sys_funcs.cc b/sys_funcs.cc index a82ac0b62..4d2002606 100644 --- a/sys_funcs.cc +++ b/sys_funcs.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2009 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 @@ -46,6 +46,16 @@ struct sfunc_return_type_cell : sfunc_return_type { static struct sfunc_return_type_cell*sfunc_stack = 0; +void cleanup_sys_func_table() +{ + struct sfunc_return_type_cell *next, *cur = sfunc_stack; + while (cur) { + next = cur->next; + delete cur; + cur = next; + } +} + const struct sfunc_return_type* lookup_sys_func(const char*name) { /* First, try to find then name in the function stack. */ @@ -186,7 +196,7 @@ int load_sys_func_table(const char*path) fprintf(stderr, "%s:%s: Unknown type: %s\n", path, name, stype); } + fclose(fd); return 0; } - diff --git a/tgt-vvp/draw_mux.c b/tgt-vvp/draw_mux.c index 0ccd46cf7..592afea73 100644 --- a/tgt-vvp/draw_mux.c +++ b/tgt-vvp/draw_mux.c @@ -19,9 +19,6 @@ # include "vvp_priv.h" # include -#ifdef HAVE_MALLOC_H -# include -#endif # include # include diff --git a/tgt-vvp/draw_net_input.c b/tgt-vvp/draw_net_input.c index 5f1394a8e..c65e826f0 100644 --- a/tgt-vvp/draw_net_input.c +++ b/tgt-vvp/draw_net_input.c @@ -505,6 +505,16 @@ static char* draw_island_port(ivl_island_t island, /* Omit LPMPART_BI device pin-data(0) drivers. */ # define OMIT_PART_BI_DATA 0x0001 +static ivl_nexus_ptr_t *drivers = 0x0; +static unsigned adrivers = 0; + +void EOC_cleanup_drivers() +{ + free(drivers); + drivers = NULL; + adrivers = 0; +} + char* draw_net_input_x(ivl_nexus_t nex, ivl_nexus_ptr_t omit_ptr, int omit_flags, struct vvp_nexus_data*nex_data) @@ -515,8 +525,6 @@ char* draw_net_input_x(ivl_nexus_t nex, unsigned idx; int level; unsigned ndrivers = 0; - static ivl_nexus_ptr_t *drivers = 0x0; - static unsigned adrivers = 0; const char*resolv_type; diff --git a/tgt-vvp/eval_real.c b/tgt-vvp/eval_real.c index 304f8921b..23ebcac4f 100644 --- a/tgt-vvp/eval_real.c +++ b/tgt-vvp/eval_real.c @@ -22,9 +22,6 @@ */ # include "vvp_priv.h" # include -#ifdef HAVE_MALLOC_H -# include -#endif # include # include # include @@ -55,9 +52,6 @@ static int draw_binary_real(ivl_expr_t expr) { int l, r = -1; - /* If the opcode is a vector only opcode then the sub expression - * must not be a real expression, so use vector evaluation and - * then convert that result to a real value. */ switch (ivl_expr_opcode(expr)) { case 'E': case 'N': @@ -70,22 +64,8 @@ static int draw_binary_real(ivl_expr_t expr) case 'A': case 'O': case 'X': - { - struct vector_info vi; - int res; - const char*sign_flag; - - vi = draw_eval_expr(expr, STUFF_OK_XZ); - res = allocate_word(); - sign_flag = ivl_expr_signed(expr)? "/s" : ""; - fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n", - sign_flag, res, vi.base, vi.wid); - - fprintf(vvp_out, " %%cvt/ri %d, %d;\n", res, res); - - clr_vector(vi); - return res; - } + /* These should be caught in draw_eval_real(). */ + assert(0); } l = draw_eval_real(ivl_expr_oper1(expr)); @@ -120,16 +100,20 @@ static int draw_binary_real(ivl_expr_t expr) int lab_out = local_count++; int lab_r = local_count++; /* If r is NaN, the go out and accept l as result. */ - fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", r, r); - fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_out); + fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", r, r); + fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, + lab_out); /* If l is NaN, the go out and accept r as result. */ - fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", l, l); - fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_r); + fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", l, l); + fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, + lab_r); /* If l <= r then go out. */ - fprintf(vvp_out, " %%cmp/wr %d, %d;\n", r, l); - fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 5;\n", thread_count, lab_out); + fprintf(vvp_out, " %%cmp/wr %d, %d;\n", r, l); + fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 5;\n", thread_count, + lab_out); /* At this point we know we want r as the result. */ - fprintf(vvp_out, "T_%d.%d %%mov/wr %d, %d;\n", thread_count, lab_r, l, r); + fprintf(vvp_out, "T_%d.%d %%mov/wr %d, %d;\n", thread_count, + lab_r, l, r); fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out); break; } @@ -138,16 +122,20 @@ static int draw_binary_real(ivl_expr_t expr) int lab_out = local_count++; int lab_r = local_count++; /* If r is NaN, the go out and accept l as result. */ - fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", r, r); - fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_out); + fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", r, r); + fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, + lab_out); /* If l is NaN, the go out and accept r as result. */ - fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", l, l); - fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_r); + fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", l, l); + fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, + lab_r); /* if l >= r then go out. */ - fprintf(vvp_out, " %%cmp/wr %d, %d;\n", l, r); - fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 5;\n", thread_count, lab_out); + fprintf(vvp_out, " %%cmp/wr %d, %d;\n", l, r); + fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 5;\n", thread_count, + lab_out); - fprintf(vvp_out, "T_%d.%d %%mov/wr %d, %d;\n", thread_count, lab_r, l, r); + fprintf(vvp_out, "T_%d.%d %%mov/wr %d, %d;\n", thread_count, + lab_r, l, r); fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out); break; } @@ -508,8 +496,10 @@ static int draw_unary_real(ivl_expr_t expr) return sub; } - fprintf(vvp_out, "; XXXX unary (%c) on sube in %d\n", ivl_expr_opcode(expr), sub); - fprintf(stderr, "XXXX evaluate unary (%c) on sube in %d\n", ivl_expr_opcode(expr), sub); + fprintf(vvp_out, "; XXXX unary (%c) on sube in %d\n", + ivl_expr_opcode(expr), sub); + fprintf(stderr, "XXXX evaluate unary (%c) on sube in %d\n", + ivl_expr_opcode(expr), sub); return 0; } @@ -517,6 +507,27 @@ int draw_eval_real(ivl_expr_t expr) { int res = 0; + /* If this expression/sub-expression is not real then we need + * to evaluate it as a bit value and then convert the bit based + * result to a real value. This is required to get integer + * division to work correctly. */ + if (ivl_expr_value(expr) != IVL_VT_REAL) { + struct vector_info vi; + int res; + const char*sign_flag; + + vi = draw_eval_expr(expr, STUFF_OK_XZ); + res = allocate_word(); + sign_flag = ivl_expr_signed(expr)? "/s" : ""; + fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n", sign_flag, res, + vi.base, vi.wid); + + fprintf(vvp_out, " %%cvt/ri %d, %d;\n", res, res); + + clr_vector(vi); + return res; + } + switch (ivl_expr_type(expr)) { case IVL_EX_BINARY: diff --git a/tgt-vvp/vvp.c b/tgt-vvp/vvp.c index d8e847a86..8f0cb882e 100644 --- a/tgt-vvp/vvp.c +++ b/tgt-vvp/vvp.c @@ -140,6 +140,7 @@ int target_design(ivl_design_t des) } fclose(vvp_out); + EOC_cleanup_drivers(); return rc + vvp_errors; } diff --git a/tgt-vvp/vvp_priv.h b/tgt-vvp/vvp_priv.h index fda6bb5ad..f67e94506 100644 --- a/tgt-vvp/vvp_priv.h +++ b/tgt-vvp/vvp_priv.h @@ -1,7 +1,7 @@ #ifndef __vvp_priv_H #define __vvp_priv_H /* - * Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2009 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 @@ -141,6 +141,7 @@ struct vvp_nexus_data { * cache it. */ extern const char* draw_net_input(ivl_nexus_t nex); +void EOC_cleanup_drivers(); /* * See draw_net_input.c for details on draw_net_input_x. (It would be diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 3d6b119ca..160044b1a 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -665,25 +665,12 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr) ivl_drive_t str0, str1; int level; - int ninp = ivl_logic_pins(lptr) - 1; - typedef const char*const_charp; - const_charp*input_strings = calloc(ninp, sizeof(const_charp)); - - for (pdx = 0 ; pdx < ninp ; pdx += 1) { - ivl_nexus_t nex = ivl_logic_pin(lptr, pdx+1); - if (nex == 0) { - /* Only UDPs can have unconnected inputs. */ - assert(ivl_logic_type(lptr) == IVL_LO_UDP); - input_strings[pdx] = 0; - } else { - input_strings[pdx] = draw_net_input(nex); - } - } + int ninp; + const char **input_strings; switch (ivl_logic_type(lptr)) { case IVL_LO_UDP: - free(input_strings); draw_udp_in_scope(lptr); return; @@ -706,7 +693,6 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr) /* Skip pullup and pulldown objects. Things that have pull objects as inputs will instead generate the appropriate C symbol. */ - free(input_strings); return; case IVL_LO_AND: @@ -1862,12 +1848,14 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) fprintf(vvp_out, ">;\n"); break; case IVL_EX_REALNUM: - fprintf(vvp_out, "P_%p .param/real \"%s\" %d %d, %s; value=%#g\n", - par, ivl_parameter_basename(par), - ivl_file_table_index(ivl_parameter_file(par)), - ivl_parameter_lineno(par), - draw_Cr_to_string(ivl_expr_dvalue(pex)), - ivl_expr_dvalue(pex)); + { char *res = draw_Cr_to_string(ivl_expr_dvalue(pex)); + fprintf(vvp_out, "P_%p .param/real \"%s\" %d %d, %s; " + "value=%#g\n", par, ivl_parameter_basename(par), + ivl_file_table_index(ivl_parameter_file(par)), + ivl_parameter_lineno(par), res, + ivl_expr_dvalue(pex)); + free(res); + } break; default: fprintf(vvp_out, "; parameter type %d unsupported\n", diff --git a/vpi/sys_display.c b/vpi/sys_display.c index 3b8d5d7d3..fbbbcc768 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -263,7 +263,7 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, s_vpi_value value; char *result, *fmtb; unsigned int size; - unsigned int ini_size = 256; /* The initial size of the buffer. */ + unsigned int ini_size = 512; /* The initial size of the buffer. */ /* Make sure the width fits in the initial buffer. */ if (width+1 > ini_size) ini_size = width + 1; @@ -488,12 +488,15 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, /* If the default buffer is too small make it big enough. * - * This size may not always be correct, but if the default - * size is big enough for any practical value then all we - * need to worry about is extra padding and this should work - * correctly for that case, but since this uses the standard - * sprintf() routine we don't know exactly what it will do. */ + * This should always give enough space. The maximum double + * is approximately 1.8*10^308 this means we could need 310 + * characters plus the precision. We'll use 320 to give some + * extra buffer space. The initial buffers size should work + * for most cases, but to be safe we add the precision to + * the maximum size (think %6.300f when passed 1.2*10^308). */ size = width + 1; + if (size < 320) size = 320; + size += prec; if (size > ini_size) result = realloc(result, size*sizeof(char)); sprintf(result, fmtb+1, value.value.real); size = strlen(result) + 1; diff --git a/vpi/sys_lxt.c b/vpi/sys_lxt.c index a784a4643..eb53451a3 100644 --- a/vpi/sys_lxt.c +++ b/vpi/sys_lxt.c @@ -17,10 +17,9 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -# include "sys_priv.h" # include "lxt_write.h" -# include "vcd_priv.h" # include "sys_priv.h" +# include "vcd_priv.h" /* * This file contains the implementations of the LXT related @@ -39,6 +38,29 @@ # include "stringheap.h" +static char *dump_path = NULL; +static struct lt_trace *dump_file = NULL; + +struct vcd_info { + vpiHandle item; + vpiHandle cb; + struct t_vpi_time time; + struct lt_symbol *sym; + struct vcd_info *next; + struct vcd_info *dmp_next; + int scheduled; +}; + + +static struct vcd_info *vcd_list = NULL; +static struct vcd_info *vcd_dmp_list = NULL; +static PLI_UINT64 vcd_cur_time = 0; +static int dump_is_off = 0; +static long dump_limit = 0; +static int dump_is_full = 0; +static int finish_status = 0; + + static enum lxm_optimum_mode_e { LXM_NONE = 0, LXM_SPACE = 1, @@ -140,30 +162,6 @@ static char *create_full_name(const char *name) return n; } - -static char *dump_path = 0; -static struct lt_trace *dump_file = 0; - -struct vcd_info { - vpiHandle item; - vpiHandle cb; - struct t_vpi_time time; - struct lt_symbol *sym; - struct vcd_info *next; - struct vcd_info *dmp_next; - int scheduled; -}; - - -static struct vcd_info*vcd_list = 0; -static struct vcd_info*vcd_dmp_list = 0; -static PLI_UINT64 vcd_cur_time = 0; -static int dump_is_off = 0; -static long dump_limit = 0; -static int dump_is_full = 0; -static int finish_status = 0; - - static void show_this_item(struct vcd_info*info) { s_vpi_value value; @@ -434,7 +432,8 @@ static PLI_INT32 sys_dumpall_calltf(PLI_BYTE8*name) static void *close_dumpfile(void) { lt_close(dump_file); - return (dump_file = NULL); + dump_file = NULL; + return NULL; } static void open_dumpfile(vpiHandle callh) @@ -552,7 +551,7 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) case vpiNet: type = "wire"; if(0){ case vpiMemoryWord: - if (vpi_get(vpiConstantSelect, item) == 0) { + if (vpi_get(vpiConstantSelect, item) == 0) { /* Turn a non-constant array word select into a * constant word select. */ vpiHandle array = vpi_handle(vpiParent, item); @@ -592,12 +591,12 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) info = malloc(sizeof(*info)); info->time.type = vpiSimTime; - info->item = item; - info->sym = lt_symbol_add(dump_file, ident, - 0 /* array rows */, - vpi_get(vpiLeftRange, item), - vpi_get(vpiRightRange, item), - LT_SYM_F_BITS); + info->item = item; + info->sym = lt_symbol_add(dump_file, ident, + 0 /* array rows */, + vpi_get(vpiLeftRange, item), + vpi_get(vpiRightRange, item), + LT_SYM_F_BITS); info->scheduled = 0; cb.time = &info->time; diff --git a/vpi/sys_lxt2.c b/vpi/sys_lxt2.c index 016aeb8c2..5eddf6ad4 100644 --- a/vpi/sys_lxt2.c +++ b/vpi/sys_lxt2.c @@ -17,10 +17,9 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -# include "sys_priv.h" # include "lxt2_write.h" -# include "vcd_priv.h" # include "sys_priv.h" +# include "vcd_priv.h" /* * This file contains the implementations of the LXT2 related @@ -39,6 +38,29 @@ # include "stringheap.h" +static char *dump_path = NULL; +static struct lxt2_wr_trace *dump_file = NULL; + +struct vcd_info { + vpiHandle item; + vpiHandle cb; + struct t_vpi_time time; + struct lxt2_wr_symbol *sym; + struct vcd_info *next; + struct vcd_info *dmp_next; + int scheduled; +}; + + +static struct vcd_info *vcd_list = NULL; +static struct vcd_info *vcd_dmp_list = NULL; +static PLI_UINT64 vcd_cur_time = 0; +static int dump_is_off = 0; +static long dump_limit = 0; +static int dump_is_full = 0; +static int finish_status = 0; + + static enum lxm_optimum_mode_e { LXM_NONE = 0, LXM_SPACE = 1, @@ -141,30 +163,6 @@ static char *create_full_name(const char *name) return n; } - -static char *dump_path = 0; -static struct lxt2_wr_trace *dump_file = 0; - -struct vcd_info { - vpiHandle item; - vpiHandle cb; - struct t_vpi_time time; - struct lxt2_wr_symbol *sym; - struct vcd_info *next; - struct vcd_info *dmp_next; - int scheduled; -}; - - -static struct vcd_info*vcd_list = 0; -static struct vcd_info*vcd_dmp_list = 0; -static PLI_UINT64 vcd_cur_time = 0; -static int dump_is_off = 0; -static long dump_limit = 0; -static int dump_is_full = 0; -static int finish_status = 0; - - static void show_this_item(struct vcd_info*info) { s_vpi_value value; @@ -436,8 +434,8 @@ static PLI_INT32 sys_dumpall_calltf(PLI_BYTE8*name) static void *close_dumpfile(void) { lxt2_wr_close(dump_file); - dump_file = 0; - return 0; + dump_file = NULL; + return NULL; } static void open_dumpfile(vpiHandle callh) @@ -604,12 +602,12 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) info = malloc(sizeof(*info)); info->time.type = vpiSimTime; - info->item = item; - info->sym = lxt2_wr_symbol_add(dump_file, ident, - 0 /* array rows */, - vpi_get(vpiLeftRange, item), - vpi_get(vpiRightRange, item), - LXT2_WR_SYM_F_BITS); + info->item = item; + info->sym = lxt2_wr_symbol_add(dump_file, ident, + 0 /* array rows */, + vpi_get(vpiLeftRange, item), + vpi_get(vpiRightRange, item), + LXT2_WR_SYM_F_BITS); info->scheduled = 0; cb.time = &info->time; diff --git a/vpi/sys_vcd.c b/vpi/sys_vcd.c index 12780d78c..6fbbfd95c 100644 --- a/vpi/sys_vcd.c +++ b/vpi/sys_vcd.c @@ -18,6 +18,7 @@ */ # include "sys_priv.h" +# include "vcd_priv.h" /* * This file contains the implementations of the VCD related @@ -33,10 +34,29 @@ #ifdef HAVE_MALLOC_H # include #endif -# include "vcd_priv.h" -static char*dump_path = 0; -static FILE*dump_file = 0; +static char *dump_path = NULL; +static FILE *dump_file = NULL; + +struct vcd_info { + vpiHandle item; + vpiHandle cb; + struct t_vpi_time time; + const char *ident; + struct vcd_info *next; + struct vcd_info *dmp_next; + int scheduled; +}; + + +static struct vcd_info *vcd_list = NULL; +static struct vcd_info *vcd_dmp_list = NULL; +static PLI_UINT64 vcd_cur_time = 0; +static int dump_is_off = 0; +static long dump_limit = 0; +static int dump_is_full = 0; +static int finish_status = 0; + static const char*units_names[] = { "s", @@ -47,17 +67,6 @@ static const char*units_names[] = { "fs" }; -struct vcd_info { - vpiHandle item; - vpiHandle cb; - struct t_vpi_time time; - const char*ident; - struct vcd_info* next; - struct vcd_info* dmp_next; - int scheduled; -}; - - static char vcdid[8] = "!"; static void gen_new_vcd_id(void) @@ -76,14 +85,6 @@ static void gen_new_vcd_id(void) } } -static struct vcd_info *vcd_list = 0; -static struct vcd_info *vcd_dmp_list = 0; -PLI_UINT64 vcd_cur_time = 0; -static int dump_is_off = 0; -static long dump_limit = 0; -static int dump_is_full = 0; -static int finish_status = 0; - static char *truncate_bitvec(char *s) { char l, r; @@ -480,7 +481,6 @@ static PLI_INT32 sys_dumplimit_calltf(PLI_BYTE8 *name) s_vpi_value val; /* Get the value and set the dump limit. */ - assert(argv); val.format = vpiIntVal; vpi_get_value(vpi_scan(argv), &val); dump_limit = val.value.integer; @@ -520,13 +520,13 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) case vpiNet: type = "wire"; if(0){ case vpiMemoryWord: - if (vpi_get(vpiConstantSelect, item) == 0) { + if (vpi_get(vpiConstantSelect, item) == 0) { /* Turn a non-constant array word select into a * constant word select. */ vpiHandle array = vpi_handle(vpiParent, item); PLI_INT32 index = vpi_get(vpiIndex, item); item = vpi_handle_by_index(array, index); - } + } case vpiIntegerVar: case vpiTimeVar: case vpiReg: type = "reg"; } @@ -581,9 +581,8 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) cb.reason = cbValueChange; cb.cb_rtn = variable_cb_1; - - info->next = vcd_list; - info->dmp_next = 0; + info->dmp_next = 0; + info->next = vcd_list; vcd_list = info; info->cb = vpi_register_cb(&cb); diff --git a/vvp/array.cc b/vvp/array.cc index 5b8522f71..ec3f112f3 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -599,13 +599,11 @@ static vpiHandle array_iterator_scan(vpiHandle ref, int) unsigned use_index = obj->next; obj->next += 1; - if (obj->array->nets) - return obj->array->nets[obj->next]; + if (obj->array->nets) return obj->array->nets[use_index]; - assert(obj->array->vals4); + assert(obj->array->vals4 || obj->array->valsr); - if (obj->array->vals_words == 0) - array_make_vals_words(obj->array); + if (obj->array->vals_words == 0) array_make_vals_words(obj->array); return &(obj->array->vals_words[use_index].as_word); } @@ -850,6 +848,7 @@ void array_set_word(vvp_array_t arr, unsigned address, double val) assert(arr->nets == 0); arr->valsr->set_word(address, val); + array_word_change(arr, address); } vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address) @@ -1146,7 +1145,11 @@ void vvp_fun_arrayport_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit addr_valid_flag = vector4_to_value(bit, addr_); if (! addr_valid_flag) addr_ = arr_->array_count; - port.ptr()->send_vec4(array_get_word(arr_,addr_), 0); + if (vpi_array_is_real(arr_)) + port.ptr()->send_real(array_get_word_r(arr_, addr_), 0); + else + port.ptr()->send_vec4(array_get_word(arr_,addr_), 0); + break; default: @@ -1157,11 +1160,13 @@ void vvp_fun_arrayport_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit void vvp_fun_arrayport_sa::check_word_change(unsigned long addr) { - if (addr != addr_) - return; + if (addr != addr_) return; - vvp_vector4_t bit = array_get_word(arr_, addr_); - net_->send_vec4(bit, 0); + if (vpi_array_is_real(arr_)) { + net_->send_real(net_->out, array_get_word_r(arr_, addr_), 0); + } else { + net_->send_vec4(net_->out, array_get_word(arr_, addr_), 0); + } } class vvp_fun_arrayport_aa : public vvp_fun_arrayport, public automatic_hooks_s { @@ -1243,9 +1248,16 @@ void vvp_fun_arrayport_aa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit case 0: // Address input addr_valid_flag = vector4_to_value(bit, *addr); - if (! addr_valid_flag) - *addr = arr_->array_count; - port.ptr()->send_vec4(array_get_word(arr_,*addr), context); + if (! addr_valid_flag) *addr = arr_->array_count; + if (vpi_array_is_real(arr_)) { + port.ptr()->send_real(port.ptr()->out, + array_get_word_r(arr_, *addr), + context); + } else { + port.ptr()->send_vec4(port.ptr()->out, + array_get_word(arr_, *addr), + context); + } break; default: @@ -1269,8 +1281,13 @@ void vvp_fun_arrayport_aa::check_word_change(unsigned long addr) if (addr != *port_addr) return; - vvp_vector4_t bit = array_get_word(arr_, addr); - net_->send_vec4(bit, vthread_get_wt_context()); + if (vpi_array_is_real(arr_)) { + net_->send_real(net_->out, array_get_word_r(arr_, addr), + vthread_get_wt_context()); + } else { + net_->send_vec4(net_->out, array_get_word(arr_, addr), + vthread_get_wt_context()); + } } static void array_attach_port(vvp_array_t array, vvp_fun_arrayport*fun) @@ -1306,11 +1323,17 @@ void array_word_change(vvp_array_t array, unsigned long addr) } if (cur->cb_data.cb_rtn != 0) { - if (cur->cb_data.value) - vpip_vec4_get_value(array->vals4->get_word(addr), - array->vals_width, - array->signed_flag, - cur->cb_data.value); + if (cur->cb_data.value) { + if (vpi_array_is_real(array)) { + vpip_real_get_value(array->valsr->get_word(addr), + cur->cb_data.value); + } else { + vpip_vec4_get_value(array->vals4->get_word(addr), + array->vals_width, + array->signed_flag, + cur->cb_data.value); + } + } callback_execute(cur); prev = cur; diff --git a/vvp/main.cc b/vvp/main.cc index 539e277d3..76d66a168 100644 --- a/vvp/main.cc +++ b/vvp/main.cc @@ -207,6 +207,7 @@ int main(int argc, char*argv[]) FILE *logfile = 0x0; extern void vpi_set_vlog_info(int, char**); extern bool stop_is_finish; + extern int stop_is_finish_exit_code; #ifdef __MINGW32__ /* In the Windows world, we get the first module path @@ -225,7 +226,7 @@ int main(int argc, char*argv[]) /* For non-interactive runs we do not want to run the interactive * debugger, so make $stop just execute a $finish. */ stop_is_finish = false; - while ((opt = getopt(argc, argv, "+hl:M:m:nsvV")) != EOF) switch (opt) { + while ((opt = getopt(argc, argv, "+hl:M:m:nNsvV")) != EOF) switch (opt) { case 'h': fprintf(stderr, "Usage: vvp [options] input-file [+plusargs...]\n" @@ -236,6 +237,7 @@ int main(int argc, char*argv[]) " -M - Clear VPI module path\n" " -m module Load vpi module.\n" " -n Non-interactive ($stop = $finish).\n" + " -N Same as -n, but exit code is 1 instead of 0\n" " -s $stop right away.\n" " -v Verbose progress messages.\n" " -V Print the version information.\n" ); @@ -257,6 +259,10 @@ int main(int argc, char*argv[]) case 'n': stop_is_finish = true; break; + case 'N': + stop_is_finish = true; + stop_is_finish_exit_code = 1; + break; case 's': schedule_stop(0); break; diff --git a/vvp/stop.cc b/vvp/stop.cc index 889f1b90f..a404f1325 100644 --- a/vvp/stop.cc +++ b/vvp/stop.cc @@ -44,6 +44,7 @@ struct __vpiScope*stop_current_scope = 0; bool stop_is_finish; /* When set, $stop acts like $finish (set in main.cc). */ +int stop_is_finish_exit_code = 0; #ifndef USE_READLINE static char* readline_stub(const char*prompt) @@ -490,6 +491,7 @@ void stop_handler(int rc) /* The user may be running in a non-interactive environment, so * they want $stop and to be the same as $finish. */ if (stop_is_finish) { + vpip_set_return_value(stop_is_finish_exit_code); schedule_finish(0); return; } diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 82f82ae4a..74acb2c13 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -1002,7 +1002,8 @@ static vpiHandle find_name(const char *name, vpiHandle handle) if (!strcmp(name, nm)) { rtn = ref->intern[i]; break; - } else if (vpi_get(vpiType, ref->intern[i]) == vpiMemory) { + } else if (vpi_get(vpiType, ref->intern[i]) == vpiMemory || + vpi_get(vpiType, ref->intern[i]) == vpiNetArray) { /* We need to iterate on the words */ vpiHandle word_i, word_h; word_i = vpi_iterate(vpiMemoryWord, ref->intern[i]); diff --git a/vvp/vvp.man b/vvp/vvp.man index c680c91cb..d1c0e3c9c 100644 --- a/vvp/vvp.man +++ b/vvp/vvp.man @@ -4,7 +4,7 @@ vvp - Icarus Verilog vvp runtime engine .SH SYNOPSIS .B vvp -[-sv] [-Mpath] [-mmodule] [-llogfile] inputfile [extended-args...] +[-nNsvV] [-Mpath] [-mmodule] [-llogfile] inputfile [extended-args...] .SH DESCRIPTION .PP @@ -46,6 +46,11 @@ This flag makes $stop or a a synonym for $finish. It can be used to give the program a more meaningful interface when running in a non-interactive environment. .TP 8 +.B -N +This flag does the same thing as -n, but results in an exit code +of 1 if the stimulation calls $stop. It can be used to indicate a +simulation failure when running a testbench. +.TP 8 .B -s Stop. This will cause the simulation to stop in the beginning, before any events are scheduled. This allows the interactive user to get diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index c6becdb30..42ea332cd 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -1422,6 +1422,10 @@ vvp_realarray_t::vvp_realarray_t(unsigned wor) : words_(wor) { array_ = new double[words_]; + // Real array words have a default value of zero. + for (unsigned idx = 0 ; idx < words_; idx += 1) { + array_[idx] = 0.0; + } } vvp_realarray_t::~vvp_realarray_t()