Skip to content

Commit

Permalink
Rework handling of timescales in parser.
Browse files Browse the repository at this point in the history
This implements and enforces the full set of rules for determining
timescales in SystemVerilog. The previous relaxation of the rules
that allowed timescales to be redefined within the compilation unit
scope has been removed. Time unit and precision redeclarations are
now recognised after a nested module declaration.
  • Loading branch information
martinwhitaker committed Nov 5, 2017
1 parent 9382d22 commit fd807a7
Show file tree
Hide file tree
Showing 12 changed files with 330 additions and 265 deletions.
3 changes: 1 addition & 2 deletions Module.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2016 Stephen Williams ([email protected])
* Copyright (c) 1998-2017 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
Expand Down Expand Up @@ -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()
Expand Down
4 changes: 1 addition & 3 deletions Module.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef IVL_Module_H
#define IVL_Module_H
/*
* Copyright (c) 1998-2016 Stephen Williams ([email protected])
* Copyright (c) 1998-2017 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
Expand Down Expand Up @@ -121,8 +121,6 @@ class Module : public PScopeExtra, public LineInfo {

map<perm_string,PExpr*> 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<PGenerate*> generate_schemes;
Expand Down
7 changes: 5 additions & 2 deletions PScope.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008,2016 Stephen Williams ([email protected])
* Copyright (c) 2008-2017 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
Expand Down Expand Up @@ -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()
Expand All @@ -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()
Expand Down
17 changes: 14 additions & 3 deletions PScope.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef IVL_PScope_H
#define IVL_PScope_H
/*
* Copyright (c) 2008-2016 Stephen Williams ([email protected])
* Copyright (c) 2008-2017 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -199,6 +206,10 @@ class PScopeExtra : public PScope {
elaboration to choose an elaboration order. */
std::vector<PClass*> 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;
Expand Down
2 changes: 1 addition & 1 deletion elab_scope.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
129 changes: 129 additions & 0 deletions elaborate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<perm_string,Module*>::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<perm_string,PPackage*>::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
Expand Down Expand Up @@ -6315,6 +6440,10 @@ Design* elaborate(list<perm_string>roots)
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 << "<toplevel>: elaborate: "
<< "Start calling Package elaborate_sig methods." << endl;
Expand Down
9 changes: 0 additions & 9 deletions lexor.lex
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 0 additions & 1 deletion main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand Down
Loading

0 comments on commit fd807a7

Please sign in to comment.