Don't evaluate built-in system functions if they are overridden.
We don't support evaluating user-defined system functions at compile time. If possible, defer evaluation until run time. If used in a constant expression, output a "sorry" message.
This commit is contained in:
parent
bf655003e8
commit
1069a0ef02
16
PExpr.cc
16
PExpr.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2016 Stephen Williams <steve@icarus.com>
|
||||
* Copyright (c) 1998-2019 Stephen Williams <steve@icarus.com>
|
||||
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
|
|
@ -203,12 +203,12 @@ PEBShift::~PEBShift()
|
|||
}
|
||||
|
||||
PECallFunction::PECallFunction(const pform_name_t&n, const vector<PExpr *> &parms)
|
||||
: package_(0), path_(n), parms_(parms)
|
||||
: package_(0), path_(n), parms_(parms), is_overridden_(false)
|
||||
{
|
||||
}
|
||||
|
||||
PECallFunction::PECallFunction(PPackage*pkg, const pform_name_t&n, const vector<PExpr *> &parms)
|
||||
: package_(pkg), path_(n), parms_(parms)
|
||||
: package_(pkg), path_(n), parms_(parms), is_overridden_(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -221,7 +221,7 @@ static pform_name_t pn_from_ps(perm_string n)
|
|||
}
|
||||
|
||||
PECallFunction::PECallFunction(PPackage*pkg, perm_string n, const list<PExpr *> &parms)
|
||||
: package_(pkg), path_(pn_from_ps(n)), parms_(parms.size())
|
||||
: package_(pkg), path_(pn_from_ps(n)), parms_(parms.size()), is_overridden_(false)
|
||||
{
|
||||
int tmp_idx = 0;
|
||||
assert(parms_.size() == parms.size());
|
||||
|
|
@ -231,18 +231,18 @@ PECallFunction::PECallFunction(PPackage*pkg, perm_string n, const list<PExpr *>
|
|||
}
|
||||
|
||||
PECallFunction::PECallFunction(perm_string n, const vector<PExpr*>&parms)
|
||||
: package_(0), path_(pn_from_ps(n)), parms_(parms)
|
||||
: package_(0), path_(pn_from_ps(n)), parms_(parms), is_overridden_(false)
|
||||
{
|
||||
}
|
||||
|
||||
PECallFunction::PECallFunction(perm_string n)
|
||||
: package_(0), path_(pn_from_ps(n))
|
||||
: package_(0), path_(pn_from_ps(n)), is_overridden_(false)
|
||||
{
|
||||
}
|
||||
|
||||
// NOTE: Anachronism. Try to work all use of svector out.
|
||||
PECallFunction::PECallFunction(const pform_name_t&n, const list<PExpr *> &parms)
|
||||
: package_(0), path_(n), parms_(parms.size())
|
||||
: package_(0), path_(n), parms_(parms.size()), is_overridden_(false)
|
||||
{
|
||||
int tmp_idx = 0;
|
||||
assert(parms_.size() == parms.size());
|
||||
|
|
@ -252,7 +252,7 @@ PECallFunction::PECallFunction(const pform_name_t&n, const list<PExpr *> &parms)
|
|||
}
|
||||
|
||||
PECallFunction::PECallFunction(perm_string n, const list<PExpr*>&parms)
|
||||
: package_(0), path_(pn_from_ps(n)), parms_(parms.size())
|
||||
: package_(0), path_(pn_from_ps(n)), parms_(parms.size()), is_overridden_(false)
|
||||
{
|
||||
int tmp_idx = 0;
|
||||
assert(parms_.size() == parms.size());
|
||||
|
|
|
|||
3
PExpr.h
3
PExpr.h
|
|
@ -928,6 +928,9 @@ class PECallFunction : public PExpr {
|
|||
pform_name_t path_;
|
||||
std::vector<PExpr *> parms_;
|
||||
|
||||
// For system functions.
|
||||
bool is_overridden_;
|
||||
|
||||
bool check_call_matches_definition_(Design*des, NetScope*dscope) const;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -286,7 +286,8 @@ struct sfunc_return_type {
|
|||
const char* name;
|
||||
ivl_variable_type_t type;
|
||||
unsigned wid;
|
||||
int signed_flag;
|
||||
bool signed_flag;
|
||||
bool override_flag;
|
||||
};
|
||||
|
||||
extern const struct sfunc_return_type* lookup_sys_func(const char*name);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2019 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
|
||||
|
|
@ -233,7 +233,7 @@ NetESelect* NetESelect::dup_expr() const
|
|||
|
||||
NetESFunc* NetESFunc::dup_expr() const
|
||||
{
|
||||
NetESFunc*tmp = new NetESFunc(name_, type_, expr_width(), nparms());
|
||||
NetESFunc*tmp = new NetESFunc(name_, type_, expr_width(), nparms(), is_overridden_);
|
||||
ivl_assert(*this, tmp);
|
||||
|
||||
tmp->cast_signed(has_sign());
|
||||
|
|
|
|||
17
elab_expr.cc
17
elab_expr.cc
|
|
@ -1202,6 +1202,8 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
|
|||
min_width_ = expr_width_;
|
||||
signed_flag_ = sfunc_info->signed_flag;
|
||||
|
||||
is_overridden_ = sfunc_info->override_flag;
|
||||
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: test_width "
|
||||
<< "of system function " << name
|
||||
|
|
@ -1547,10 +1549,19 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
|
|||
if ((nparms == 1) && (parms_[0] == 0))
|
||||
nparms = 0;
|
||||
|
||||
NetESFunc*fun = new NetESFunc(name, expr_type_, expr_width_, nparms);
|
||||
NetESFunc*fun = new NetESFunc(name, expr_type_, expr_width_, nparms, is_overridden_);
|
||||
fun->set_line(*this);
|
||||
|
||||
if (!fun->is_built_in()) {
|
||||
bool need_const = NEED_CONST & flags;
|
||||
|
||||
/* We don't support evaluating overridden functions. */
|
||||
if (is_overridden_ && (need_const || scope->need_const_func())) {
|
||||
cerr << get_fileline() << ": sorry: Cannot evaluate "
|
||||
"overridden system function." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
if (is_overridden_ || !fun->is_built_in()) {
|
||||
if (scope->need_const_func()) {
|
||||
cerr << get_fileline() << ": error: " << name
|
||||
<< " is not a built-in function, so cannot"
|
||||
|
|
@ -1567,8 +1578,6 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
|
|||
expression as much as possible, and use the reduced
|
||||
expression if one is created. */
|
||||
|
||||
bool need_const = NEED_CONST & flags;
|
||||
|
||||
/* These functions can work in a constant context with a signal expression. */
|
||||
if ((nparms == 1) && (dynamic_cast<PEIdent*>(parms_[0]))) {
|
||||
if (strcmp(name, "$dimensions") == 0) need_const = false;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2018 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2019 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
|
||||
|
|
@ -2400,6 +2400,10 @@ NetESFunc::ID NetESFunc::built_in_id_() const
|
|||
|
||||
NetExpr* NetESFunc::eval_tree()
|
||||
{
|
||||
/* We don't support evaluating overridden functions. */
|
||||
if (is_overridden_)
|
||||
return 0;
|
||||
|
||||
/* Get the ID for this system function if it can be used as a
|
||||
* constant function. */
|
||||
ID id = built_in_id_();
|
||||
|
|
|
|||
10
net_expr.cc
10
net_expr.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2002-2019 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
|
||||
|
|
@ -461,15 +461,15 @@ bool NetESelect::has_width() const
|
|||
}
|
||||
|
||||
NetESFunc::NetESFunc(const char*n, ivl_variable_type_t t,
|
||||
unsigned width, unsigned np)
|
||||
: name_(0), type_(t), enum_type_(0), parms_(np)
|
||||
unsigned width, unsigned np, bool is_overridden)
|
||||
: name_(0), type_(t), enum_type_(0), parms_(np), is_overridden_(is_overridden)
|
||||
{
|
||||
name_ = lex_strings.add(n);
|
||||
expr_width(width);
|
||||
}
|
||||
|
||||
NetESFunc::NetESFunc(const char*n, ivl_type_t rtype, unsigned np)
|
||||
: NetExpr(rtype), name_(0), type_(IVL_VT_NO_TYPE), enum_type_(0), parms_(np)
|
||||
: NetExpr(rtype), name_(0), type_(IVL_VT_NO_TYPE), enum_type_(0), parms_(np), is_overridden_(false)
|
||||
{
|
||||
name_ = lex_strings.add(n);
|
||||
expr_width(rtype->packed_width());
|
||||
|
|
@ -485,7 +485,7 @@ NetESFunc::NetESFunc(const char*n, ivl_type_t rtype, unsigned np)
|
|||
}
|
||||
|
||||
NetESFunc::NetESFunc(const char*n, const netenum_t*enum_type, unsigned np)
|
||||
: name_(0), type_(enum_type->base_type()), enum_type_(enum_type), parms_(np)
|
||||
: name_(0), type_(enum_type->base_type()), enum_type_(enum_type), parms_(np), is_overridden_(false)
|
||||
{
|
||||
name_ = lex_strings.add(n);
|
||||
expr_width(enum_type->packed_width());
|
||||
|
|
|
|||
|
|
@ -4538,7 +4538,7 @@ class NetESFunc : public NetExpr {
|
|||
|
||||
public:
|
||||
NetESFunc(const char*name, ivl_variable_type_t t,
|
||||
unsigned width, unsigned nprms);
|
||||
unsigned width, unsigned nprms, bool is_overridden =false);
|
||||
NetESFunc(const char*name, ivl_type_t rtype, unsigned nprms);
|
||||
NetESFunc(const char*name, const netenum_t*enum_type, unsigned nprms);
|
||||
~NetESFunc();
|
||||
|
|
@ -4634,6 +4634,7 @@ class NetESFunc : public NetExpr {
|
|||
ivl_variable_type_t type_;
|
||||
const netenum_t*enum_type_;
|
||||
std::vector<NetExpr*>parms_;
|
||||
bool is_overridden_;
|
||||
|
||||
ID built_in_id_() const;
|
||||
|
||||
|
|
|
|||
42
sys_funcs.cc
42
sys_funcs.cc
|
|
@ -30,14 +30,14 @@
|
|||
*/
|
||||
|
||||
static const struct sfunc_return_type sfunc_table[] = {
|
||||
{ "$realtime", IVL_VT_REAL, 1, 0 },
|
||||
{ "$bitstoreal", IVL_VT_REAL, 1, 0 },
|
||||
{ "$itor", IVL_VT_REAL, 1, 0 },
|
||||
{ "$realtobits", IVL_VT_LOGIC, 64, 0 },
|
||||
{ "$time", IVL_VT_LOGIC, 64, 0 },
|
||||
{ "$stime", IVL_VT_LOGIC, 32, 0 },
|
||||
{ "$simtime", IVL_VT_LOGIC, 64, 0 },
|
||||
{ 0, IVL_VT_LOGIC, 32, 0 }
|
||||
{ "$realtime", IVL_VT_REAL, 1, false, false },
|
||||
{ "$bitstoreal", IVL_VT_REAL, 1, false, false },
|
||||
{ "$itor", IVL_VT_REAL, 1, false, false },
|
||||
{ "$realtobits", IVL_VT_LOGIC, 64, false, false },
|
||||
{ "$time", IVL_VT_LOGIC, 64, false, false },
|
||||
{ "$stime", IVL_VT_LOGIC, 32, false, false },
|
||||
{ "$simtime", IVL_VT_LOGIC, 64, false, false },
|
||||
{ 0, IVL_VT_LOGIC, 32, false, false }
|
||||
};
|
||||
|
||||
struct sfunc_return_type_cell : sfunc_return_type {
|
||||
|
|
@ -69,9 +69,8 @@ void cleanup_sys_func_table()
|
|||
}
|
||||
}
|
||||
|
||||
const struct sfunc_return_type* lookup_sys_func(const char*name)
|
||||
static struct sfunc_return_type* find_in_sys_func_list(const char*name)
|
||||
{
|
||||
/* First, try to find the name in the function list. */
|
||||
struct sfunc_return_type_cell*cur = sfunc_list_head;
|
||||
while (cur) {
|
||||
if (strcmp(cur->name, name) == 0)
|
||||
|
|
@ -80,6 +79,16 @@ const struct sfunc_return_type* lookup_sys_func(const char*name)
|
|||
cur = cur->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct sfunc_return_type* lookup_sys_func(const char*name)
|
||||
{
|
||||
/* First, try to find the name in the function list. */
|
||||
struct sfunc_return_type*def = find_in_sys_func_list(name);
|
||||
if (def)
|
||||
return def;
|
||||
|
||||
/* Next, look in the core table. */
|
||||
unsigned idx = 0;
|
||||
while (sfunc_table[idx].name) {
|
||||
|
|
@ -147,12 +156,21 @@ int load_sys_func_table(const char*path)
|
|||
cp = stype + strcspn(stype, " \t\r\n");
|
||||
if (cp[0]) *cp++ = 0;
|
||||
|
||||
struct sfunc_return_type*def = find_in_sys_func_list(name);
|
||||
if (def) {
|
||||
/* Keep the original definition, but flag that it
|
||||
overrides a later definition. */
|
||||
def->override_flag = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(stype,"vpiSysFuncReal") == 0) {
|
||||
cell = new struct sfunc_return_type_cell;
|
||||
cell->name = lex_strings.add(name);
|
||||
cell->type = IVL_VT_REAL;
|
||||
cell->wid = 1;
|
||||
cell->signed_flag = true;
|
||||
cell->override_flag = false;
|
||||
append_to_list(cell);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -163,6 +181,7 @@ int load_sys_func_table(const char*path)
|
|||
cell->type = IVL_VT_LOGIC;
|
||||
cell->wid = 32;
|
||||
cell->signed_flag = true;
|
||||
cell->override_flag = false;
|
||||
append_to_list(cell);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -203,6 +222,7 @@ int load_sys_func_table(const char*path)
|
|||
cell->type = IVL_VT_LOGIC;
|
||||
cell->wid = width;
|
||||
cell->signed_flag = signed_flag;
|
||||
cell->override_flag = false;
|
||||
append_to_list(cell);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -213,6 +233,7 @@ int load_sys_func_table(const char*path)
|
|||
cell->type = IVL_VT_VOID;
|
||||
cell->wid = 0;
|
||||
cell->signed_flag = false;
|
||||
cell->override_flag = false;
|
||||
append_to_list(cell);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -223,6 +244,7 @@ int load_sys_func_table(const char*path)
|
|||
cell->type = IVL_VT_STRING;
|
||||
cell->wid = 0; // string is a dynamic length type
|
||||
cell->signed_flag = false;
|
||||
cell->override_flag = false;
|
||||
append_to_list(cell);
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue