diff --git a/Module.cc b/Module.cc index d880c0009..e608a6401 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,7 +29,9 @@ Module::Module(perm_string n) : PScope(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 f5fb524fd..a2960bc74 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 @@ -106,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/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/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..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; } } @@ -941,7 +955,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); 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..ad0df6906 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,8 @@ static list keyword_mask_stack; static int comment_enter; static bool in_module = false; +static bool in_UDP = false; +bool in_celldefine = false; %} %x CCOMMENT @@ -107,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; } @@ -237,6 +237,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; @@ -348,7 +356,7 @@ S [afpnumkKMGT] return REALTIME; } - /* Notice and handle the timescale directive. */ + /* Notice and handle the `timescale directive. */ ^{W}?`timescale { BEGIN(PPTIMESCALE); } .* { process_timescale(yytext); } @@ -362,28 +370,54 @@ S [afpnumkKMGT] yylloc.first_line += 1; BEGIN(0); } + /* 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. */ + /* From 1364-2005 Chapter 19. */ +^{W}?`nounconnected_drive{W}?.* { } +^{W}?`pragme{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); } @@ -483,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." @@ -495,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." @@ -1053,47 +1099,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; 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/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 764d99ffc..e24d67bbc 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); @@ -1908,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_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/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..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 @@ -449,11 +467,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/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()); 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) {