Skip to content

Commit

Permalink
Support timescales in design units that aren't inside a module.
Browse files Browse the repository at this point in the history
SystemVerilog allows tasks, functions, and classes to be defined at the
root level or inside packages, so we can't rely on an enclosing module
being present to provide the timescale.
  • Loading branch information
martinwhitaker committed Jul 22, 2016
1 parent e316cc7 commit 7bed181
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 74 deletions.
5 changes: 1 addition & 4 deletions Module.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2015 Stephen Williams ([email protected])
* Copyright (c) 1998-2016 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 @@ -36,9 +36,6 @@ Module::Module(LexicalScope*parent, perm_string n)
program_block = false;
uc_drive = UCD_NONE;
timescale_warn_done = false;
time_unit = 0;
time_precision = 0;
time_from_timescale = false;
}

Module::~Module()
Expand Down
6 changes: 1 addition & 5 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-2015 Stephen Williams ([email protected])
* Copyright (c) 1998-2016 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,10 +121,6 @@ class Module : public PScopeExtra, public LineInfo {

map<perm_string,PExpr*> attributes;

/* These are the timescale for this module. The default is
set by the `timescale directive. */
int time_unit, time_precision;
bool time_from_timescale;
bool timescale_warn_done;

/* The module has a list of generate schemes that appear in
Expand Down
31 changes: 12 additions & 19 deletions PScope.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008,2010 Stephen Williams ([email protected])
* Copyright (c) 2008,2016 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 All @@ -24,14 +24,21 @@ bool LexicalScope::var_init_needs_explicit_lifetime() const
return false;
}

PScope::PScope(perm_string n, LexicalScope*parent)
: LexicalScope(parent), name_(n)
PWire* LexicalScope::wires_find(perm_string name)
{
map<perm_string,PWire*>::const_iterator cur = wires.find(name);
if (cur == wires.end())
return 0;
else
return (*cur).second;
}

PScope::PScope(perm_string n)
: LexicalScope(0), name_(n)
PScope::PScope(perm_string n, LexicalScope*parent)
: LexicalScope(parent), name_(n)
{
time_unit = 0;
time_precision = 0;
time_from_timescale = false;
}

PScope::~PScope()
Expand All @@ -41,25 +48,11 @@ PScope::~PScope()
delete it->second;
}

PWire* LexicalScope::wires_find(perm_string name)
{
map<perm_string,PWire*>::const_iterator cur = wires.find(name);
if (cur == wires.end())
return 0;
else
return (*cur).second;
}

PScopeExtra::PScopeExtra(perm_string n, LexicalScope*parent)
: PScope(n, parent)
{
}

PScopeExtra::PScopeExtra(perm_string n)
: PScope(n)
{
}

PScopeExtra::~PScopeExtra()
{
}
14 changes: 9 additions & 5 deletions PScope.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,17 @@ class PScope : public LexicalScope {
// modules do not nest in Verilog, the parent must be nil for
// modules. Scopes for tasks and functions point to their
// containing module.
PScope(perm_string name, LexicalScope*parent);
explicit PScope(perm_string name);
explicit PScope(perm_string name, LexicalScope*parent =0);
virtual ~PScope();

perm_string pscope_name() const { return name_; }

/* These are the timescale for this scope. The default is
set by the `timescale directive or, in SystemVerilog,
by timeunit and timeprecision statements. */
int time_unit, time_precision;
bool time_from_timescale;

protected:
bool elaborate_sig_wires_(Design*des, NetScope*scope) const;

Expand All @@ -182,14 +187,13 @@ class PScope : public LexicalScope {
class PScopeExtra : public PScope {

public:
PScopeExtra(perm_string, LexicalScope*parent);
explicit PScopeExtra(perm_string);
explicit PScopeExtra(perm_string, LexicalScope*parent =0);
~PScopeExtra();

/* Task definitions within this module */
std::map<perm_string,PTask*> tasks;
std::map<perm_string,PFunction*> funcs;
/* class definitions within this module. */
/* Class definitions within this module. */
std::map<perm_string,PClass*> classes;
/* This is the lexical order of the classes, and is used by
elaboration to choose an elaboration order. */
Expand Down
26 changes: 18 additions & 8 deletions elab_scope.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2015 Stephen Williams ([email protected])
* Copyright (c) 2000-2016 Stephen Williams ([email protected])
* Copyright CERN 2013 / Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
Expand Down Expand Up @@ -54,6 +54,15 @@
# include <cassert>
# include "ivl_assert.h"


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);
des->set_precision(pscope->time_precision);
}

typedef map<perm_string,LexicalScope::param_expr_t>::const_iterator mparm_it_t;

static void collect_parm_item_(Design*des, NetScope*scope, perm_string name,
Expand Down Expand Up @@ -523,6 +532,7 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
class_scope->set_class_def(use_class);
use_class->set_class_scope(class_scope);
use_class->set_definition_scope(scope);
set_scope_timescale(des, class_scope, pclass);

// Collect the properties, elaborate them, and add them to the
// elaborated class definition.
Expand Down Expand Up @@ -654,8 +664,10 @@ static void elaborate_scope_task(Design*des, NetScope*scope, PTask*task)
task_scope->is_auto(task->is_auto());
task_scope->set_line(task);

if (scope==0)
if (scope==0) {
set_scope_timescale(des, task_scope, task);
des->add_root_task(task_scope, task);
}

if (debug_scopes) {
cerr << task->get_fileline() << ": elaborate_scope_task: "
Expand Down Expand Up @@ -719,8 +731,10 @@ static void elaborate_scope_func(Design*des, NetScope*scope, PFunction*task)
task_scope->is_auto(task->is_auto());
task_scope->set_line(task);

if (scope==0)
if (scope==0) {
set_scope_timescale(des, task_scope, task);
des->add_root_task(task_scope, task);
}

if (debug_scopes) {
cerr << task->get_fileline() << ": elaborate_scope_func: "
Expand Down Expand Up @@ -1750,11 +1764,7 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s

instances[idx] = my_scope;

// Set time units and precision.
my_scope->time_unit(mod->time_unit);
my_scope->time_precision(mod->time_precision);
my_scope->time_from_timescale(mod->time_from_timescale);
des->set_precision(mod->time_precision);
set_scope_timescale(des, my_scope, mod);

// Look for module parameter replacements. The "replace" map
// maps parameter name to replacement expression that is
Expand Down
11 changes: 6 additions & 5 deletions elaborate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
# include "PEvent.h"
# include "PGenerate.h"
# include "PPackage.h"
# include "PScope.h"
# include "PSpec.h"
# include "netlist.h"
# include "netenum.h"
Expand All @@ -50,6 +51,9 @@
# include "ivl_assert.h"


// Implemented in elab_scope.cc
extern void set_scope_timescale(Design*des, NetScope*scope, PScope*pscope);

void PGate::elaborate(Design*, NetScope*) const
{
cerr << "internal error: what kind of gate? " <<
Expand Down Expand Up @@ -6215,6 +6219,7 @@ Design* elaborate(list<perm_string>roots)
ivl_assert(*pac->second, pac->first == pac->second->pscope_name());
NetScope*scope = des->make_package_scope(pac->first);
scope->set_line(pac->second);
set_scope_timescale(des, scope, pac->second);

elaborator_work_item_t*es = new elaborate_package_t(des, scope, pac->second);
des->elaboration_work_list.push_back(es);
Expand Down Expand Up @@ -6251,11 +6256,7 @@ Design* elaborate(list<perm_string>roots)
// Collect some basic properties of this scope from the
// Module definition.
scope->set_line(rmod);
scope->time_unit(rmod->time_unit);
scope->time_precision(rmod->time_precision);
scope->time_from_timescale(rmod->time_from_timescale);
des->set_precision(rmod->time_precision);

set_scope_timescale(des, scope, rmod);

// Save this scope, along with its definition, in the
// "root_elems" list for later passes.
Expand Down
50 changes: 33 additions & 17 deletions pform.cc
Original file line number Diff line number Diff line change
Expand Up @@ -345,13 +345,37 @@ static PScopeExtra* find_nearest_scopex(LexicalScope*scope)
return scopex;
}

/*
* Set the local time unit/precision to the global value.
*/
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;

if (warn_timescale && (lexical_scope == 0) && pform_timescale_file
&& (strcmp(pform_timescale_file, loc.text) != 0)) {

cerr << loc.get_fileline() << ": warning: "
<< "timescale for " << scope->pscope_name()
<< " inherited from another file." << endl;
cerr << pform_timescale_file << ":" << pform_timescale_line
<< ": ...: The inherited timescale is here." << endl;
}
}

PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name,
LexicalScope::lifetime_t lifetime)
{
PClass*class_scope = new PClass(name, lexical_scope);
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(!pform_cur_generate);
Expand Down Expand Up @@ -384,6 +408,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);

lexical_scope = pkg_scope;
return pkg_scope;
}
Expand All @@ -400,6 +426,8 @@ 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);
if ((scopex == 0) && !gn_system_verilog()) {
cerr << task->get_fileline() << ": error: task declarations "
Expand Down Expand Up @@ -455,6 +483,8 @@ 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);
if ((scopex == 0) && (generation_flag < GN_VER2005_SV)) {
cerr << func->get_fileline() << ": error: function declarations "
Expand Down Expand Up @@ -1200,17 +1230,12 @@ void pform_startmodule(const struct vlltype&loc, const char*name,
cur_module->is_interface = is_interface;
cur_module->default_lifetime = find_lifetime(lifetime);

/* Set the local time unit/precision to the global value. */
cur_module->time_unit = pform_time_unit;
cur_module->time_precision = pform_time_prec;
FILE_NAME(cur_module, loc);

pform_set_scope_timescale(cur_module, loc);
tu_local_flag = tu_global_flag;
tp_local_flag = tp_global_flag;

/* If we have a timescale file then the time information is from
* a timescale directive. */
cur_module->time_from_timescale = pform_timescale_file != 0;

FILE_NAME(cur_module, loc);
cur_module->library_flag = pform_library_flag;

pform_cur_module.push_front(cur_module);
Expand All @@ -1221,15 +1246,6 @@ void pform_startmodule(const struct vlltype&loc, const char*name,
zero. That's just the way it is, thanks to the standard. */
scope_generate_counter = 1;

if (warn_timescale && pform_timescale_file
&& (strcmp(pform_timescale_file,loc.text) != 0)) {

cerr << cur_module->get_fileline() << ": warning: "
<< "timescale for " << name
<< " inherited from another file." << endl;
cerr << pform_timescale_file << ":" << pform_timescale_line
<< ": ...: The inherited timescale is here." << endl;
}
pform_bind_attributes(cur_module->attributes, attr);
}

Expand Down
7 changes: 1 addition & 6 deletions vpi/sys_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -2055,12 +2055,7 @@ static PLI_INT32 sys_printtimescale_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
item = vpi_scan(argv);
vpi_free_object(argv);
}

if (vpi_get(vpiType, item) != vpiModule) {
scope = vpi_handle(vpiModule, item);
} else {
scope = item;
}
scope = sys_func_module(item);

vpi_printf("Time scale of (%s) is ", vpi_get_str(vpiFullName, item));
vpi_printf("%s / ", pts_convert(vpi_get(vpiTimeUnit, scope)));
Expand Down
11 changes: 7 additions & 4 deletions vpi/sys_priv.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003-2011 Stephen Williams ([email protected])
* Copyright (c) 2003-2016 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 @@ -229,15 +229,18 @@ unsigned is_string_obj(vpiHandle obj)


/*
* Find the enclosing module.
* Find the enclosing module. If there is no enclosing module (which can be
* the case in SystemVerilog), return the highest enclosing scope.
*/
vpiHandle sys_func_module(vpiHandle obj)
{
assert(obj);

while (vpi_get(vpiType, obj) != vpiModule) {
obj = vpi_handle(vpiScope, obj);
assert(obj);
vpiHandle scope = vpi_handle(vpiScope, obj);
if (scope == 0)
break;
obj = scope;
}

return obj;
Expand Down
Loading

0 comments on commit 7bed181

Please sign in to comment.