diff --git a/PExpr.cc b/PExpr.cc index b358542b5..af9a1999c 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2016 Stephen Williams + * Copyright (c) 1998-2019 Stephen Williams * 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 &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 &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 &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 } PECallFunction::PECallFunction(perm_string n, const vector&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 &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 &parms) } PECallFunction::PECallFunction(perm_string n, const list&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()); diff --git a/PExpr.h b/PExpr.h index fd91dc6a8..369464f9a 100644 --- a/PExpr.h +++ b/PExpr.h @@ -928,6 +928,9 @@ class PECallFunction : public PExpr { pform_name_t path_; std::vector parms_; + // For system functions. + bool is_overridden_; + bool check_call_matches_definition_(Design*des, NetScope*dscope) const; diff --git a/compiler.h b/compiler.h index fd50cd52f..593955e65 100644 --- a/compiler.h +++ b/compiler.h @@ -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); diff --git a/dup_expr.cc b/dup_expr.cc index c1ec0ce0d..c1c2246db 100644 --- a/dup_expr.cc +++ b/dup_expr.cc @@ -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()); diff --git a/elab_expr.cc b/elab_expr.cc index fbfcea532..630a037c4 100644 --- a/elab_expr.cc +++ b/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(parms_[0]))) { if (strcmp(name, "$dimensions") == 0) need_const = false; diff --git a/eval_tree.cc b/eval_tree.cc index 372a382cc..2e2fac3f1 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -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_(); diff --git a/net_expr.cc b/net_expr.cc index fa9e6fe2c..ecbcd96e3 100644 --- a/net_expr.cc +++ b/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()); diff --git a/netlist.h b/netlist.h index 37ed539b7..82163a1d8 100644 --- a/netlist.h +++ b/netlist.h @@ -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::vectorparms_; + bool is_overridden_; ID built_in_id_() const; diff --git a/sys_funcs.cc b/sys_funcs.cc index 41aaa2adb..a39585c70 100644 --- a/sys_funcs.cc +++ b/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; }