diff --git a/Module.cc b/Module.cc index 7c2d14dfb0..c5980637e7 100644 --- a/Module.cc +++ b/Module.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2017 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 @@ -35,7 +35,6 @@ Module::Module(LexicalScope*parent, perm_string n) is_interface = false; program_block = false; uc_drive = UCD_NONE; - timescale_warn_done = false; } Module::~Module() diff --git a/Module.h b/Module.h index 66c60af4f7..411c99f9f3 100644 --- a/Module.h +++ b/Module.h @@ -1,7 +1,7 @@ #ifndef IVL_Module_H #define IVL_Module_H /* - * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2017 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 @@ -121,8 +121,6 @@ class Module : public PScopeExtra, public LineInfo { map attributes; - bool timescale_warn_done; - /* The module has a list of generate schemes that appear in the module definition. These are used at elaboration time. */ list generate_schemes; diff --git a/PScope.cc b/PScope.cc index 0b6a132d3e..c0738cc298 100644 --- a/PScope.cc +++ b/PScope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008,2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2017 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 @@ -38,7 +38,8 @@ PScope::PScope(perm_string n, LexicalScope*parent) { time_unit = 0; time_precision = 0; - time_from_timescale = false; + time_unit_is_default = true; + time_prec_is_default = true; } PScope::~PScope() @@ -51,6 +52,8 @@ PScope::~PScope() PScopeExtra::PScopeExtra(perm_string n, LexicalScope*parent) : PScope(n, parent) { + time_unit_is_local = false; + time_prec_is_local = false; } PScopeExtra::~PScopeExtra() diff --git a/PScope.h b/PScope.h index 7e4fd6fa38..24674d6dfb 100644 --- a/PScope.h +++ b/PScope.h @@ -1,7 +1,7 @@ #ifndef IVL_PScope_H #define IVL_PScope_H /* - * Copyright (c) 2008-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2017 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 @@ -164,11 +164,18 @@ class PScope : public LexicalScope { perm_string pscope_name() const { return name_; } - /* These are the timescale for this scope. The default is + /* These are the timescale for this scope. The value is set by the `timescale directive or, in SystemVerilog, by timeunit and timeprecision statements. */ int time_unit, time_precision; - bool time_from_timescale; + + /* Flags used to support warnings about timescales. */ + bool time_unit_is_default; + bool time_prec_is_default; + + bool has_explicit_timescale() const { + return !(time_unit_is_default || time_prec_is_default); + } protected: bool elaborate_sig_wires_(Design*des, NetScope*scope) const; @@ -199,6 +206,10 @@ class PScopeExtra : public PScope { elaboration to choose an elaboration order. */ std::vector classes_lexical; + /* Flags used to support warnings about timescales. */ + bool time_unit_is_local; + bool time_prec_is_local; + protected: void dump_classes_(ostream&out, unsigned indent) const; void dump_tasks_(ostream&out, unsigned indent) const; diff --git a/elab_scope.cc b/elab_scope.cc index 7917ea2df7..cfbc2a50d8 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -59,7 +59,7 @@ void set_scope_timescale(Design*des, NetScope*scope, PScope*pscope) { scope->time_unit(pscope->time_unit); scope->time_precision(pscope->time_precision); - scope->time_from_timescale(pscope->time_from_timescale); + scope->time_from_timescale(pscope->has_explicit_timescale()); des->set_precision(pscope->time_precision); } diff --git a/elaborate.cc b/elaborate.cc index be0a77d0a3..7db3625046 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -6146,6 +6146,131 @@ bool Design::check_proc_delay() const return result_flag; } +/* + * Check whether all design elements have an explicit timescale or all + * design elements use the default timescale. If a mixture of explicit + * and default timescales is found, a warning message is output. Note + * that we only need to check the top level design elements - nested + * design elements will always inherit the timescale from their parent + * if they don't have any local timescale declarations. + * + * NOTE: Strictly speaking, this should be an error for SystemVerilog + * (1800-2012 section 3.14.2). + */ +static void check_timescales(bool&some_explicit, bool&some_implicit, + const PScope*scope) +{ + if (scope->time_unit_is_default) + some_implicit = true; + else + some_explicit = true; + if (scope->time_prec_is_default) + some_implicit = true; + else + some_explicit = true; +} + +static void check_timescales() +{ + bool some_explicit = false; + bool some_implicit = false; + map::iterator mod; + for (mod = pform_modules.begin(); mod != pform_modules.end(); ++mod) { + const Module*mp = (*mod).second; + check_timescales(some_explicit, some_implicit, mp); + if (some_explicit && some_implicit) + break; + } + map::iterator pkg; + if (gn_system_verilog() && !(some_explicit && some_implicit)) { + for (pkg = pform_packages.begin(); pkg != pform_packages.end(); ++pkg) { + const PPackage*pp = (*pkg).second; + check_timescales(some_explicit, some_implicit, pp); + if (some_explicit && some_implicit) + break; + } + } + if (gn_system_verilog() && !(some_explicit && some_implicit)) { + for (unsigned idx = 0; idx < pform_units.size(); idx += 1) { + const PPackage*pp = pform_units[idx]; + // We don't need a timescale if the compilation unit + // contains no items outside a design element. + if (pp->parameters.empty() && + pp->localparams.empty() && + pp->wires.empty() && + pp->tasks.empty() && + pp->funcs.empty() && + pp->classes.empty()) + continue; + + check_timescales(some_explicit, some_implicit, pp); + if (some_explicit && some_implicit) + break; + } + } + + if (!(some_explicit && some_implicit)) + return; + + if (gn_system_verilog()) { + cerr << "warning: " + << "Some design elements have no explicit time unit and/or" + << endl; + cerr << " : " + << "time precision. This may cause confusing timing results." + << endl; + cerr << " : " + << "Affected design elements are:" + << endl; + } else { + cerr << "warning: " + << "Some modules have no timescale. This may cause" + << endl; + cerr << " : " + << "confusing timing results. Affected modules are:" + << endl; + } + + for (mod = pform_modules.begin(); mod != pform_modules.end(); ++mod) { + Module*mp = (*mod).second; + if (mp->has_explicit_timescale()) + continue; + cerr << " : -- module " << (*mod).first + << " declared here: " << mp->get_fileline() << endl; + } + + if (!gn_system_verilog()) + return; + + for (pkg = pform_packages.begin(); pkg != pform_packages.end(); ++pkg) { + PPackage*pp = (*pkg).second; + if (pp->has_explicit_timescale()) + continue; + cerr << " : -- package " << (*pkg).first + << " declared here: " << pp->get_fileline() << endl; + } + + for (unsigned idx = 0; idx < pform_units.size(); idx += 1) { + PPackage*pp = pform_units[idx]; + if (pp->has_explicit_timescale()) + continue; + + if (pp->parameters.empty() && + pp->localparams.empty() && + pp->wires.empty() && + pp->tasks.empty() && + pp->funcs.empty() && + pp->classes.empty()) + continue; + + cerr << " : -- compilation unit"; + if (pform_units.size() > 1) { + cerr << " from: " << pp->get_file(); + } + cerr << endl; + } +} + /* * This function is the root of all elaboration. The input is the list * of root module names. The function locates the Module definitions @@ -6315,6 +6440,10 @@ Design* elaborate(listroots) if (des->errors > 0) return des; + // Now we have the full design, check for timescale inconsistencies. + if (warn_timescale) + check_timescales(); + if (debug_elaborate) { cerr << ": elaborate: " << "Start calling Package elaborate_sig methods." << endl; diff --git a/lexor.lex b/lexor.lex index 3381581a79..70fc1fda98 100644 --- a/lexor.lex +++ b/lexor.lex @@ -311,15 +311,6 @@ TU [munpf] BEGIN(UDPTABLE); break; - /* Translate these to checks if we already have or are - * outside the declaration region. */ - case K_timeunit: - if (have_timeunit_decl) rc = K_timeunit_check; - break; - case K_timeprecision: - if (have_timeprec_decl) rc = K_timeprecision_check; - break; - default: yylval.text = 0; break; diff --git a/main.cc b/main.cc index e3ee2a56ab..cb087239e9 100644 --- a/main.cc +++ b/main.cc @@ -1085,7 +1085,6 @@ int main(int argc, char*argv[]) if (flag_tmp) disable_concatz_generation = strcmp(flag_tmp,"true")==0; /* Parse the input. Make the pform. */ - pform_set_timescale(def_ts_units, def_ts_prec, 0, 0); int rc = 0; for (unsigned idx = 0; idx < source_files.size(); idx += 1) { rc += pform_parse(source_files[idx]); diff --git a/parse.y b/parse.y index 1a06fa83f8..a48b84ef17 100644 --- a/parse.y +++ b/parse.y @@ -1,7 +1,7 @@ %{ /* - * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -35,9 +35,6 @@ class PSpecPath; extern void lex_end_table(); -bool have_timeunit_decl = false; -bool have_timeprec_decl = false; - static list* param_active_range = 0; static bool param_active_signed = false; static ivl_variable_type_t param_active_type = IVL_VT_LOGIC; @@ -532,8 +529,6 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %token K_tagged K_this K_throughout K_timeprecision K_timeunit K_type %token K_typedef K_union K_unique K_var K_virtual K_void K_wait_order %token K_wildcard K_with K_within - /* Fake tokens that are passed once we have an initial token. */ -%token K_timeprecision_check K_timeunit_check /* The new tokens from 1800-2009. */ %token K_accept_on K_checker K_endchecker K_eventually K_global K_implies @@ -692,7 +687,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %left UNARY_PREC -/* to resolve dangling else ambiguity. */ + /* to resolve dangling else ambiguity. */ %nonassoc less_than_K_else %nonassoc K_else @@ -700,12 +695,22 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %nonassoc '(' %nonassoc K_exclude + /* to resolve timeunits declaration/redeclaration ambiguity */ +%precedence no_timeunits_declaration +%precedence one_timeunits_declaration +%precedence K_timeunit K_timeprecision + %% /* IEEE1800-2005: A.1.2 */ /* source_text ::= [ timeunits_declaration ] { description } */ -source_text : description_list | ; +source_text + : timeunits_declaration_opt + { pform_set_scope_timescale(yyloc); } + description_list + | /* empty */ + ; assertion_item /* IEEE1800-2012: A.6.10 */ : concurrent_assertion_item @@ -1137,11 +1142,7 @@ data_type_or_implicit_or_void } ; - /* NOTE 1: We pull the "timeunits_declaration" into the description - here in order to be a little more flexible with where timeunits - statements may go. This may be a bad idea, but it is legacy now. */ - - /* NOTE 2: The "module" rule of the description combines the + /* NOTE: The "module" rule of the description combines the module_declaration, program_declaration, and interface_declaration rules from the standard description. */ @@ -1726,17 +1727,18 @@ open_range_list /* IEEE1800-2005 A.2.11 */ package_declaration /* IEEE1800-2005 A.1.2 */ : K_package lifetime_opt IDENTIFIER ';' - { pform_start_package_declaration(@1, $3, $2); - } + { pform_start_package_declaration(@1, $3, $2); } + timeunits_declaration_opt + { pform_set_scope_timescale(@1); } package_item_list_opt K_endpackage endlabel_opt { pform_end_package_declaration(@1); // If an end label is present make sure it match the package name. - if ($8) { - if (strcmp($3,$8) != 0) { - yyerror(@8, "error: End label doesn't match package name"); + if ($10) { + if (strcmp($3,$10) != 0) { + yyerror(@10, "error: End label doesn't match package name"); } - delete[]$8; + delete[]$10; } delete[]$3; } @@ -2230,20 +2232,23 @@ tf_port_list /* IEEE1800-2005: A.2.7 */ } ; - /* NOTE: Icarus Verilog is a little more generous with the - timeunits declarations by allowing them to happen in multiple - places in the file. So the rule is adjusted to be invoked by the - "description" rule. This theoretically allows files to be - concatenated together and still compile. */ timeunits_declaration /* IEEE1800-2005: A.1.2 */ : K_timeunit TIME_LITERAL ';' - { pform_set_timeunit($2, false, false); } + { pform_set_timeunit($2); } | K_timeunit TIME_LITERAL '/' TIME_LITERAL ';' - { pform_set_timeunit($2, false, false); - pform_set_timeprecision($4, false, false); + { pform_set_timeunit($2); + pform_set_timeprecision($4); } | K_timeprecision TIME_LITERAL ';' - { pform_set_timeprecision($2, false, false); } + { pform_set_timeprecision($2); } + ; + + /* Allow zero, one, or two declarations. The second declaration might + be a repeat declaration, but the pform functions take care of that. */ +timeunits_declaration_opt + : /* empty */ %prec no_timeunits_declaration + | timeunits_declaration %prec one_timeunits_declaration + | timeunits_declaration timeunits_declaration ; value_range /* IEEE1800-2005: A.8.3 */ @@ -4409,47 +4414,6 @@ cont_assign_list { $$ = $1; } ; - /* We allow zero, one or two unique declarations. */ -local_timeunit_prec_decl_opt - : /* Empty */ - | K_timeunit TIME_LITERAL '/' TIME_LITERAL ';' - { pform_set_timeunit($2, true, false); - have_timeunit_decl = true; - pform_set_timeprecision($4, true, false); - have_timeprec_decl = true; - } - | local_timeunit_prec_decl - | local_timeunit_prec_decl local_timeunit_prec_decl2 - ; - - /* By setting the appropriate have_time???_decl we allow only - one declaration of each type in this module. */ -local_timeunit_prec_decl - : K_timeunit TIME_LITERAL ';' - { pform_set_timeunit($2, true, false); - have_timeunit_decl = true; - } - | K_timeprecision TIME_LITERAL ';' - { pform_set_timeprecision($2, true, false); - have_timeprec_decl = true; - } - ; -local_timeunit_prec_decl2 - : K_timeunit TIME_LITERAL ';' - { pform_set_timeunit($2, true, false); - have_timeunit_decl = true; - } - | K_timeprecision TIME_LITERAL ';' - { pform_set_timeprecision($2, true, false); - have_timeprec_decl = true; - } - /* As the second item this form is always a check. */ - | K_timeunit TIME_LITERAL '/' TIME_LITERAL ';' - { pform_set_timeunit($2, true, true); - pform_set_timeprecision($4, true, true); - } - ; - /* This is the global structure of a module. A module is a start section, with optional ports, then an optional list of module items, and finally an end marker. */ @@ -4462,11 +4426,8 @@ module module_port_list_opt module_attribute_foreign ';' { pform_module_set_ports($8); } - local_timeunit_prec_decl_opt - { have_timeunit_decl = true; // Every thing past here is - have_timeprec_decl = true; // a check! - pform_check_timeunit_prec(); - } + timeunits_declaration_opt + { pform_set_scope_timescale(@2); } module_item_list_opt module_end { Module::UCDriveType ucd; @@ -4503,8 +4464,6 @@ module } } pform_endmodule($4, in_celldefine, ucd); - have_timeunit_decl = false; // We will allow decls again. - have_timeprec_decl = false; } endlabel_opt { // Last step: check any closing name. This is done late so @@ -4896,6 +4855,8 @@ module_item | attribute_list_opt assertion_item + | timeunits_declaration + | class_declaration | task_declaration @@ -5019,14 +4980,6 @@ module_item | KK_attribute '(' error ')' ';' { yyerror(@1, "error: Malformed $attribute parameter list."); } - | K_timeunit_check TIME_LITERAL ';' - { pform_set_timeunit($2, true, true); } - | K_timeunit_check TIME_LITERAL '/' TIME_LITERAL ';' - { pform_set_timeunit($2, true, true); - pform_set_timeprecision($4, true, true); - } - | K_timeprecision_check TIME_LITERAL ';' - { pform_set_timeprecision($2, true, true); } ; module_item_list diff --git a/parse_misc.h b/parse_misc.h index ddee21bf74..d02902013e 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -1,7 +1,7 @@ #ifndef IVL_parse_misc_H #define IVL_parse_misc_H /* - * Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2017 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 @@ -71,12 +71,6 @@ extern unsigned long based_size; extern bool in_celldefine; enum UCDriveType { UCD_NONE, UCD_PULL0, UCD_PULL1 }; extern UCDriveType uc_drive; -/* - * Flags to control if we are declaring or checking a timeunit or - * timeprecision statement. - */ -extern bool have_timeunit_decl; -extern bool have_timeprec_decl; /* * The parser signals back to the lexor that the next identifier diff --git a/pform.cc b/pform.cc index 1be0e2b464..f071d1fbf9 100644 --- a/pform.cc +++ b/pform.cc @@ -73,6 +73,7 @@ vector pform_units; static bool is_compilation_unit(LexicalScope*scope) { // A compilation unit is the only scope that doesn't have a parent. + assert(scope); return scope->parent_scope() == 0; } @@ -355,30 +356,27 @@ static PModport*pform_cur_modport = 0; 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. + * These variables track the time scale set by the most recent `timescale + * directive. Time scales set by SystemVerilog timeunit and timeprecision + * declarations are stored directly in the current lexical scope. */ static int pform_time_unit; static int pform_time_prec; -/* These two flags check the initial timeprecision and timeunit - * declaration inside a module. - */ -static bool tp_decl_flag = false; -static bool tu_decl_flag = false; - /* - * Flags used to set time_from_timescale based on timeunit and - * timeprecision. + * These variables track where the most recent `timescale directive + * occurred. This allows us to warn about time scales that are inherited + * from another file. */ -static bool tu_global_flag = false; -static bool tp_global_flag = false; -static bool tu_local_flag = false; -static bool tp_local_flag = false; - static char*pform_timescale_file = 0; static unsigned pform_timescale_line; +/* + * These variables track whether we can accept new timeunits declarations. + */ +bool allow_timeunit_decl = true; +bool allow_timeprec_decl = true; + static inline void FILE_NAME(LineInfo*obj, const char*file, unsigned lineno) { obj->set_lineno(lineno); @@ -426,17 +424,57 @@ static PScopeExtra* find_nearest_scopex(LexicalScope*scope) } /* - * Set the local time unit/precision to the global value. + * Set the local time unit/precision. This version is used for setting + * the time scale for design elements (modules, packages, etc.) and is + * called after any initial timeunit and timeprecision declarations + * have been parsed. */ -static void pform_set_scope_timescale(PScope*scope, const struct vlltype&loc) -{ - scope->time_unit = pform_time_unit; - scope->time_precision = pform_time_prec; - /* If we have a timescale file then the time information is from - * a timescale directive. */ - scope->time_from_timescale = pform_timescale_file != 0; +void pform_set_scope_timescale(const struct vlltype&loc) +{ + PScopeExtra*scope = dynamic_cast(lexical_scope); + assert(scope); + + PScopeExtra*parent = find_nearest_scopex(scope->parent_scope()); + + bool used_global_timescale = false; + if (scope->time_unit_is_default) { + if (is_compilation_unit(scope)) { + scope->time_unit = def_ts_units; + } else if (!is_compilation_unit(parent)) { + scope->time_unit = parent->time_unit; + scope->time_unit_is_default = parent->time_unit_is_default; + } else if (pform_timescale_file != 0) { + scope->time_unit = pform_time_unit; + scope->time_unit_is_default = false; + used_global_timescale = true; + } else /* parent is compilation unit */ { + scope->time_unit = parent->time_unit; + scope->time_unit_is_default = parent->time_unit_is_default; + } + } + if (scope->time_prec_is_default) { + if (is_compilation_unit(scope)) { + scope->time_precision = def_ts_prec; + } else if (!is_compilation_unit(parent)) { + scope->time_precision = parent->time_precision; + scope->time_prec_is_default = parent->time_prec_is_default; + } else if (pform_timescale_file != 0) { + scope->time_precision = pform_time_prec; + scope->time_prec_is_default = false; + used_global_timescale = true; + } else { + scope->time_precision = parent->time_precision; + scope->time_prec_is_default = parent->time_prec_is_default; + } + } + + if (gn_system_verilog() && (scope->time_unit < scope->time_precision)) { + VLerror("error: a timeprecision is missing or is too large!"); + } else { + assert(scope->time_unit >= scope->time_precision); + } - if (warn_timescale && is_compilation_unit(lexical_scope) && pform_timescale_file + if (warn_timescale && used_global_timescale && (strcmp(pform_timescale_file, loc.text) != 0)) { cerr << loc.get_fileline() << ": warning: " @@ -445,6 +483,22 @@ static void pform_set_scope_timescale(PScope*scope, const struct vlltype&loc) cerr << pform_timescale_file << ":" << pform_timescale_line << ": ...: The inherited timescale is here." << endl; } + + allow_timeunit_decl = false; + allow_timeprec_decl = false; +} + +/* + * Set the local time unit/precision. This version is used for setting + * the time scale for subsidiary items (classes, subroutines, etc.), + * which simply inherit their time scale from their parent scope. + */ +static void pform_set_scope_timescale(PScope*scope, const PScope*parent) +{ + scope->time_unit = parent->time_unit; + scope->time_precision = parent->time_precision; + scope->time_unit_is_default = parent->time_unit_is_default; + scope->time_prec_is_default = parent->time_prec_is_default; } PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name, @@ -454,12 +508,12 @@ PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name, class_scope->default_lifetime = find_lifetime(lifetime); FILE_NAME(class_scope, loc); - pform_set_scope_timescale(class_scope, loc); - PScopeExtra*scopex = find_nearest_scopex(lexical_scope); assert(scopex); assert(!pform_cur_generate); + pform_set_scope_timescale(class_scope, scopex); + if (scopex->classes.find(name) != scopex->classes.end()) { cerr << class_scope->get_fileline() << ": error: duplicate " "definition for class '" << name << "' in '" @@ -480,7 +534,8 @@ PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name, pkg_scope->default_lifetime = find_lifetime(lifetime); FILE_NAME(pkg_scope, loc); - pform_set_scope_timescale(pkg_scope, loc); + allow_timeunit_decl = true; + allow_timeprec_decl = true; lexical_scope = pkg_scope; return pkg_scope; @@ -498,8 +553,6 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, task->default_lifetime = default_lifetime; FILE_NAME(task, loc); - pform_set_scope_timescale(task, loc); - PScopeExtra*scopex = find_nearest_scopex(lexical_scope); assert(scopex); if (is_compilation_unit(scopex) && !gn_system_verilog()) { @@ -508,6 +561,8 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, error_count += 1; } + pform_set_scope_timescale(task, scopex); + if (pform_cur_generate) { // Check if the task is already in the dictionary. if (pform_cur_generate->tasks.find(task->pscope_name()) != @@ -547,8 +602,6 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name, func->default_lifetime = default_lifetime; FILE_NAME(func, loc); - pform_set_scope_timescale(func, loc); - PScopeExtra*scopex = find_nearest_scopex(lexical_scope); assert(scopex); if (is_compilation_unit(scopex) && !gn_system_verilog()) { @@ -557,6 +610,8 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name, error_count += 1; } + pform_set_scope_timescale(func, scopex); + if (pform_cur_generate) { // Check if the function is already in the dictionary. if (pform_cur_generate->funcs.find(func->pscope_name()) != @@ -907,64 +962,23 @@ static void pform_declare_implicit_nets(PExpr*expr) /* * The lexor calls this function to set the active timescale when it * detects a `timescale directive. The function saves the directive - * values (for use by modules) and if warnings are enabled checks to - * see if some modules have no timescale. + * values (for use by subsequent design elements) and if warnings are + * enabled checks to see if some design elements have no timescale. */ void pform_set_timescale(int unit, int prec, const char*file, unsigned lineno) { - bool first_flag = true; - assert(unit >= prec); pform_time_unit = unit; pform_time_prec = prec; - /* A `timescale clears the timeunit/timeprecision state. */ - tu_global_flag = false; - tp_global_flag = false; if (pform_timescale_file) { free(pform_timescale_file); - first_flag = false; } if (file) pform_timescale_file = strdup(file); else pform_timescale_file = 0; pform_timescale_line = lineno; - - 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; - cerr << file << ":" << lineno << ": : " - << "confusing timing results. Affected modules are:" - << endl; - - for (mod = pform_modules.begin() - ; mod != pform_modules.end() ; ++ mod ) { - 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 - << " declared here: " << mp->get_fileline() << endl; - } - } } bool get_time_unit(const char*cp, int &unit) @@ -1084,70 +1098,62 @@ static bool get_time_unit_prec(const char*cp, int &res, bool is_unit) return true; } -void pform_set_timeunit(const char*txt, bool in_module, bool only_check) +void pform_set_timeunit(const char*txt) { int val; if (get_time_unit_prec(txt, val, true)) return; - if (in_module) { - if (!only_check) { - pform_cur_module.front()->time_unit = val; - tu_decl_flag = true; - tu_local_flag = true; - } else if (!tu_decl_flag) { - VLerror(yylloc, "error: repeat timeunit found and the " - "initial module timeunit is missing."); - return; - } else if (pform_cur_module.front()->time_unit != val) { - VLerror(yylloc, "error: repeat timeunit does not match " - "the initial module timeunit " - "declaration."); - return; - } - + PScopeExtra*scope = dynamic_cast(lexical_scope); + assert(scope); + + if (allow_timeunit_decl) { + scope->time_unit = val; + scope->time_unit_is_local = true; + scope->time_unit_is_default = false; + allow_timeunit_decl = false; + } else if (!scope->time_unit_is_local) { + VLerror(yylloc, "error: repeat timeunit found and the initial " + "timeunit for this scope is missing."); + } else if (scope->time_unit != val) { + VLerror(yylloc, "error: repeat timeunit does not match the " + "initial timeunit for this scope."); } else { - /* Skip a global timeunit when `timescale is defined. */ - if (pform_timescale_file) return; - tu_global_flag = true; - pform_time_unit = val; + // This is a redeclaration, so don't allow any new declarations + allow_timeprec_decl = false; } } int pform_get_timeunit() { - if (pform_cur_module.empty()) - return pform_time_unit; - else - return pform_cur_module.front()->time_unit; + PScopeExtra*scopex = find_nearest_scopex(lexical_scope); + assert(scopex); + return scopex->time_unit; } -void pform_set_timeprecision(const char*txt, bool in_module, bool only_check) +void pform_set_timeprecision(const char*txt) { int val; if (get_time_unit_prec(txt, val, false)) return; - if (in_module) { - if (!only_check) { - pform_cur_module.front()->time_precision = val; - tp_decl_flag = true; - tp_local_flag = true; - } else if (!tp_decl_flag) { - VLerror(yylloc, "error: repeat timeprecision found and the " - "initial module timeprecision is missing."); - return; - } else if (pform_cur_module.front()->time_precision != val) { - VLerror(yylloc, "error: repeat timeprecision does not match " - "the initial module timeprecision " - "declaration."); - return; - } + PScopeExtra*scope = dynamic_cast(lexical_scope); + assert(scope); + + if (allow_timeprec_decl) { + scope->time_precision = val; + scope->time_prec_is_local = true; + scope->time_prec_is_default = false; + allow_timeprec_decl = false; + } else if (!scope->time_prec_is_local) { + VLerror(yylloc, "error: repeat timeprecision found and the initial " + "timeprecision for this scope is missing."); + } else if (scope->time_precision != val) { + VLerror(yylloc, "error: repeat timeprecision does not match the " + "initial timeprecision for this scope."); } else { - /* Skip a global timeprecision when `timescale is defined. */ - if (pform_timescale_file) return; - pform_time_prec = val; - tp_global_flag=true; + // This is a redeclaration, so don't allow any new declarations + allow_timeunit_decl = false; } } @@ -1252,14 +1258,13 @@ void pform_startmodule(const struct vlltype&loc, const char*name, FILE_NAME(cur_module, loc); - pform_set_scope_timescale(cur_module, loc); - tu_local_flag = tu_global_flag; - tp_local_flag = tp_global_flag; - cur_module->library_flag = pform_library_flag; pform_cur_module.push_front(cur_module); + allow_timeunit_decl = true; + allow_timeprec_decl = true; + lexical_scope = cur_module; /* The generate scheme numbering starts with *1*, not @@ -1269,21 +1274,6 @@ void pform_startmodule(const struct vlltype&loc, const char*name, pform_bind_attributes(cur_module->attributes, attr); } -/* - * In SystemVerilog we can have separate timeunit and timeprecision - * declarations. We need to have the values worked out by time this - * task is called. - */ -void pform_check_timeunit_prec() -{ - assert(! pform_cur_module.empty()); - if (gn_system_verilog() && - (pform_cur_module.front()->time_unit < pform_cur_module.front()->time_precision)) { - VLerror("error: a timeprecision is missing or is too large!"); - } else assert(pform_cur_module.front()->time_unit >= - pform_cur_module.front()->time_precision); -} - /* * This function is called by the parser to make a simple port * reference. This is a name without a .X(...), so the internal name @@ -1327,8 +1317,6 @@ void pform_endmodule(const char*name, bool inside_celldefine, Module*cur_module = pform_cur_module.front(); pform_cur_module.pop_front(); - cur_module->time_from_timescale = (tu_local_flag && tp_local_flag) - || (pform_timescale_file != 0); perm_string mod_name = cur_module->mod_name(); assert(strcmp(name, mod_name) == 0); cur_module->is_cell = inside_celldefine; @@ -1358,11 +1346,6 @@ void pform_endmodule(const char*name, bool inside_celldefine, // The current lexical scope should be this module by now. ivl_assert(*cur_module, lexical_scope == cur_module); pform_pop_scope(); - - tp_decl_flag = false; - tu_decl_flag = false; - tu_local_flag = false; - tp_local_flag = false; } static void pform_add_genvar(const struct vlltype&li, const perm_string&name, @@ -3691,12 +3674,18 @@ int pform_parse(const char*path) sprintf(unit_name, "$unit#%u", ++nunits); else sprintf(unit_name, "$unit"); + PPackage*unit = new PPackage(lex_strings.make(unit_name), 0); unit->default_lifetime = LexicalScope::STATIC; - unit->time_unit = def_ts_units; - unit->time_precision = def_ts_prec; - unit->time_from_timescale = false; + unit->set_file(filename_strings.make(path)); + unit->set_lineno(1); pform_units.push_back(unit); + + pform_set_timescale(def_ts_units, def_ts_prec, 0, 0); + + allow_timeunit_decl = true; + allow_timeprec_decl = true; + lexical_scope = unit; } reset_lexor(); diff --git a/pform.h b/pform.h index 8666386eb5..b533254047 100644 --- a/pform.h +++ b/pform.h @@ -1,7 +1,7 @@ #ifndef IVL_pform_H #define IVL_pform_H /* - * Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2017 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 @@ -165,8 +165,8 @@ extern void pform_startmodule(const struct vlltype&loc, const char*name, bool program_block, bool is_interface, LexicalScope::lifetime_t lifetime, list*attr); -extern void pform_check_timeunit_prec(); extern void pform_module_set_ports(vector*); +extern void pform_set_scope_timescale(const struct vlltype&loc); /* These functions are used when we have a complete port definition, either in an ansi style or non-ansi style declaration. In this case, we have @@ -567,8 +567,7 @@ extern void parm_to_defparam_list(const string¶m); */ extern bool get_time_unit(const char*cp, int &unit); extern int pform_get_timeunit(); -extern void pform_set_timeunit(const char*txt, bool in_module, bool only_check); -extern void pform_set_timeprecision(const char*txt, bool in_module, - bool only_check); +extern void pform_set_timeunit(const char*txt); +extern void pform_set_timeprecision(const char*txt); #endif /* IVL_pform_H */