From 9619eb3a0dfe8bb921bc28a91fec2cb737511e34 Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Tue, 19 May 2009 16:41:22 -0700 Subject: [PATCH 1/8] Remove fresh const lint It looks pretty stupid and non-c++-y, but it does remove two compiler warnings vvp/stop.cc: In function 'void stop_handler(int)': vvp/stop.cc:492: warning: deprecated conversion from string constant to 'char*' vvp/stop.cc:493: warning: deprecated conversion from string constant to 'char*' --- vvp/stop.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/vvp/stop.cc b/vvp/stop.cc index 0b6aad7a3..889f1b90f 100644 --- a/vvp/stop.cc +++ b/vvp/stop.cc @@ -478,6 +478,13 @@ static void invoke_command(char*txt) delete[]argv; } +static void invoke_command_const(const char*txt) +{ + char *vtxt = strdup(txt); + invoke_command(vtxt); + free(vtxt); +} + void stop_handler(int rc) { /* The user may be running in a non-interactive environment, so @@ -489,8 +496,8 @@ void stop_handler(int rc) vpi_mcd_printf(1,"** VVP Stop(%d) **\n", rc); vpi_mcd_printf(1,"** Flushing output streams.\n"); - invoke_command("$fflush"); - invoke_command("$dumpflush"); + invoke_command_const("$fflush"); + invoke_command_const("$dumpflush"); vpi_mcd_printf(1,"** Current simulation time is %" TIME_FMT_U " ticks.\n", schedule_simtime()); From 79578f20d126d4eebb74e76b5f4897529717eb8e Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 19 May 2009 19:09:32 -0700 Subject: [PATCH 2/8] Fix memory leak when parsing command files. These are not leaks in the true sense of the word, but it is memory that is not being freed before the program finishes so valgrind will complain about this. --- driver/cflexor.lex | 19 +++++++++++++++---- driver/cfparse.y | 6 +----- driver/cfparse_misc.h | 3 ++- driver/main.c | 2 ++ 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/driver/cflexor.lex b/driver/cflexor.lex index dd35c1fa2..526f8eaed 100644 --- a/driver/cflexor.lex +++ b/driver/cflexor.lex @@ -4,7 +4,7 @@ %{ /* - * 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 @@ -21,9 +21,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: cflexor.lex,v 1.11 2007/03/22 16:08:18 steve Exp $" -#endif # include "cfparse.h" # include "cfparse_misc.h" @@ -236,3 +233,17 @@ void cfreset(FILE*fd, const char*path) current_file = strdup(path); cflloc.first_line = 1; } + +/* + * 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/driver/cfparse.y b/driver/cfparse.y index 67d85db94..9ee38e7d3 100644 --- a/driver/cfparse.y +++ b/driver/cfparse.y @@ -1,6 +1,6 @@ %{ /* - * Copyright (c) 20001 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 @@ -17,10 +17,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: cfparse.y,v 1.12 2007/04/19 02:52:53 steve Exp $" -#endif - # include "globals.h" # include "cfparse_misc.h" diff --git a/driver/cfparse_misc.h b/driver/cfparse_misc.h index b822bd7a9..708d79f93 100644 --- a/driver/cfparse_misc.h +++ b/driver/cfparse_misc.h @@ -1,7 +1,7 @@ #ifndef __cfparse_misc_H #define __cfparse_misc_H /* - * Copyright (c) 2001 Picture Elements, Inc. + * Copyright (c) 2001-2009 Picture Elements, Inc. * Stephen Williams (steve@picturel.com) * * This source code is free software; you can redistribute it @@ -38,6 +38,7 @@ int cflex(void); int cferror(const char *); int cfparse(void); void switch_to_command_file(const char *); +void destroy_lexor(); char *current_file; #endif diff --git a/driver/main.c b/driver/main.c index b97decf7a..6dc1496dd 100644 --- a/driver/main.c +++ b/driver/main.c @@ -941,7 +941,9 @@ int main(int argc, char **argv) return 1; } free(command_filename); + fclose(fp); } + destroy_lexor(); if (depfile) { fprintf(defines_file, "M:%s\n", depfile); From 9c02c7d7a448d6a52791d80f8863345ea3495149 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 19 May 2009 19:37:18 -0700 Subject: [PATCH 3/8] Cleanup if an invalid option is given. Cleanup the temporary files and memory if iverilog is given an invalid option. --- driver/main.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/driver/main.c b/driver/main.c index 6dc1496dd..66e451397 100644 --- a/driver/main.c +++ b/driver/main.c @@ -870,6 +870,20 @@ int main(int argc, char **argv) break; case '?': default: + fclose(source_file); + remove(source_path); + free(source_path); + fclose(defines_file); + remove(defines_path); + free(defines_path); + fclose(iconfig_file); + remove(iconfig_path); + free(iconfig_path); + remove(compiled_defines_path); + free(compiled_defines_path); + while( (command_filename = get_cmd_file()) ) { + free(command_filename); + } return 1; } } From 22416b4d01732f908a3b373e3ced4a30d9d45128 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 20 May 2009 09:14:39 -0700 Subject: [PATCH 4/8] Print a better error message for a '~' token in front of ('&' | '|' | '^') Some users may expect this to work so this patch catches these specific cases and tells the user to use the singe unary operators '~&', etc. instead. --- parse.y | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/parse.y b/parse.y index 764d99ffc..84a0f2005 100644 --- a/parse.y +++ b/parse.y @@ -921,6 +921,21 @@ expression FILE_NAME(tmp, @2); $$ = tmp; } + | '~' '&' expr_primary %prec UNARY_PREC + { yyerror(@1, "error: '~' '&' is not a valid expression. " + "Please use operator '~&' instead."); + $$ = 0; + } + | '~' '|' expr_primary %prec UNARY_PREC + { yyerror(@1, "error: '~' '|' is not a valid expression. " + "Please use operator '~|' instead."); + $$ = 0; + } + | '~' '^' expr_primary %prec UNARY_PREC + { yyerror(@1, "error: '~' '^' is not a valid expression. " + "Please use operator '~^' instead."); + $$ = 0; + } | K_NAND expr_primary %prec UNARY_PREC { PEUnary*tmp = new PEUnary('A', $2); FILE_NAME(tmp, @2); From 636758f66d649f32b4a77c2c6c37f64a39bd518e Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 21 May 2009 14:41:58 -0700 Subject: [PATCH 5/8] Add support for `celldefine, vpiCellInstance This patch adds real functionality for `celldefine and pushes this property to the run time which can access this with vpiCellInstance. This is technically only available for a module, but all scopes have the property and only modules should return true when the 'endmodule' is between a `celldefine and `endcelldefine directive. --- Module.cc | 3 ++- Module.h | 2 ++ design_dump.cc | 1 + elab_scope.cc | 2 ++ ivl.def | 1 + ivl_target.h | 4 ++++ ivlpp/main.c | 32 +++++++++++++++++----------- lexor.lex | 20 +++++++++++------- net_scope.cc | 1 + netlist.h | 6 +++++- parse.y | 2 +- parse_misc.h | 4 +++- pform.cc | 3 ++- pform.h | 2 +- pform_dump.cc | 6 ++++-- t-dll-api.cc | 6 ++++++ t-dll.cc | 1 + t-dll.h | 2 ++ tgt-stub/stub.c | 3 ++- tgt-vvp/vvp_scope.c | 4 ++-- vpi_user.h | 51 +++++++++++++++++++++++---------------------- vvp/compile.h | 3 ++- vvp/parse.y | 10 ++++----- vvp/vpi_priv.h | 1 + vvp/vpi_scope.cc | 8 ++++++- 25 files changed, 116 insertions(+), 62 deletions(-) diff --git a/Module.cc b/Module.cc index d880c0009..789e4137a 100644 --- a/Module.cc +++ b/Module.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-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 @@ -29,6 +29,7 @@ Module::Module(perm_string n) : PScope(n) { library_flag = false; + is_cell = false; default_nettype = NetNet::NONE; } diff --git a/Module.h b/Module.h index f5fb524fd..4f4ead3d5 100644 --- a/Module.h +++ b/Module.h @@ -74,6 +74,8 @@ class Module : public PScope, public LineInfo { other effect. */ bool library_flag; + bool is_cell; + NetNet::Type default_nettype; /* specparams are simpler then other params, in that they have diff --git a/design_dump.cc b/design_dump.cc index cf54cfb0d..30a98325b 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1081,6 +1081,7 @@ void NetScope::dump(ostream&o) const print_type(o); if (is_auto()) o << " (automatic)"; + if (is_cell()) o << " (cell)"; o << endl; for (unsigned idx = 0 ; idx < attr_cnt() ; idx += 1) diff --git a/elab_scope.cc b/elab_scope.cc index f9a20cf89..afc438573 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -479,6 +479,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, elaborate_scope_events_(des, scope, events); + scope->is_cell(is_cell); + return des->errors == 0; } diff --git a/ivl.def b/ivl.def index d57d9ad0d..c254c422a 100644 --- a/ivl.def +++ b/ivl.def @@ -161,6 +161,7 @@ ivl_scope_event ivl_scope_events ivl_scope_file ivl_scope_is_auto +ivl_scope_is_cell ivl_scope_lineno ivl_scope_logs ivl_scope_log diff --git a/ivl_target.h b/ivl_target.h index 78723d155..8a2758a46 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -1537,6 +1537,9 @@ extern unsigned ivl_parameter_lineno(ivl_parameter_t net); * ivl_scope_is_auto * Is the task or function declared to be automatic? * + * ivl_scope_is_cell + * Is the module defined to be a cell? + * * ivl_scope_var * ivl_scope_vars * REMOVED @@ -1614,6 +1617,7 @@ extern unsigned ivl_scope_events(ivl_scope_t net); extern ivl_event_t ivl_scope_event(ivl_scope_t net, unsigned idx); extern const char* ivl_scope_file(ivl_scope_t net); extern unsigned ivl_scope_is_auto(ivl_scope_t net); +extern unsigned ivl_scope_is_cell(ivl_scope_t net); extern unsigned ivl_scope_lineno(ivl_scope_t net); extern unsigned ivl_scope_logs(ivl_scope_t net); extern ivl_net_logic_t ivl_scope_log(ivl_scope_t net, unsigned idx); diff --git a/ivlpp/main.c b/ivlpp/main.c index df9d1b811..1b3906c55 100644 --- a/ivlpp/main.c +++ b/ivlpp/main.c @@ -214,26 +214,34 @@ int main(int argc, char*argv[]) FILE*precomp_out = NULL; /* Define preprocessor keywords that I plan to just pass. */ + /* From 1364-2005 Chapter 19. */ + define_macro("begin_keywords", "`begin_keywords", 1, 0); define_macro("celldefine", "`celldefine", 1, 0); - define_macro("default_decay_time", "`default_decay_time", 1, 0); define_macro("default_nettype", "`default_nettype", 1, 0); - define_macro("default_trireg_strength", "`default_trireg_strength", 1, 0); - define_macro("delay_mode_distributed", "`delay_mode_distributed", 1, 0); - define_macro("delay_mode_unit", "`delay_mode_unit", 1, 0); - define_macro("delay_mode_path", "`delay_mode_path", 1, 0); - define_macro("delay_mode_zero", "`delay_mode_zero", 1, 0); - define_macro("disable_portfaults", "`disable_portfaults", 1, 0); - define_macro("enable_portfaults", "`enable_portfaults", 1, 0); + define_macro("end_keywords", "`end_keywords", 1, 0); define_macro("endcelldefine", "`endcelldefine", 1, 0); - define_macro("endprotect", "`endprotect", 1, 0); define_macro("line", "`line", 1, 0); - define_macro("nosuppress_faults", "`nosuppress_faults", 1, 0); define_macro("nounconnected_drive", "`nounconnected_drive", 1, 0); - define_macro("protect", "`protect", 1, 0); + define_macro("pragma", "`pragma", 1, 0); define_macro("resetall", "`resetall", 1, 0); - define_macro("suppress_faults", "`suppress_faults", 1, 0); define_macro("timescale", "`timescale", 1, 0); define_macro("unconnected_drive", "`unconnected_drive", 1, 0); + + /* From 1364-2005 Annex D. */ + define_macro("default_decay_time", "`default_decay_time", 1, 0); + define_macro("default_trireg_strength", "`default_trireg_strength", 1, 0); + define_macro("delay_mode_distributed", "`delay_mode_distributed", 1, 0); + define_macro("delay_mode_path", "`delay_mode_path", 1, 0); + define_macro("delay_mode_unit", "`delay_mode_unit", 1, 0); + define_macro("delay_mode_zero", "`delay_mode_zero", 1, 0); + + /* From other places. */ + define_macro("disable_portfaults", "`disable_portfaults", 1, 0); + define_macro("enable_portfaults", "`enable_portfaults", 1, 0); + define_macro("endprotect", "`endprotect", 1, 0); + define_macro("nosuppress_faults", "`nosuppress_faults", 1, 0); + define_macro("protect", "`protect", 1, 0); + define_macro("suppress_faults", "`suppress_faults", 1, 0); define_macro("uselib", "`uselib", 1, 0); include_cnt = 2; diff --git a/lexor.lex b/lexor.lex index 447eaf813..6668cf514 100644 --- a/lexor.lex +++ b/lexor.lex @@ -88,6 +88,7 @@ static list keyword_mask_stack; static int comment_enter; static bool in_module = false; +bool in_celldefine = false; %} %x CCOMMENT @@ -362,28 +363,33 @@ S [afpnumkKMGT] yylloc.first_line += 1; BEGIN(0); } +^{W}?`celldefine{W}?.* { in_celldefine = true; } +^{W}?`endcelldefine{W}?.* { in_celldefine = false; } /* These are directives that I do not yet support. I think that IVL should handle these, not an external preprocessor. */ + /* From 1364-2005 Chapter 19. */ +^{W}?`line{W}?.* { } +^{W}?`nounconnected_drive{W}?.* { } +^{W}?`pragme{W}?.* { } +^{W}?`resetall{W}?.* { } +^{W}?`unconnected_drive{W}?.* { } -^{W}?`celldefine{W}?.* { } + /* From 1364-2005 Annex D. */ ^{W}?`default_decay_time{W}?.* { } ^{W}?`default_trireg_strength{W}?.* { } ^{W}?`delay_mode_distributed{W}?.* { } -^{W}?`delay_mode_unit{W}?.* { } ^{W}?`delay_mode_path{W}?.* { } +^{W}?`delay_mode_unit{W}?.* { } ^{W}?`delay_mode_zero{W}?.* { } + + /* From other places. */ ^{W}?`disable_portfaults{W}?.* { } ^{W}?`enable_portfaults{W}?.* { } -^{W}?`endcelldefine{W}?.* { } `endprotect { } -^{W}?`line{W}?.* { } ^{W}?`nosuppress_faults{W}?.* { } -^{W}?`nounconnected_drive{W}?.* { } `protect { } -^{W}?`resetall{W}?.* { } ^{W}?`suppress_faults{W}?.* { } -^{W}?`unconnected_drive{W}?.* { } ^{W}?`uselib{W}?.* { } ^{W}?`begin_keywords{W}? { BEGIN(PPBEGIN_KEYWORDS); } diff --git a/net_scope.cc b/net_scope.cc index 851ab0fb1..3a2e6f91b 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -41,6 +41,7 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t) events_ = 0; lcounter_ = 0; is_auto_ = false; + is_cell_ = false; if (up) { default_nettype_ = up->default_nettype(); diff --git a/netlist.h b/netlist.h index ca9c78fbc..387adffc8 100644 --- a/netlist.h +++ b/netlist.h @@ -761,6 +761,10 @@ class NetScope : public Attrib { void is_auto(bool is_auto__) { is_auto_ = is_auto__; }; bool is_auto() const { return is_auto_; }; + /* Is the module a cell (is in a `celldefine) */ + void is_cell(bool is_cell__) { is_cell_ = is_cell__; }; + bool is_cell() const { return is_cell_; }; + const NetTaskDef* task_def() const; const NetFuncDef* func_def() const; @@ -908,7 +912,7 @@ class NetScope : public Attrib { NetScope*sub_; unsigned lcounter_; - bool is_auto_; + bool is_auto_, is_cell_; }; /* diff --git a/parse.y b/parse.y index 84a0f2005..e24d67bbc 100644 --- a/parse.y +++ b/parse.y @@ -1923,7 +1923,7 @@ module : attribute_list_opt module_start IDENTIFIER { pform_module_set_ports($6); } module_item_list_opt K_endmodule - { pform_endmodule($3); + { pform_endmodule($3, in_celldefine); delete[]$3; } diff --git a/parse_misc.h b/parse_misc.h index d82b3c8f9..6aa623a13 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -1,7 +1,7 @@ #ifndef __parse_misc_H #define __parse_misc_H /* - * Copyright (c) 1998-2000 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-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 @@ -65,4 +65,6 @@ extern ostream& operator << (ostream&, const YYLTYPE&loc); extern unsigned error_count, warn_count; extern unsigned long based_size; +extern bool in_celldefine; + #endif diff --git a/pform.cc b/pform.cc index b3bac9103..b87ac6e2b 100644 --- a/pform.cc +++ b/pform.cc @@ -449,11 +449,12 @@ void pform_module_set_ports(vector*ports) } } -void pform_endmodule(const char*name) +void pform_endmodule(const char*name, bool in_celldefine) { assert(pform_cur_module); perm_string mod_name = pform_cur_module->mod_name(); assert(strcmp(name, mod_name) == 0); + pform_cur_module->is_cell = in_celldefine; map::const_iterator test = pform_modules.find(mod_name); diff --git a/pform.h b/pform.h index ef18234e9..92166d41b 100644 --- a/pform.h +++ b/pform.h @@ -159,7 +159,7 @@ extern void pform_module_define_port(const struct vlltype&li, extern Module::port_t* pform_module_port_reference(perm_string name, const char*file, unsigned lineno); -extern void pform_endmodule(const char*); +extern void pform_endmodule(const char*, bool in_celldefine); extern void pform_make_udp(perm_string name, list*parms, svector*decl, list*table, diff --git a/pform_dump.cc b/pform_dump.cc index e65a7c7bc..a522eb8ac 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-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 @@ -1147,7 +1147,9 @@ void Module::dump(ostream&out) const out << " *) "; } - out << "module " << mod_name() << ";" << endl; + out << "module " << mod_name() << ";"; + if (is_cell) out << " // Is in `celldefine."; + out << endl; for (unsigned idx = 0 ; idx < ports.size() ; idx += 1) { port_t*cur = ports[idx]; diff --git a/t-dll-api.cc b/t-dll-api.cc index 46e261b93..e5a513e8d 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -1655,6 +1655,12 @@ extern "C" unsigned ivl_scope_is_auto(ivl_scope_t net) return net->is_auto; } +extern "C" unsigned ivl_scope_is_cell(ivl_scope_t net) +{ + assert(net); + return net->is_cell; +} + extern "C" unsigned ivl_scope_lineno(ivl_scope_t net) { assert(net); diff --git a/t-dll.cc b/t-dll.cc index a66feefb3..f1b18f857 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -2389,6 +2389,7 @@ void dll_target::scope(const NetScope*net) scop->nattr = net->attr_cnt(); scop->attr = fill_in_attributes(net); scop->is_auto = net->is_auto(); + scop->is_cell = net->is_cell(); switch (net->type()) { case NetScope::MODULE: diff --git a/t-dll.h b/t-dll.h index e6c7bd6bc..5006a6ab4 100644 --- a/t-dll.h +++ b/t-dll.h @@ -606,6 +606,8 @@ struct ivl_scope_s { ivl_statement_t def; unsigned is_auto; + unsigned is_cell; + unsigned ports; ivl_signal_t*port; diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 98723b0a8..2a378b737 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -1533,7 +1533,8 @@ static int show_scope(ivl_scope_t net, void*x) is_auto = ivl_scope_is_auto(net) ? "automatic " : ""; switch (ivl_scope_type(net)) { case IVL_SCT_MODULE: - fprintf(out, " module %s", ivl_scope_tname(net)); + fprintf(out, " module %s%s", ivl_scope_tname(net), + ivl_scope_is_cell(net) ? " (cell)" : ""); break; case IVL_SCT_FUNCTION: fprintf(out, " function %s%s", is_auto, ivl_scope_tname(net)); diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index eea3ab47b..3d6b119ca 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -1825,9 +1825,9 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) ivl_scope_lineno(net)); if (parent) { - fprintf(vvp_out, ", %d %d, S_%p;\n", + fprintf(vvp_out, ", %d %d %u, S_%p;\n", ivl_file_table_index(ivl_scope_def_file(net)), - ivl_scope_def_lineno(net), parent); + ivl_scope_def_lineno(net), ivl_scope_is_cell(net), parent); } else { fprintf(vvp_out, ";\n"); diff --git a/vpi_user.h b/vpi_user.h index c335c0a72..ba019190b 100644 --- a/vpi_user.h +++ b/vpi_user.h @@ -304,33 +304,34 @@ typedef struct t_vpi_delay { #define vpiCallback 1000 /* PROPERTIES */ -#define vpiUndefined (-1) -#define vpiType 1 -#define vpiName 2 -#define vpiFullName 3 -#define vpiSize 4 -#define vpiFile 5 -#define vpiLineNo 6 -#define vpiTopModule 7 -#define vpiDefName 9 +#define vpiUndefined (-1) +#define vpiType 1 +#define vpiName 2 +#define vpiFullName 3 +#define vpiSize 4 +#define vpiFile 5 +#define vpiLineNo 6 +#define vpiTopModule 7 +#define vpiCellInstance 8 +#define vpiDefName 9 #define vpiTimeUnit 11 #define vpiTimePrecision 12 -#define vpiDefFile 15 -#define vpiDefLineNo 16 -#define vpiNetType 22 -# define vpiWire 1 -#define vpiArray 28 -#define vpiEdge 36 -# define vpiNoEdge 0x00 /* No edge */ -# define vpiEdge01 0x01 /* 0 --> 1 */ -# define vpiEdge10 0x02 /* 1 --> 0 */ -# define vpiEdge0x 0x04 /* 0 --> x */ -# define vpiEdgex1 0x08 /* x --> 1 */ -# define vpiEdge1x 0x10 /* 1 --> x */ -# define vpiEdgex0 0x20 /* x --> 0 */ -# define vpiPosedge (vpiEdgex1|vpiEdge01|vpiEdge0x) -# define vpiNegedge (vpiEdgex0|vpiEdge10|vpiEdge1x) -# define vpiAnyEdge (vpiPosedge|vpiNegedge) +#define vpiDefFile 15 +#define vpiDefLineNo 16 +#define vpiNetType 22 +# define vpiWire 1 +#define vpiArray 28 +#define vpiEdge 36 +# define vpiNoEdge 0x00 /* No edge */ +# define vpiEdge01 0x01 /* 0 --> 1 */ +# define vpiEdge10 0x02 /* 1 --> 0 */ +# define vpiEdge0x 0x04 /* 0 --> x */ +# define vpiEdgex1 0x08 /* x --> 1 */ +# define vpiEdge1x 0x10 /* 1 --> x */ +# define vpiEdgex0 0x20 /* x --> 0 */ +# define vpiPosedge (vpiEdgex1|vpiEdge01|vpiEdge0x) +# define vpiNegedge (vpiEdgex0|vpiEdge10|vpiEdge1x) +# define vpiAnyEdge (vpiPosedge|vpiNegedge) #define vpiConstType 40 # define vpiDecConst 1 # define vpiRealConst 2 diff --git a/vvp/compile.h b/vvp/compile.h index c28036755..f63732246 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -414,7 +414,8 @@ extern void compile_codelabel(char*label); */ extern void compile_scope_decl(char*typ, char*lab, char*nam, char*tnam, char*par, long file_idx, long lineno, - long def_file_idx, long def_lineno); + long def_file_idx, long def_lineno, + long is_cell); extern void compile_scope_recall(char*sym); /* diff --git a/vvp/parse.y b/vvp/parse.y index ae2454891..03cf2dccf 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -574,19 +574,19 @@ statement parent scope, then this is a root scope. */ | T_LABEL K_SCOPE T_SYMBOL ',' T_STRING T_STRING T_NUMBER T_NUMBER ';' - { compile_scope_decl($1, $3, $5, $6, 0, $7, $8, $7, $8); } + { compile_scope_decl($1, $3, $5, $6, 0, $7, $8, $7, $8, 0); } | T_LABEL K_SCOPE T_SYMBOL ',' T_STRING T_STRING T_NUMBER T_NUMBER ',' - T_NUMBER T_NUMBER ',' T_SYMBOL ';' - { compile_scope_decl($1, $3, $5, $6, $13, $7, $8, $10, $11); } + T_NUMBER T_NUMBER T_NUMBER ',' T_SYMBOL ';' + { compile_scope_decl($1, $3, $5, $6, $14, $7, $8, $10, $11, $12); } /* XXXX Legacy declaration has no type name. */ | T_LABEL K_SCOPE T_SYMBOL ',' T_STRING ';' - { compile_scope_decl($1, $3, $5, 0, 0, 0, 0, 0, 0); } + { compile_scope_decl($1, $3, $5, 0, 0, 0, 0, 0, 0, 0); } | T_LABEL K_SCOPE T_SYMBOL ',' T_STRING ',' T_SYMBOL ';' - { compile_scope_decl($1, $3, $5, 0, $7, 0, 0, 0, 0); } + { compile_scope_decl($1, $3, $5, 0, $7, 0, 0, 0, 0, 0); } /* Scope recall has no label of its own, but refers by label to a declared scope. */ diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index a3a40653a..a1d0ba6e8 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -186,6 +186,7 @@ struct __vpiScope { unsigned def_file_idx; unsigned def_lineno; bool is_automatic; + bool is_cell; /* The scope has a system time of its own. */ struct __vpiSystemTime scoped_time; struct __vpiSystemTime scoped_stime; diff --git a/vvp/vpi_scope.cc b/vvp/vpi_scope.cc index 975928bfe..ac3aac5a5 100644 --- a/vvp/vpi_scope.cc +++ b/vvp/vpi_scope.cc @@ -128,6 +128,9 @@ static int scope_get(int code, vpiHandle obj) assert(handle_is_scope(obj)); switch (code) { + case vpiCellInstance: + return (int) ref->is_cell; + case vpiDefLineNo: return ref->def_lineno; @@ -395,7 +398,7 @@ static void attach_to_scope_(struct __vpiScope*scope, vpiHandle obj) void compile_scope_decl(char*label, char*type, char*name, char*tname, char*parent, long file_idx, long lineno, - long def_file_idx, long def_lineno) + long def_file_idx, long def_lineno, long is_cell) { struct __vpiScope*scope = new struct __vpiScope; count_vpi_scopes += 1; @@ -409,6 +412,9 @@ compile_scope_decl(char*label, char*type, char*name, char*tname, base_type = &type[0]; } + if (is_cell) scope->is_cell = true; + else scope->is_cell = false; + if (strcmp(base_type,"module") == 0) { scope->base.vpi_type = &vpip_scope_module_rt; } else if (strcmp(base_type,"function") == 0) { From 4991711672205a21acb0cd718b7e50f8822715b7 Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 22 May 2009 11:03:36 -0700 Subject: [PATCH 6/8] Add support for `resetall and other directive changes. This patch adds support for the `resetall directive. It also changes `celldefine, `endcelldefine and `resetall to no longer grab text following them. These directives do not take an argument so they should not be grabbing any text and silently discarding it. The `timescale processing was reworked to handle being reset and hooks were added to easily change the default time units and precision when we add that feature request. --- Module.cc | 1 + Module.h | 1 + lexor.lex | 42 +++++++++++++++++++++++++++++++++++------- main.cc | 4 ++++ parse_api.h | 7 ++++++- pform.cc | 30 ++++++++++++++++++++++++------ 6 files changed, 71 insertions(+), 14 deletions(-) diff --git a/Module.cc b/Module.cc index 789e4137a..e608a6401 100644 --- a/Module.cc +++ b/Module.cc @@ -31,6 +31,7 @@ Module::Module(perm_string n) library_flag = false; is_cell = false; default_nettype = NetNet::NONE; + timescale_warn_done = false; } Module::~Module() diff --git a/Module.h b/Module.h index 4f4ead3d5..a2960bc74 100644 --- a/Module.h +++ b/Module.h @@ -108,6 +108,7 @@ class Module : public PScope, public LineInfo { set by the `timescale directive. */ int time_unit, time_precision; bool time_from_timescale; + bool timescale_warn_done; /* Task definitions within this module */ map tasks; diff --git a/lexor.lex b/lexor.lex index 6668cf514..1f5d10737 100644 --- a/lexor.lex +++ b/lexor.lex @@ -67,9 +67,6 @@ static const char* set_file_name(char*text) return path; } - -extern void pform_set_timescale(int, int, const char*file, unsigned line); - void reset_lexor(); static void line_directive(); static void line_directive2(); @@ -88,6 +85,7 @@ static list keyword_mask_stack; static int comment_enter; static bool in_module = false; +static bool in_UDP = false; bool in_celldefine = false; %} @@ -238,6 +236,14 @@ S [afpnumkKMGT] in_module = false; break; + case K_primitive: + in_UDP = true; + break; + + case K_endprimitive: + in_UDP = false; + break; + default: yylval.text = 0; break; @@ -349,7 +355,7 @@ S [afpnumkKMGT] return REALTIME; } - /* Notice and handle the timescale directive. */ + /* Notice and handle the `timescale directive. */ ^{W}?`timescale { BEGIN(PPTIMESCALE); } .* { process_timescale(yytext); } @@ -363,8 +369,31 @@ S [afpnumkKMGT] yylloc.first_line += 1; BEGIN(0); } -^{W}?`celldefine{W}?.* { in_celldefine = true; } -^{W}?`endcelldefine{W}?.* { in_celldefine = false; } + /* Notice and handle the `celldefine and `endcelldefine directives. */ + +^{W}?`celldefine{W}? { in_celldefine = true; } +^{W}?`endcelldefine{W}? { in_celldefine = false; } + + /* Notice and handle the resetall directive. */ + +^{W}?`resetall{W}? { + if (in_module) { + cerr << yylloc.text << ":" << yylloc.first_line << ": error: " + "`resetall directive can not be inside a module " + "definition." << endl; + error_count += 1; + } else if (in_UDP) { + cerr << yylloc.text << ":" << yylloc.first_line << ": error: " + "`resetall directive can not be inside a UDP " + "definition." << endl; + error_count += 1; + } else { + pform_set_default_nettype(NetNet::WIRE, yylloc.text, + yylloc.first_line); + in_celldefine = false; + pform_set_timescale(def_ts_units, def_ts_prec, 0, 0); + /* Add `nounconnected_drive when implemented. */ + } } /* These are directives that I do not yet support. I think that IVL should handle these, not an external preprocessor. */ @@ -372,7 +401,6 @@ S [afpnumkKMGT] ^{W}?`line{W}?.* { } ^{W}?`nounconnected_drive{W}?.* { } ^{W}?`pragme{W}?.* { } -^{W}?`resetall{W}?.* { } ^{W}?`unconnected_drive{W}?.* { } /* From 1364-2005 Annex D. */ diff --git a/main.cc b/main.cc index c692a154a..b3f1201c0 100644 --- a/main.cc +++ b/main.cc @@ -142,6 +142,9 @@ bool verbose_flag = false; unsigned integer_width = 32; +int def_ts_units = 0; +int def_ts_prec = 0; + /* * Keep a heap of identifier strings that I encounter. This is a more * efficient way to allocate those strings. @@ -726,6 +729,7 @@ int main(int argc, char*argv[]) if (flag_tmp) recursive_mod_limit = strtoul(flag_tmp,NULL,0); /* Parse the input. Make the pform. */ + pform_set_timescale(def_ts_units, def_ts_prec, 0, 0); int rc = pform_parse(argv[optind]); if (pf_path) { diff --git a/parse_api.h b/parse_api.h index 76ea71531..ba23c564e 100644 --- a/parse_api.h +++ b/parse_api.h @@ -1,7 +1,7 @@ #ifndef __parse_api_H #define __parse_api_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 @@ -46,4 +46,9 @@ extern int pform_parse(const char*path, FILE*file =0); extern string vl_file; +extern void pform_set_timescale(int units, int prec, const char*file, + unsigned lineno); +extern int def_ts_units; +extern int def_ts_prec; + #endif diff --git a/pform.cc b/pform.cc index b87ac6e2b..52dfed03c 100644 --- a/pform.cc +++ b/pform.cc @@ -70,11 +70,11 @@ static NetNet::Type pform_default_nettype = NetNet::WIRE; * These variables track the current time scale, as well as where the * timescale was set. This supports warnings about tangled timescales. */ -static int pform_time_unit = 0; -static int pform_time_prec = 0; +static int pform_time_unit; +static int pform_time_prec; static char*pform_timescale_file = 0; -static unsigned pform_timescale_line = 0; +static unsigned pform_timescale_line; static inline void FILE_NAME(LineInfo*obj, const char*file, unsigned lineno) { @@ -298,10 +298,25 @@ void pform_set_timescale(int unit, int prec, first_flag = false; } - pform_timescale_file = strdup(file); + if (file) pform_timescale_file = strdup(file); + else pform_timescale_file = 0; pform_timescale_line = lineno; - if (warn_timescale && first_flag && (pform_modules.size() > 0)) { + if (!warn_timescale || !first_flag || !file) return; + + /* Look to see if we have any modules without a timescale. */ + bool have_no_ts = false; + map::iterator mod; + for (mod = pform_modules.begin(); mod != pform_modules.end(); mod++) { + const Module*mp = (*mod).second; + if (mp->time_from_timescale || + mp->timescale_warn_done) continue; + have_no_ts = true; + break; + } + + /* If we do then print a message for the new ones. */ + if (have_no_ts) { cerr << file << ":" << lineno << ": warning: " << "Some modules have no timescale. This may cause" << endl; @@ -312,7 +327,10 @@ void pform_set_timescale(int unit, int prec, map::iterator mod; for (mod = pform_modules.begin() ; mod != pform_modules.end() ; mod++) { - const Module*mp = (*mod).second; + Module*mp = (*mod).second; + if (mp->time_from_timescale || + mp->timescale_warn_done) continue; + mp->timescale_warn_done = true; cerr << file << ":" << lineno << ": : " << " -- module " << (*mod).first From 1bce6ec7264b5bf7018e6cca0aaf566da4f3e881 Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 22 May 2009 18:53:26 -0700 Subject: [PATCH 7/8] Add better error checking to the two line directives. Icarus supports both a #line and `line directive. This patch reworks the parsing of these to provide better error detection and full checking. --- lexor.lex | 161 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 132 insertions(+), 29 deletions(-) diff --git a/lexor.lex b/lexor.lex index 1f5d10737..b70936c73 100644 --- a/lexor.lex +++ b/lexor.lex @@ -106,8 +106,9 @@ S [afpnumkKMGT] %% -^"#line"[ ]+\"[^\"]*\"[ ]+[0-9]+.* { line_directive(); } -^"`line"[ ]+[0-9]+[ ]+\"[^\"]*\".* { line_directive2(); } + /* Recognize the various line directives. */ +^"#line"[ \t]+.+ { line_directive(); } +^[ \t]?"`line"[ \t]+.+ { line_directive2(); } [ \t\b\f\r] { ; } \n { yylloc.first_line += 1; } @@ -398,7 +399,6 @@ S [afpnumkKMGT] /* These are directives that I do not yet support. I think that IVL should handle these, not an external preprocessor. */ /* From 1364-2005 Chapter 19. */ -^{W}?`line{W}?.* { } ^{W}?`nounconnected_drive{W}?.* { } ^{W}?`pragme{W}?.* { } ^{W}?`unconnected_drive{W}?.* { } @@ -1087,47 +1087,150 @@ int yywrap() */ static void line_directive() { - char*qt1 = strchr(yytext, '"'); - assert(qt1); - qt1 += 1; + char *cpr; + /* Skip any leading space. */ + char *cp = index(yytext, '#'); + /* Skip the #line directive. */ + assert(strncmp(cp, "#line", 5) == 0); + cp += 5; + /* Skip the space after the #line directive. */ + cp += strspn(cp, " \t"); - char*qt2 = strchr(qt1, '"'); - assert(qt2); + /* Find the starting " and skip it. */ + char*fn_start = strchr(cp, '"'); + if (cp != fn_start) { + VLerror(yylloc, "Invalid #line directive (file name start)."); + return; + } + fn_start += 1; - char*buf = new char[qt2-qt1+1]; - strncpy(buf, qt1, qt2-qt1); - buf[qt2-qt1] = 0; + /* Find the last ". */ + char*fn_end = strrchr(fn_start, '"'); + if (!fn_end) { + VLerror(yylloc, "Invalid #line directive (file name end)."); + return; + } + /* Copy the file name and assign it to yylloc. */ + char*buf = new char[fn_end-fn_start+1]; + strncpy(buf, fn_start, fn_end-fn_start); + buf[fn_end-fn_start] = 0; + + /* Skip the space after the file name. */ + cp = fn_end; + cp += 1; + cpr = cp; + cpr += strspn(cp, " \t"); + if (cp == cpr) { + VLerror(yylloc, "Invalid #line directive (missing space after " + "file name)."); + return; + } + cp = cpr; + + /* Get the line number and verify that it is correct. */ + unsigned long lineno = strtoul(cp, &cpr, 10); + if (cp == cpr) { + VLerror(yylloc, "Invalid line number for #line directive."); + return; + } + cp = cpr; + + /* Verify that only space is left. */ + cpr += strspn(cp, " \t"); + if ((size_t)(cpr-yytext) != strlen(yytext)) { + VLerror(yylloc, "Invalid #line directive (extra garbage after " + "line number)."); + return; + } + + /* Now we can assign the new values to yyloc. */ yylloc.text = set_file_name(buf); - - qt2 += 1; - yylloc.first_line = strtoul(qt2,0,0); + yylloc.first_line = lineno; } +/* + * The line directive matches lines of the form `line N "foo" M and + * calls this function. Here I parse out the file name and line + * number, and change the yylloc to suite. M is ignored. + */ static void line_directive2() { - assert(strncmp(yytext,"`line",5) == 0); - char*cp = yytext + strlen("`line"); - cp += strspn(cp, " "); - yylloc.first_line = strtoul(cp,&cp,10); + char *cpr; + /* Skip any leading space. */ + char *cp = index(yytext, '`'); + /* Skip the `line directive. */ + assert(strncmp(cp, "`line", 5) == 0); + cp += 5; - yylloc.first_line -= 1; + /* strtoul skips leading space. */ + unsigned long lineno = strtoul(cp, &cpr, 10); + if (cp == cpr) { + VLerror(yylloc, "Invalid line number for `line directive."); + return; + } + lineno -= 1; + cp = cpr; - cp += strspn(cp, " "); - if (*cp == 0) return; + /* Skip the space between the line number and the file name. */ + cpr += strspn(cp, " \t"); + if (cp == cpr) { + VLerror(yylloc, "Invalid `line directive (missing space after " + "line number)."); + return; + } + cp = cpr; - char*qt1 = strchr(yytext, '"'); - assert(qt1); - qt1 += 1; + /* Find the starting " and skip it. */ + char*fn_start = strchr(cp, '"'); + if (cp != fn_start) { + VLerror(yylloc, "Invalid `line directive (file name start)."); + return; + } + fn_start += 1; - char*qt2 = strchr(qt1, '"'); - assert(qt2); + /* Find the last ". */ + char*fn_end = strrchr(fn_start, '"'); + if (!fn_end) { + VLerror(yylloc, "Invalid `line directive (file name end)."); + return; + } - char*buf = new char[qt2-qt1+1]; - strncpy(buf, qt1, qt2-qt1); - buf[qt2-qt1] = 0; + /* Skip the space after the file name. */ + cp = fn_end; + cp += 1; + cpr = cp; + cpr += strspn(cp, " \t"); + if (cp == cpr) { + VLerror(yylloc, "Invalid `line directive (missing space after " + "file name)."); + return; + } + cp = cpr; + + /* Check that the level is correct, we do not need the level. */ + strtoul(cp, &cpr, 10); + if (cp == cpr) { + VLerror(yylloc, "Invalid level for `line directive."); + return; + } + cp = cpr; + + /* Verify that only space is left. */ + cpr += strspn(cp, " \t"); + if ((size_t)(cpr-yytext) != strlen(yytext)) { + VLerror(yylloc, "Invalid `line directive (extra garbage after " + "level)."); + return; + } + + /* Copy the file name and assign it and the line number to yylloc. */ + char*buf = new char[fn_end-fn_start+1]; + strncpy(buf, fn_start, fn_end-fn_start); + buf[fn_end-fn_start] = 0; yylloc.text = set_file_name(buf); + yylloc.first_line = lineno; } extern FILE*vl_input; From 4affc6e412ad6b8583a7aa4e9c490299e96269a0 Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 22 May 2009 19:08:22 -0700 Subject: [PATCH 8/8] Make ivl warn that it does not support `ifndef or `elsif We added support for these two directives some time ago, but ivl was never updated to warn that it did not support them and you needed to use ivlpp. --- lexor.lex | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lexor.lex b/lexor.lex index b70936c73..ad0df6906 100644 --- a/lexor.lex +++ b/lexor.lex @@ -517,6 +517,12 @@ S [afpnumkKMGT] << endl; } +^{W}?`elsif{W}?.* { + cerr << yylloc.text << ":" << yylloc.first_line << + ": warning: `elsif not supported. Use an external preprocessor." + << endl; + } + ^{W}?`endif{W}?.* { cerr << yylloc.text << ":" << yylloc.first_line << ": warning: `endif not supported. Use an external preprocessor." @@ -529,6 +535,12 @@ S [afpnumkKMGT] << endl; } +^{W}?`ifndef{W}?.* { + cerr << yylloc.text << ":" << yylloc.first_line << + ": warning: `ifndef not supported. Use an external preprocessor." + << endl; + } + ^`include{W}?.* { cerr << yylloc.text << ":" << yylloc.first_line << ": warning: `include not supported. Use an external preprocessor."