Merge pull request #992 from larsclausen/tf-named-ports

Add support for binding function/task arguments by name
This commit is contained in:
Cary R 2023-08-20 20:39:51 -07:00 committed by GitHub
commit e1f5dbcf17
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
106 changed files with 1636 additions and 541 deletions

View File

@ -114,7 +114,8 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \
net_event.o net_expr.o net_func.o \
net_func_eval.o net_link.o net_modulo.o \
net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_tran.o \
net_udp.o pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \
net_udp.o map_named_args.o \
pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \
pform_disciplines.o pform_dump.o pform_package.o pform_pclass.o \
pform_types.o \
symbol_search.o sync.o sys_funcs.o verinum.o verireal.o vpi_modules.o target.o \

View File

@ -99,14 +99,8 @@ PEAssignPattern::PEAssignPattern()
}
PEAssignPattern::PEAssignPattern(const list<PExpr*>&p)
: parms_(p.size())
: parms_(p.begin(), p.end())
{
size_t idx = 0;
for (list<PExpr*>::const_iterator cur = p.begin()
; cur != p.end() ; ++cur) {
parms_[idx] = *cur;
idx += 1;
}
}
PEAssignPattern::~PEAssignPattern()
@ -221,12 +215,12 @@ PEBShift::~PEBShift()
{
}
PECallFunction::PECallFunction(const pform_name_t&n, const vector<PExpr *> &parms)
PECallFunction::PECallFunction(const pform_name_t &n, const vector<named_pexpr_t> &parms)
: path_(n), parms_(parms), is_overridden_(false)
{
}
PECallFunction::PECallFunction(PPackage*pkg, const pform_name_t&n, const vector<PExpr *> &parms)
PECallFunction::PECallFunction(PPackage *pkg, const pform_name_t &n, const vector<named_pexpr_t> &parms)
: path_(pkg, n), parms_(parms), is_overridden_(false)
{
}
@ -239,17 +233,12 @@ static pform_name_t pn_from_ps(perm_string n)
return tmp;
}
PECallFunction::PECallFunction(PPackage*pkg, const pform_name_t &n, const list<PExpr *> &parms)
: path_(pkg, n), parms_(parms.size()), is_overridden_(false)
PECallFunction::PECallFunction(PPackage *pkg, const pform_name_t &n, const list<named_pexpr_t> &parms)
: path_(pkg, n), parms_(parms.begin(), parms.end()), is_overridden_(false)
{
int tmp_idx = 0;
ivl_assert(*this, parms_.size() == parms.size());
for (list<PExpr*>::const_iterator idx = parms.begin()
; idx != parms.end() ; ++idx)
parms_[tmp_idx++] = *idx;
}
PECallFunction::PECallFunction(perm_string n, const vector<PExpr*>&parms)
PECallFunction::PECallFunction(perm_string n, const vector<named_pexpr_t> &parms)
: path_(pn_from_ps(n)), parms_(parms), is_overridden_(false)
{
}
@ -260,24 +249,14 @@ PECallFunction::PECallFunction(perm_string n)
}
// NOTE: Anachronism. Try to work all use of svector out.
PECallFunction::PECallFunction(const pform_name_t&n, const list<PExpr *> &parms)
: path_(n), parms_(parms.size()), is_overridden_(false)
PECallFunction::PECallFunction(const pform_name_t &n, const list<named_pexpr_t> &parms)
: path_(n), parms_(parms.begin(), parms.end()), is_overridden_(false)
{
int tmp_idx = 0;
ivl_assert(*this, parms_.size() == parms.size());
for (list<PExpr*>::const_iterator idx = parms.begin()
; idx != parms.end() ; ++idx)
parms_[tmp_idx++] = *idx;
}
PECallFunction::PECallFunction(perm_string n, const list<PExpr*>&parms)
: path_(pn_from_ps(n)), parms_(parms.size()), is_overridden_(false)
PECallFunction::PECallFunction(perm_string n, const list<named_pexpr_t> &parms)
: path_(pn_from_ps(n)), parms_(parms.begin(), parms.end()), is_overridden_(false)
{
int tmp_idx = 0;
ivl_assert(*this, parms_.size() == parms.size());
for (list<PExpr*>::const_iterator idx = parms.begin()
; idx != parms.end() ; ++idx)
parms_[tmp_idx++] = *idx;
}
PECallFunction::~PECallFunction()
@ -286,31 +265,25 @@ PECallFunction::~PECallFunction()
void PECallFunction::declare_implicit_nets(LexicalScope*scope, NetNet::Type type)
{
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
if (parms_[idx])
parms_[idx]->declare_implicit_nets(scope, type);
for (const auto &parm : parms_) {
if (parm.parm)
parm.parm->declare_implicit_nets(scope, type);
}
}
bool PECallFunction::has_aa_term(Design*des, NetScope*scope) const
{
bool flag = false;
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
if (parms_[idx])
flag |= parms_[idx]->has_aa_term(des, scope);
for (const auto &parm : parms_) {
if (parm.parm)
flag |= parm.parm->has_aa_term(des, scope);
}
return flag;
}
PEConcat::PEConcat(const list<PExpr*>&p, PExpr*r)
: parms_(p.size()), width_modes_(SIZED, p.size()), repeat_(r)
: parms_(p.begin(), p.end()), width_modes_(SIZED, p.size()), repeat_(r)
{
int tmp_idx = 0;
ivl_assert(*this, parms_.size() == p.size());
for (list<PExpr*>::const_iterator idx = p.begin()
; idx != p.end() ; ++idx)
parms_[tmp_idx++] = *idx;
tested_scope_ = 0;
repeat_count_ = 1;
}
@ -493,14 +466,9 @@ PENewClass::PENewClass(void)
{
}
PENewClass::PENewClass(const list<PExpr*>&p, data_type_t *class_type)
: parms_(p.size()), class_type_(class_type)
PENewClass::PENewClass(const list<named_pexpr_t> &p, data_type_t *class_type)
: parms_(p.begin(), p.end()), class_type_(class_type)
{
size_t tmp_idx = 0;
for (list<PExpr*>::const_iterator cur = p.begin()
; cur != p.end() ; ++ cur) {
parms_[tmp_idx++] = *cur;
}
}
PENewClass::~PENewClass()

18
PExpr.h
View File

@ -570,7 +570,7 @@ class PENewClass : public PExpr {
// New without (or with default) constructor
explicit PENewClass ();
// New with constructor arguments
explicit PENewClass (const std::list<PExpr*>&p,
explicit PENewClass (const std::list<named_pexpr_t> &p,
data_type_t *class_type = nullptr);
~PENewClass();
@ -592,7 +592,7 @@ class PENewClass : public PExpr {
NetExpr*obj, unsigned flags) const;
private:
std::vector<PExpr*>parms_;
std::vector<named_pexpr_t> parms_;
data_type_t *class_type_;
};
@ -895,20 +895,20 @@ class PETernary : public PExpr {
*/
class PECallFunction : public PExpr {
public:
explicit PECallFunction(const pform_name_t&n, const std::vector<PExpr *> &parms);
explicit PECallFunction(const pform_name_t &n, const std::vector<named_pexpr_t> &parms);
// Call function defined in package.
explicit PECallFunction(PPackage*pkg, const pform_name_t&n, const std::list<PExpr *> &parms);
explicit PECallFunction(PPackage *pkg, const pform_name_t &n, const std::list<named_pexpr_t> &parms);
// Used to convert a user function called as a task
explicit PECallFunction(PPackage*pkg, const pform_name_t&n, const std::vector<PExpr *> &parms);
explicit PECallFunction(PPackage *pkg, const pform_name_t &n, const std::vector<named_pexpr_t> &parms);
// Call of system function (name is not hierarchical)
explicit PECallFunction(perm_string n, const std::vector<PExpr *> &parms);
explicit PECallFunction(perm_string n, const std::vector<named_pexpr_t> &parms);
explicit PECallFunction(perm_string n);
// std::list versions. Should be removed!
explicit PECallFunction(const pform_name_t&n, const std::list<PExpr *> &parms);
explicit PECallFunction(perm_string n, const std::list<PExpr *> &parms);
explicit PECallFunction(const pform_name_t &n, const std::list<named_pexpr_t> &parms);
explicit PECallFunction(perm_string n, const std::list<named_pexpr_t> &parms);
~PECallFunction();
@ -929,7 +929,7 @@ class PECallFunction : public PExpr {
private:
pform_scoped_name_t path_;
std::vector<PExpr *> parms_;
std::vector<named_pexpr_t> parms_;
// For system functions.
bool is_overridden_;

View File

@ -270,7 +270,7 @@ PGModule::PGModule(perm_string type, perm_string name, list<PExpr*>*pins)
}
PGModule::PGModule(perm_string type, perm_string name,
named<PExpr*>*pins, unsigned npins)
named_pexpr_t *pins, unsigned npins)
: PGate(name, 0), bound_type_(0), type_(type), overrides_(0), pins_(pins),
npins_(npins), parms_(0), nparms_(0)
{
@ -292,7 +292,7 @@ void PGModule::set_parameters(list<PExpr*>*o)
overrides_ = o;
}
void PGModule::set_parameters(named<PExpr*>*pa, unsigned npa)
void PGModule::set_parameters(named_pexpr_t *pa, unsigned npa)
{
ivl_assert(*this, parms_ == 0);
ivl_assert(*this, overrides_ == 0);

View File

@ -204,7 +204,7 @@ class PGModule : public PGate {
// If the binding of ports is by name, this constructor takes
// the bindings and stores them for later elaboration.
explicit PGModule(perm_string type, perm_string name,
named<PExpr*>*pins, unsigned npins);
named_pexpr_t *pins, unsigned npins);
// If the module type is known by design, then use this
// constructor.
@ -215,7 +215,7 @@ class PGModule : public PGate {
// Parameter overrides can come as an ordered list, or a set
// of named expressions.
void set_parameters(std::list<PExpr*>*o);
void set_parameters(named<PExpr*>*pa, unsigned npa);
void set_parameters(named_pexpr_t *pa, unsigned npa);
std::map<perm_string,PExpr*> attributes;
@ -232,11 +232,11 @@ class PGModule : public PGate {
Module*bound_type_;
perm_string type_;
std::list<PExpr*>*overrides_;
named<PExpr*>*pins_;
named_pexpr_t *pins_;
unsigned npins_;
// These members support parameter override by name
named<PExpr*>*parms_;
named_pexpr_t *parms_;
unsigned nparms_;
friend class delayed_elaborate_scope_mod_instances;

View File

@ -19,10 +19,11 @@
# include "PSpec.h"
PSpecPath::PSpecPath(unsigned src_cnt, unsigned dst_cnt, char polarity,
bool full_flag)
PSpecPath::PSpecPath(const std::list<perm_string> &src_list,
const std::list<perm_string> &dst_list,
char polarity, bool full_flag)
: conditional(false), condition(0), edge(0),
src(src_cnt), dst(dst_cnt),
src(src_list.begin(), src_list.end()), dst(dst_list.begin(), dst_list.end()),
data_source_expression(0)
{
full_flag_ = full_flag;

View File

@ -22,6 +22,7 @@
# include "LineInfo.h"
# include "StringHeap.h"
# include <vector>
# include <list>
class PExpr;
@ -56,8 +57,9 @@ class PExpr;
class PSpecPath : public LineInfo {
public:
PSpecPath(unsigned src_cnt, unsigned dst_cnt, char polarity,
bool full_flag);
PSpecPath(const std::list<perm_string> &src_list,
const std::list<perm_string> &dst_list,
char polarity, bool full_flag);
~PSpecPath();
void elaborate(class Design*des, class NetScope*scope) const;

View File

@ -63,7 +63,8 @@ class PTaskFunc : public PScope, public PNamedItem {
// default value expressions, if any.
void elaborate_sig_ports_(Design*des, NetScope*scope,
std::vector<NetNet*>&ports,
std::vector<NetExpr*>&pdefs) const;
std::vector<NetExpr*> &pdefs,
std::vector<perm_string> &port_names) const;
void dump_ports_(std::ostream&out, unsigned ind) const;

View File

@ -166,37 +166,19 @@ PNamedItem::SymbolType PBlock::symbol_type() const
return BLOCK;
}
PCallTask::PCallTask(const pform_name_t&n, const list<PExpr*>&p)
: package_(0), path_(n), parms_(p.size())
PCallTask::PCallTask(const pform_name_t &n, const list<named_pexpr_t> &p)
: package_(0), path_(n), parms_(p.begin(), p.end())
{
list<PExpr*>::const_iterator cur = p.begin();
for (size_t idx = 0 ; idx < parms_.size() ; idx += 1) {
parms_[idx] = *cur;
++cur;
}
ivl_assert(*this, cur == p.end());
}
PCallTask::PCallTask(PPackage*pkg, const pform_name_t&n, const list<PExpr*>&p)
: package_(pkg), path_(n), parms_(p.size())
PCallTask::PCallTask(PPackage *pkg, const pform_name_t &n, const list<named_pexpr_t> &p)
: package_(pkg), path_(n), parms_(p.begin(), p.end())
{
list<PExpr*>::const_iterator cur = p.begin();
for (size_t idx = 0 ; idx < parms_.size() ; idx += 1) {
parms_[idx] = *cur;
++cur;
}
ivl_assert(*this, cur == p.end());
}
PCallTask::PCallTask(perm_string n, const list<PExpr*>&p)
: package_(0), parms_(p.size())
PCallTask::PCallTask(perm_string n, const list<named_pexpr_t> &p)
: package_(0), parms_(p.begin(), p.end())
{
list<PExpr*>::const_iterator cur = p.begin();
for (size_t idx = 0 ; idx < parms_.size() ; idx += 1) {
parms_[idx] = *cur;
++cur;
}
ivl_assert(*this, cur == p.end());
path_.push_back(name_component_t(n));
}
@ -234,15 +216,14 @@ PCAssign::~PCAssign()
delete expr_;
}
PChainConstructor::PChainConstructor(const list<PExpr*>&parms)
: parms_(parms.size())
PChainConstructor::PChainConstructor(const list<named_pexpr_t> &parms)
: parms_(parms.begin(), parms.end())
{
}
PChainConstructor::PChainConstructor(const vector<named_pexpr_t> &parms)
: parms_(parms)
{
list<PExpr*>::const_iterator cur = parms.begin();
for (size_t idx = 0 ; idx < parms_.size() ; idx += 1) {
parms_[idx] = *cur;
++cur;
}
ivl_assert(*this, cur == parms.end());
}
PChainConstructor::~PChainConstructor()
@ -350,12 +331,8 @@ PForce::~PForce()
}
PForeach::PForeach(perm_string av, const list<perm_string>&ix, Statement*s)
: array_var_(av), index_vars_(ix.size()), statement_(s)
: array_var_(av), index_vars_(ix.begin(), ix.end()), statement_(s)
{
size_t idx = 0;
for (list<perm_string>::const_iterator cur = ix.begin()
; cur != ix.end() ; ++cur)
index_vars_[idx++] = *cur;
}
PForeach::~PForeach()

View File

@ -223,9 +223,9 @@ class PBreak : public Statement {
class PCallTask : public Statement {
public:
explicit PCallTask(PPackage*pkg, const pform_name_t&n, const std::list<PExpr*>&parms);
explicit PCallTask(const pform_name_t&n, const std::list<PExpr*>&parms);
explicit PCallTask(perm_string n, const std::list<PExpr*>&parms);
explicit PCallTask(PPackage *pkg, const pform_name_t &n, const std::list<named_pexpr_t> &parms);
explicit PCallTask(const pform_name_t &n, const std::list<named_pexpr_t> &parms);
explicit PCallTask(perm_string n, const std::list<named_pexpr_t> &parms);
~PCallTask();
const pform_name_t& path() const;
@ -253,11 +253,13 @@ class PCallTask : public Statement {
NetProc*elaborate_sys_task_method_(Design*des, NetScope*scope,
NetNet*net,
perm_string method_name,
const char*sys_task_name) const;
const char *sys_task_name,
const std::vector<perm_string> &parm_names = {}) const;
NetProc*elaborate_queue_method_(Design*des, NetScope*scope,
NetNet*net,
perm_string method_name,
const char*sys_task_name) const;
const char *sys_task_name,
const std::vector<perm_string> &parm_names) const;
NetProc*elaborate_method_func_(NetScope*scope,
NetNet*net,
ivl_type_t type,
@ -267,7 +269,7 @@ class PCallTask : public Statement {
PPackage*package_;
pform_name_t path_;
std::vector<PExpr*> parms_;
std::vector<named_pexpr_t> parms_;
bool void_cast_ = false;
};
@ -320,17 +322,18 @@ class PCAssign : public Statement {
*/
class PChainConstructor : public Statement {
public:
explicit PChainConstructor(const std::list<PExpr*>&parms);
explicit PChainConstructor(const std::list<named_pexpr_t> &parms);
explicit PChainConstructor(const std::vector<named_pexpr_t> &parms);
~PChainConstructor();
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
virtual void dump(std::ostream&out, unsigned ind) const;
inline const std::vector<PExpr*>& chain_args(void) const
inline const std::vector<named_pexpr_t>& chain_args(void) const
{ return parms_; }
private:
std::vector<PExpr*> parms_;
std::vector<named_pexpr_t> parms_;
};
class PCondit : public Statement {

View File

@ -206,6 +206,18 @@ ostream& operator << (ostream&fd, NetCaseCmp::kind_t that)
return fd;
}
static std::ostream& operator << (std::ostream &out, const std::vector<NetExpr*> &exprs)
{
for (size_t idx = 0; idx < exprs.size(); idx++) {
if (idx != 0)
out << ", ";
if (exprs[idx])
out << *exprs[idx];
}
return out;
}
ostream& ivl_type_s::debug_dump(ostream&o) const
{
o << typeid(*this).name();
@ -1650,17 +1662,7 @@ void NetSTask::dump(ostream&o, unsigned ind) const
o << setw(ind) << "" << name_;
if (! parms_.empty()) {
o << "(";
if (parms_[0])
parms_[0]->dump(o);
for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) {
o << ", ";
if (parms_[idx])
parms_[idx]->dump(o);
}
o << ")";
o << "(" << parms_ << ")";
}
o << ";" << endl;
}
@ -1702,15 +1704,7 @@ void NetEAccess::dump(ostream&o) const
void NetEArrayPattern::dump(ostream&fd) const
{
fd << "'{";
if (items_.size() >= 1) {
if (items_[0]) fd << *items_[0];
}
for (size_t idx = 1 ; idx < items_.size() ; idx += 1) {
fd << ", ";
if (items_[idx]) fd << *items_[idx];
}
fd << "}";
fd << "'{" << items_ << "}";
}
void NetEBinary::dump(ostream&o) const
@ -1814,18 +1808,7 @@ void NetEConcat::dump(ostream&o) const
if (repeat_ != 1)
o << repeat_;
if (parms_[0])
o << "{" << *parms_[0];
else
o << "{";
for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) {
if (parms_[idx])
o << ", " << *parms_[idx];
else
o << ", ";
}
o << "}";
o << "{" << parms_ << "}";
}
void NetEConst::dump(ostream&o) const
@ -1965,15 +1948,7 @@ void NetETernary::dump(ostream&o) const
void NetEUFunc::dump(ostream&o) const
{
o << scope_path(func_) << "(";
if (! parms_.empty()) {
parms_[0]->dump(o);
for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) {
o << ", ";
parms_[idx]->dump(o);
}
}
o << ")";
o << scope_path(func_) << "(" << parms_ << ")";
}
void NetEUnary::dump(ostream&o) const

View File

@ -40,6 +40,7 @@
# include "netscalar.h"
# include "util.h"
# include "ivl_assert.h"
# include "map_named_args.h"
using namespace std;
@ -1374,7 +1375,7 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
// The Icarus Verilog specific $ivlh_to_unsigned() system
// task takes a second argument which is the output
// size. This can be an arbitrary constant function.
PExpr*pexpr = parms_[1];
PExpr *pexpr = parms_[1].parm;
if (pexpr == 0) {
cerr << get_fileline() << ": error: "
<< "Missing $ivlh_to_unsigned width." << endl;
@ -1396,7 +1397,7 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
// The argument width is self-determined and doesn't
// affect the result width.
width_mode_t arg_mode = SIZED;
parms_[0]->test_width(des, scope, arg_mode);
parms_[0].parm->test_width(des, scope, arg_mode);
expr_type_ = pexpr->expr_type();
expr_width_ = value;
@ -1406,7 +1407,7 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
}
if (name=="$signed" || name=="$unsigned") {
PExpr*expr = parms_[0];
PExpr *expr = parms_[0].parm;
if (expr == 0)
return 0;
@ -1423,7 +1424,7 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
}
if (name=="$sizeof" || name=="$bits") {
PExpr*expr = parms_[0];
PExpr *expr = parms_[0].parm;
if (expr == 0)
return 0;
@ -1450,7 +1451,7 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
}
if (name=="$is_signed") {
PExpr*expr = parms_[0];
PExpr *expr = parms_[0].parm;
if (expr == 0)
return 0;
@ -1887,6 +1888,17 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
{
perm_string name = peek_tail_name(path_);
// System functions don't have named parameters
for (const auto &parm : parms_) {
if (!parm.name.nil()) {
des->errors++;
cerr << parm.get_fileline() << ": error: "
<< "The system function `" << name
<< "` has no argument called `" << parm.name << "`."
<< endl;
}
}
/* Catch the special case that the system function is the
$ivl_unsigned function. In this case the second argument is
the size of the expression, but should already be accounted
@ -1894,7 +1906,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
if (name=="$ivlh_to_unsigned") {
ivl_assert(*this, parms_.size()==2);
PExpr*expr = parms_[0];
PExpr *expr = parms_[0].parm;
ivl_assert(*this, expr);
NetExpr*sub = expr->elaborate_expr(des, scope, expr->expr_width(), flags);
return cast_to_width_(sub, expr_wid);
@ -1904,7 +1916,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
function. Its argument will be evaluated as a self-determined
expression. */
if (name=="$signed" || name=="$unsigned") {
if ((parms_.size() != 1) || (parms_[0] == 0)) {
if ((parms_.size() != 1) || !parms_[0].parm) {
cerr << get_fileline() << ": error: The " << name
<< " function takes exactly one(1) argument." << endl;
des->errors += 1;
@ -1922,7 +1934,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
cerr << get_fileline() << ": PECallFunction::elaborate_sfunc_: "
<< name << " expression is the argument cast to expr_wid=" << expr_wid << endl;
}
PExpr*expr = parms_[0];
PExpr *expr = parms_[0].parm;
NetExpr*sub = expr->elaborate_expr(des, scope, expr_width_, flags);
return cast_to_width_(sub, expr_wid);
@ -1933,7 +1945,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
sub-expression is not used, so the expression itself can be
deleted. */
if (name=="$sizeof" || name=="$bits") {
if ((parms_.size() != 1) || (parms_[0] == 0)) {
if ((parms_.size() != 1) || !parms_[0].parm) {
cerr << get_fileline() << ": error: The " << name
<< " function takes exactly one(1) argument." << endl;
des->errors += 1;
@ -1944,7 +1956,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
cerr << get_fileline() << ": warning: $sizeof is deprecated."
<< " Use $bits() instead." << endl;
PExpr*expr = parms_[0];
PExpr *expr = parms_[0].parm;
uint64_t use_width = 0;
if (PETypename*type_expr = dynamic_cast<PETypename*>(expr)) {
@ -1991,14 +2003,14 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
a single bit flag -- 1 if the expression is signed, 0
otherwise. */
if (name=="$is_signed") {
if ((parms_.size() != 1) || (parms_[0] == 0)) {
if ((parms_.size() != 1) || !parms_[0].parm) {
cerr << get_fileline() << ": error: The " << name
<< " function takes exactly one(1) argument." << endl;
des->errors += 1;
return 0;
}
PExpr*expr = parms_[0];
PExpr *expr = parms_[0].parm;
verinum val (expr->has_sign() ? verinum::V1 : verinum::V0, 1);
NetEConst*sub = new NetEConst(val);
@ -2039,7 +2051,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
expression if one is created. */
/* These functions can work in a constant context with a signal expression. */
if ((nparms == 1) && (dynamic_cast<PEIdent*>(parms_[0]))) {
if ((nparms == 1) && (dynamic_cast<PEIdent*>(parms_[0].parm))) {
if (strcmp(name, "$dimensions") == 0) need_const = false;
else if (strcmp(name, "$high") == 0) need_const = false;
else if (strcmp(name, "$increment") == 0) need_const = false;
@ -2053,7 +2065,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
unsigned parm_errors = 0;
unsigned missing_parms = 0;
for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
PExpr*expr = parms_[idx];
PExpr *expr = parms_[idx].parm;
if (expr) {
NetExpr*tmp = elab_sys_task_arg(des, scope, name, idx,
expr, need_const);
@ -2092,7 +2104,7 @@ NetExpr* PECallFunction::elaborate_access_func_(Design*des, NetScope*scope,
NetBranch*branch = 0;
if (parms_.size() == 1) {
PExpr*arg1 = parms_[0];
PExpr *arg1 = parms_[0].parm;
PEIdent*arg_ident = dynamic_cast<PEIdent*> (arg1);
ivl_assert(*this, arg_ident);
@ -2147,7 +2159,7 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
const pform_scoped_name_t&use_path,
perm_string method_name,
NetExpr*expr,
PExpr*parg, unsigned args)
const std::vector<named_pexpr_t> &parms)
{
if (debug_elaborate) {
cerr << li->get_fileline() << ": " << __func__ << ": "
@ -2168,9 +2180,9 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
// The "num()" method returns the number of elements. This is
// actually a static constant, and can be replaced at compile time
// with a constant value.
if (args != 0) {
if (parms.size() != 0) {
cerr << li->get_fileline() << ": error: enumeration "
"method " << use_path << ".num() does not "
"method " << use_path << " does not "
"take an argument." << endl;
des->errors += 1;
}
@ -2184,9 +2196,9 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
// The "first()" method returns the first enumeration value. This
// doesn't actually care about the constant value, and instead
// returns as a constant literal the first value of the enumeration.
if (args != 0) {
if (parms.size() != 0) {
cerr << li->get_fileline() << ": error: enumeration "
"method " << use_path << ".first() does not "
"method " << use_path << " does not "
"take an argument." << endl;
des->errors += 1;
}
@ -2201,9 +2213,9 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
// The "last()" method returns the first enumeration value. This
// doesn't actually care about the constant value, and instead
// returns as a constant literal the last value of the enumeration.
if (args != 0) {
if (parms.size() != 0) {
cerr << li->get_fileline() << ": error: enumeration "
"method " << use_path << ".last() does not "
"method " << use_path << " does not "
"take an argument." << endl;
des->errors += 1;
}
@ -2216,34 +2228,14 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
NetESFunc*sys_expr;
// Process the method argument if it is available.
NetExpr* count = 0;
if (args != 0 && parg) {
count = elaborate_rval_expr(des, scope, &netvector_t::atom2u32,
parg);
if (count == 0) {
cerr << li->get_fileline() << ": error: unable to elaborate "
"enumeration method argument " << use_path << "."
<< method_name << "(" << parg << ")." << endl;
args = 0;
des->errors += 1;
} else if (NetEEvent*evt = dynamic_cast<NetEEvent*> (count)) {
cerr << evt->get_fileline() << ": error: An event '"
<< evt->event()->name() << "' cannot be an enumeration "
"method argument." << endl;
args = 0;
des->errors += 1;
}
}
if (method_name == "name") {
// The "name()" method returns the name of the current enumeration
// value. The generated system task takes the enumeration
// definition and the enumeration value. The return value is the
// string name of the enumeration.
if (args != 0) {
if (parms.size() != 0) {
cerr << li->get_fileline() << ": error: enumeration "
"method " << use_path << ".name() does not "
"method " << use_path << " does not "
"take an argument." << endl;
des->errors += 1;
}
@ -2257,37 +2249,51 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
sys_expr->parm(0, def);
sys_expr->parm(1, expr);
} else if (method_name == "next") {
// The "next()" method returns the next enumeration value.
if (args > 1) {
cerr << li->get_fileline() << ": error: enumeration "
"method " << use_path << ".next() take at "
"most one argument." << endl;
des->errors += 1;
}
sys_expr = new NetESFunc("$ivl_enum_method$next", netenum,
2 + (args != 0));
NetENetenum* def = new NetENetenum(netenum);
def->set_line(*li);
sys_expr->parm(0, def);
sys_expr->parm(1, expr);
if (args != 0) sys_expr->parm(2, count);
} else if (method_name == "next" || method_name == "prev") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("N"),
};
auto args = map_named_args(des, parm_names, parms);
} else if (method_name == "prev") {
// The "prev()" method returns the previous enumeration value.
if (args > 1) {
// Process the method argument if it is available.
NetExpr *count = nullptr;
if (args.size() != 0 && args[0]) {
count = elaborate_rval_expr(des, scope, &netvector_t::atom2u32,
args[0]);
if (!count) {
cerr << li->get_fileline() << ": error: unable to elaborate "
"enumeration method argument " << use_path << "."
<< method_name << "(" << args[0] << ")." << endl;
des->errors++;
} else if (NetEEvent *evt = dynamic_cast<NetEEvent*> (count)) {
cerr << evt->get_fileline() << ": error: An event '"
<< evt->event()->name() << "' cannot be an enumeration "
"method argument." << endl;
des->errors++;
}
}
// The "next()" and "prev()" methods returns the next or previous enumeration value.
if (args.size() > 1) {
cerr << li->get_fileline() << ": error: enumeration "
"method " << use_path << ".prev() take at "
"method " << use_path << " takes at "
"most one argument." << endl;
des->errors += 1;
}
sys_expr = new NetESFunc("$ivl_enum_method$prev", netenum,
2 + (args != 0));
const char *func_name;
if (method_name == "next")
func_name = "$ivl_enum_method$next";
else
func_name = "$ivl_enum_method$prev";
sys_expr = new NetESFunc(func_name, netenum,
2 + (count != nullptr));
NetENetenum* def = new NetENetenum(netenum);
def->set_line(*li);
sys_expr->parm(0, def);
sys_expr->parm(1, expr);
if (args != 0) sys_expr->parm(2, count);
if (count) sys_expr->parm(2, count);
} else {
// This is an unknown enumeration method.
@ -3119,9 +3125,12 @@ unsigned PECallFunction::elaborate_arguments_(Design*des, NetScope*scope,
des->errors += 1;
}
auto args = map_named_args(des, def, parms_, parm_off);
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
unsigned pidx = idx + parm_off;
PExpr*tmp = (idx < actual_count) ? parms_[idx] : NULL;
PExpr *tmp = args[idx];
if (tmp) {
parms[pidx] = elaborate_rval_expr(des, scope,
def->port(pidx)->net_type(),
@ -3354,12 +3363,10 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
// Get the method name that we are looking for.
perm_string method_name = search_results.path_tail.back().name;
PExpr*tmp = parms_.size() ? parms_[0] : NULL;
return check_for_enum_methods(this, des, scope,
netenum, path_,
method_name, sub_expr,
tmp, parms_.size());
parms_);
}
// Class methods. Generate function call to the class method.
@ -3437,6 +3444,17 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
}
if (method_name == "substr") {
if (parms_.size() != 2)
cerr << get_fileline() << ": error: Method `substr()`"
<< " requires 2 arguments, got " << parms_.size()
<< "." << endl;
static const std::vector<perm_string> parm_names = {
perm_string::literal("i"),
perm_string::literal("j")
};
auto args = map_named_args(des, parm_names, parms_);
NetESFunc*sys_expr = new NetESFunc("$ivl_string_method$substr",
&netstring_t::type_string, 3);
sys_expr->set_line(*this);
@ -3444,16 +3462,15 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
// First argument is the source string.
sys_expr->parm(0, sub_expr);
ivl_assert(*this, parms_.size() == 2);
NetExpr*tmp;
for (int i = 0; i < 2; i++) {
if (!args[i])
continue;
tmp = elaborate_rval_expr(des, scope, &netvector_t::atom2u32,
parms_[0], false);
sys_expr->parm(1, tmp);
tmp = elaborate_rval_expr(des, scope, &netvector_t::atom2u32,
parms_[1], false);
sys_expr->parm(2, tmp);
auto expr = elaborate_rval_expr(des, scope,
&netvector_t::atom2u32,
args[i], false);
sys_expr->parm(i + 1, expr);
}
return sys_expr;
}
@ -4943,7 +4960,7 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope,
return check_for_enum_methods(this, des, scope,
netenum, sr.path_head,
member_comp.name,
expr, NULL, 0);
expr, {});
}
ivl_assert(*this, sr.path_tail.empty());
@ -6661,8 +6678,8 @@ NetExpr* PENewClass::elaborate_expr_constructor_(Design*des, NetScope*scope,
// generate an error message. The case of too few arguments
// will be handled below, when we run out of arguments.
if ((parms_.size()+1) > def->port_count()) {
cerr << get_fileline() << ": error: Parm count mismatch"
<< " passing " << parms_.size() << " arguments "
cerr << get_fileline() << ": error: Argument count mismatch."
<< " Passing " << parms_.size() << " arguments"
<< " to constructor expecting " << (def->port_count()-1)
<< " arguments." << endl;
des->errors += 1;
@ -6671,14 +6688,15 @@ NetExpr* PENewClass::elaborate_expr_constructor_(Design*des, NetScope*scope,
vector<NetExpr*> parms (def->port_count());
parms[0] = obj;
auto args = map_named_args(des, def, parms_, 1);
int missing_parms = 0;
for (size_t idx = 1 ; idx < parms.size() ; idx += 1) {
// While there are default arguments, check them.
if (idx <= parms_.size() && parms_[idx-1]) {
PExpr*tmp = parms_[idx-1];
if (args[idx - 1]) {
parms[idx] = elaborate_rval_expr(des, scope,
def->port(idx)->net_type(),
tmp, false);
args[idx - 1], false);
// NOTE: if elaborate_rval_expr fails, it will return a
// nullptr, but it will also increment des->errors so there
// is nothing we need to do here.

View File

@ -688,7 +688,8 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
vector<NetNet*>ports;
vector<NetExpr*>pdef;
elaborate_sig_ports_(des, scope, ports, pdef);
vector<perm_string> port_names;
elaborate_sig_ports_(des, scope, ports, pdef, port_names);
NetFuncDef*def = new NetFuncDef(scope, ret_sig, ports, pdef);
@ -722,7 +723,8 @@ void PTask::elaborate_sig(Design*des, NetScope*scope) const
vector<NetNet*>ports;
vector<NetExpr*>pdefs;
elaborate_sig_ports_(des, scope, ports, pdefs);
vector<perm_string> port_names;
elaborate_sig_ports_(des, scope, ports, pdefs, port_names);
NetTaskDef*def = new NetTaskDef(scope, ports, pdefs);
scope->set_task_def(def);
@ -732,11 +734,14 @@ void PTask::elaborate_sig(Design*des, NetScope*scope) const
}
void PTaskFunc::elaborate_sig_ports_(Design*des, NetScope*scope,
vector<NetNet*>&ports, vector<NetExpr*>&pdefs) const
vector<NetNet*> &ports,
vector<NetExpr*> &pdefs,
vector<perm_string> &port_names) const
{
if (ports_ == 0) {
ports.clear();
pdefs.clear();
port_names.clear();
/* Make sure the function has at least one input
port. If it fails this test, print an error
@ -755,6 +760,7 @@ void PTaskFunc::elaborate_sig_ports_(Design*des, NetScope*scope,
ports.resize(ports_->size());
pdefs.resize(ports_->size());
port_names.resize(ports_->size());
for (size_t idx = 0 ; idx < ports_->size() ; idx += 1) {
@ -817,6 +823,7 @@ void PTaskFunc::elaborate_sig_ports_(Design*des, NetScope*scope,
}
ports[idx] = tmp;
port_names[idx] = port_name;
pdefs[idx] = tmp_def;
if (scope->type()==NetScope::FUNC && tmp->port_type()!=NetNet::PINPUT) {
cerr << tmp->get_fileline() << ": error: "

View File

@ -54,6 +54,7 @@
# include "parse_api.h"
# include "compiler.h"
# include "ivl_assert.h"
# include "map_named_args.h"
using namespace std;
@ -3301,12 +3302,12 @@ NetProc* PChainConstructor::elaborate(Design*des, NetScope*scope) const
vector<NetExpr*> parms (def->port_count());
parms[0] = eres;
auto args = map_named_args(des, def, parms_, 1);
for (size_t idx = 1 ; idx < parms.size() ; idx += 1) {
if (idx <= parms_.size() && parms_[idx-1]) {
PExpr*tmp = parms_[idx-1];
if (args[idx - 1]) {
parms[idx] = elaborate_rval_expr(des, scope,
def->port(idx)->net_type(),
tmp, false);
args[idx - 1], false);
continue;
}
@ -3480,12 +3481,19 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
perm_string name = peek_tail_name(path_);
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
PExpr*ex = parms_[idx];
if (ex != 0) {
eparms[idx] = elab_sys_task_arg(des, scope, name, idx, ex);
} else {
eparms[idx] = 0;
auto &parm = parms_[idx];
// System functions don't have named parameters
if (!parm.name.nil()) {
cerr << parm.get_fileline() << ": error: "
<< "The system task `" << name
<< "` has no argument called `" << parm.name
<< "`." << endl;
des->errors++;
}
eparms[idx] = elab_sys_task_arg(des, scope, name, idx,
parm.parm);
}
// Special case: Specify blocks are turned off, and this is an
@ -3615,7 +3623,8 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
NetProc* PCallTask::elaborate_sys_task_method_(Design*des, NetScope*scope,
NetNet*net,
perm_string method_name,
const char*sys_task_name) const
const char *sys_task_name,
const std::vector<perm_string> &parm_names) const
{
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
@ -3638,17 +3647,17 @@ NetProc* PCallTask::elaborate_sys_task_method_(Design*des, NetScope*scope,
<< "method takes no arguments." << endl;
des->errors += 1;
}
} else if (parm_names.size() != parms_.size()) {
cerr << get_fileline() << ": error: " << method_name
<< "() method takes " << parm_names.size() << " arguments, got "
<< parms_.size() << "." << endl;
des->errors++;
}
auto args = map_named_args(des, parm_names, parms_);
for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
PExpr*ex = parms_[idx];
if (ex != 0) {
argv[idx+1] = elab_sys_task_arg(des, scope,
method_name,
idx, ex);
} else {
argv[idx+1] = 0;
}
argv[idx + 1] = elab_sys_task_arg(des, scope, method_name,
idx, args[idx]);
}
NetSTask*sys = new NetSTask(sys_task_name, IVL_SFUNC_AS_TASK_IGNORE, argv);
@ -3663,7 +3672,8 @@ NetProc* PCallTask::elaborate_sys_task_method_(Design*des, NetScope*scope,
NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope,
NetNet*net,
perm_string method_name,
const char*sys_task_name) const
const char *sys_task_name,
const std::vector<perm_string> &parm_names) const
{
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
@ -3696,33 +3706,38 @@ NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope,
vector<NetExpr*>argv (nparms+1);
argv[0] = sig;
if (method_name != "insert") {
if ((nparms == 0) || (parms_[0] == 0)) {
argv[1] = 0;
cerr << get_fileline() << ": error: " << method_name
<< "() methods first argument is missing." << endl;
des->errors += 1;
} else
argv[1] = elab_and_eval(des, scope, parms_[0], context_width,
false, false, base_type);
} else {
if ((nparms == 0) || (parms_[0] == 0)) {
argv[1] = 0;
cerr << get_fileline() << ": error: " << method_name
<< "() methods first argument is missing." << endl;
des->errors += 1;
} else
argv[1] = elab_and_eval(des, scope, parms_[0], 32,
false, false, IVL_VT_LOGIC);
if ((nparms < 2) || (parms_[1] == 0)) {
argv[2] = 0;
auto args = map_named_args(des, parm_names, parms_);
if (method_name != "insert") {
if (nparms == 0 || !args[0]) {
argv[1] = nullptr;
cerr << get_fileline() << ": error: " << method_name
<< "() methods first argument is missing." << endl;
des->errors += 1;
} else {
argv[1] = elab_and_eval(des, scope, args[0], context_width,
false, false, base_type);
}
} else {
if (nparms == 0 || !args[0]) {
argv[1] = nullptr;
cerr << get_fileline() << ": error: " << method_name
<< "() methods first argument is missing." << endl;
des->errors += 1;
} else {
argv[1] = elab_and_eval(des, scope, args[0], context_width,
false, false, IVL_VT_LOGIC);
}
if (nparms < 2 || !args[1]) {
argv[2] = nullptr;
cerr << get_fileline() << ": error: " << method_name
<< "() methods second argument is missing." << endl;
des->errors += 1;
} else
argv[2] = elab_and_eval(des, scope, parms_[1], context_width,
} else {
argv[2] = elab_and_eval(des, scope, args[1], context_width,
false, false, base_type);
}
}
NetSTask*sys = new NetSTask(sys_task_name, IVL_SFUNC_AS_TASK_IGNORE, argv);
@ -3814,34 +3829,65 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
// Is this a method of a "string" type?
if (dynamic_cast<const netstring_t*>(net->net_type())) {
if (method_name=="itoa")
if (method_name == "itoa") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("i")
};
return elaborate_sys_task_method_(des, scope, net, method_name,
"$ivl_string_method$itoa");
else if (method_name=="hextoa")
"$ivl_string_method$itoa",
parm_names);
} else if (method_name == "hextoa") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("i")
};
return elaborate_sys_task_method_(des, scope, net, method_name,
"$ivl_string_method$hextoa");
else if (method_name=="octtoa")
"$ivl_string_method$hextoa",
parm_names);
} else if (method_name == "octtoa") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("i")
};
return elaborate_sys_task_method_(des, scope, net, method_name,
"$ivl_string_method$octtoa");
else if (method_name=="bintoa")
"$ivl_string_method$octtoa",
parm_names);
} else if (method_name == "bintoa") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("i")
};
return elaborate_sys_task_method_(des, scope, net, method_name,
"$ivl_string_method$bintoa");
else if (method_name=="realtoa")
"$ivl_string_method$bintoa",
parm_names);
} else if (method_name == "realtoa") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("r")
};
return elaborate_sys_task_method_(des, scope, net, method_name,
"$ivl_string_method$realtoa");
"$ivl_string_method$realtoa",
parm_names);
}
}
// Is this a delete method for dynamic arrays or queues?
if (net->darray_type()) {
if (method_name=="delete")
if (method_name == "delete") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("index")
};
return elaborate_sys_task_method_(des, scope, net, method_name,
"$ivl_darray_method$delete");
else if (method_name=="size")
"$ivl_darray_method$delete",
parm_names);
} else if (method_name == "size") {
// This returns an int. It could be removed, but keep for now.
return elaborate_method_func_(scope, net,
&netvector_t::atom2s32,
method_name, "$size");
else if (method_name=="reverse") {
} else if (method_name == "reverse") {
cerr << get_fileline() << ": sorry: 'reverse()' "
"array sorting method is not currently supported."
<< endl;
@ -3870,25 +3916,42 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
if (net->queue_type()) {
const netdarray_t*use_darray = net->darray_type();
if (method_name == "push_back")
if (method_name == "push_back") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("item")
};
return elaborate_queue_method_(des, scope, net, method_name,
"$ivl_queue_method$push_back");
else if (method_name == "push_front")
"$ivl_queue_method$push_back",
parm_names);
} else if (method_name == "push_front") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("item")
};
return elaborate_queue_method_(des, scope, net, method_name,
"$ivl_queue_method$push_front");
else if (method_name == "insert")
"$ivl_queue_method$push_front",
parm_names);
} else if (method_name == "insert") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("index"),
perm_string::literal("item")
};
return elaborate_queue_method_(des, scope, net, method_name,
"$ivl_queue_method$insert");
else if (method_name == "pop_front")
"$ivl_queue_method$insert",
parm_names);
} else if (method_name == "pop_front") {
return elaborate_method_func_(scope, net,
use_darray->element_type(),
method_name,
"$ivl_queue_method$pop_front");
else if (method_name == "pop_back")
} else if (method_name == "pop_back") {
return elaborate_method_func_(scope, net,
use_darray->element_type(),
method_name,
"$ivl_queue_method$pop_back");
}
}
if (const netclass_t*class_type = dynamic_cast<const netclass_t*>(par_type)) {
@ -4096,9 +4159,11 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope,
expression the r-value. We know by definition that the port
is a reg type, so this elaboration is pretty obvious. */
for (unsigned idx = use_this?1:0 ; idx < parm_count ; idx += 1) {
unsigned int off = use_this ? 1 : 0;
size_t parms_idx = use_this? idx-1 : idx;
auto args = map_named_args(des, def, parms_, off);
for (unsigned int idx = off; idx < parm_count; idx++) {
size_t parms_idx = idx - off;
NetNet*port = def->port(idx);
ivl_assert(*this, port->port_type() != NetNet::NOT_A_PORT);
@ -4111,9 +4176,9 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope,
NetExpr*rv = 0;
if (parms_idx < parms_.size() && parms_[parms_idx]) {
if (args[parms_idx]) {
rv = elaborate_rval_expr(des, scope, port->net_type(),
parms_ [parms_idx]);
args[parms_idx]);
if (NetEEvent*evt = dynamic_cast<NetEEvent*> (rv)) {
cerr << evt->get_fileline() << ": error: An event '"
<< evt->event()->name() << "' can not be a user "
@ -4161,9 +4226,9 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope,
expression that can be a target to a procedural
assignment, including a memory word. */
for (unsigned idx = use_this?1:0 ; idx < parm_count ; idx += 1) {
for (unsigned int idx = off; idx < parm_count; idx++) {
size_t parms_idx = use_this? idx-1 : idx;
size_t parms_idx = idx - off;
NetNet*port = def->port(idx);
@ -4179,12 +4244,12 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope,
message. Note that the elaborate_lval method already
printed a detailed message for the latter case. */
NetAssign_*lv = 0;
if (parms_idx < parms_.size() && parms_[parms_idx]) {
lv = parms_[parms_idx]->elaborate_lval(des, scope, false, false);
if (args[parms_idx]) {
lv = args[parms_idx]->elaborate_lval(des, scope, false, false);
if (lv == 0) {
cerr << parms_[parms_idx]->get_fileline() << ": error: "
cerr << args[parms_idx]->get_fileline() << ": error: "
<< "I give up on task port " << (idx+1)
<< " expression: " << *parms_[parms_idx] << endl;
<< " expression: " << *args[parms_idx] << endl;
}
} else if (port->port_type() == NetNet::POUTPUT) {
// Output ports were skipped earlier, so
@ -4335,19 +4400,25 @@ bool PCallTask::elaborate_elab(Design*des, NetScope*scope) const
bool const_parms = true;
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
PExpr*ex = parms_[idx];
if (ex != 0) {
eparms[idx] = elab_sys_task_arg(des, scope, name, idx, ex);
if (!check_parm_is_const(eparms[idx])) {
cerr << get_fileline() << ": error: Elaboration task "
<< name << "() parameter [" << idx+1 << "] '"
<< *eparms[idx] << "' is not constant." << endl;
des->errors += 1;
const_parms = false;
}
} else {
eparms[idx] = 0;
}
auto &parm = parms_[idx];
// Elaboration tasks don't have named parameters
if (!parm.name.nil()) {
cerr << parm.get_fileline() << ": error: "
<< "The elaboration system task `" << name
<< "` has no argument called `" << parm.name
<< "`." << endl;
des->errors++;
}
eparms[idx] = elab_sys_task_arg(des, scope, name, idx, parm.parm);
if (!check_parm_is_const(eparms[idx])) {
cerr << get_fileline() << ": error: Elaboration task "
<< name << "() parameter [" << idx+1 << "] '"
<< *eparms[idx] << "' is not constant." << endl;
des->errors += 1;
const_parms = false;
}
}
if (!const_parms) return true;

View File

@ -0,0 +1,25 @@
// Check that binding task arguments by name is supported.
module test;
class B;
integer val;
function new(integer a, integer b);
val = a + b * 10;
endfunction
endclass
class C extends B(.b(2), .a(1));
endclass
initial begin
C c;
c = new;
if (c.val == 21) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,26 @@
// Check that binding task arguments by name is supported and that a mix of
// positional and named arguments is supported.
module test;
class B;
integer val;
function new(integer a, integer b, integer c);
val = a + b * 10 + c * 100;
endfunction
endclass
class C extends B(1, .c(3), .b(2));
endclass
initial begin
C c;
c = new;
if (c.val == 321) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,27 @@
// Check that binding task arguments by name is supported and that an empty
// value can be bound to the name, in which case the default argument value
// should be used.
module test;
class B;
integer val;
function new(integer a, integer b = 2);
val = a + b * 10;
endfunction
endclass
class C extends B(.a(1), .b());
endclass
initial begin
C c;
c = new;
if (c.val == 21) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,21 @@
// Check that an error is reported when trying to bind an argument by nae that
// does not exist
module test;
class B;
function new(integer a, integer b);
$display("FAILED");
endfunction
endclass
class C extends B(.b(2), .c(1)); // This should fail. `c` is not an arugment
// of the base constructor.
endclass
initial begin
C c;
c = new;
end
endmodule

View File

@ -0,0 +1,21 @@
// Check that an error is reported when trying to bind the same argument by name
// multiple times.
module test;
class B;
function new(integer a, integer b);
$display("FAILED");
endfunction
endclass
class C extends B(.a(1), .a(2)); // This should fail. `a` is provided twice
// as a named argument.
endclass
initial begin
C c;
c = new;
end
endmodule

View File

@ -0,0 +1,21 @@
// Check that an error is reported when trying to bind an argument by name that
// is also provided as a positional argument.
module test;
class B;
function new(integer a, integer b);
$display("FAILED");
endfunction
endclass
class C extends B(1, .a(2)); // This should fail. `a` is provided both as a
// positional and named argument.
endclass
initial begin
C c;
c = new;
end
endmodule

View File

@ -0,0 +1,21 @@
// Check that an error is reported trying to provide a positional argument to a
// function after a named argument.
module test;
class B;
function new(integer a, integer b);
$display("FAILED");
endfunction
endclass
class C extends B(.a(2), 1); // This should fail. Positional arguments must
// precede named arguments.
endclass
initial begin
C c;
c = new;
end
endmodule

View File

@ -0,0 +1,20 @@
// Check that an error is reported when binding an empty value to an argument by
// name and the argument does not have a default value.
module test;
class B;
function new(integer a);
$display("FAILED");
endfunction
endclass
class C extends B(.a()); // This should fail. `a` has no default value.
endclass
initial begin
C c;
c = new;
end
endmodule

View File

@ -0,0 +1,28 @@
// Check that binding task arguments by name is supported.
module test;
class B;
integer val;
function new(integer a, integer b);
val = a + b * 10;
endfunction
endclass
class C extends B;
function new;
super.new(.b(2), .a(1));
endfunction
endclass
initial begin
C c;
c = new;
if (c.val == 21) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,29 @@
// Check that binding task arguments by name is supported and that a mix of
// positional and named arguments is supported.
module test;
class B;
integer val;
function new(integer a, integer b, integer c);
val = a + b * 10 + c * 100;
endfunction
endclass
class C extends B;
function new;
super.new(1, .c(3), .b(2));
endfunction
endclass
initial begin
C c;
c = new;
if (c.val == 321) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,30 @@
// Check that binding task arguments by name is supported and that an empty
// value can be bound to the name, in which case the default argument value
// should be used.
module test;
class B;
integer val;
function new(integer a, integer b = 2);
val = a + b * 10;
endfunction
endclass
class C extends B;
function new;
super.new(.a(1), .b());
endfunction
endclass
initial begin
C c;
c = new;
if (c.val == 21) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,24 @@
// Check that an error is reported when trying to bind an argument by nae that
// does not exist
module test;
class B;
function new(integer a, integer b);
$display("FAILED");
endfunction
endclass
class C extends B;
function new;
super.new(.b(2), .c(1)); // This should fail. `c` is not an arugment of
// the base constructor.
endfunction
endclass
initial begin
C c;
c = new;
end
endmodule

View File

@ -0,0 +1,24 @@
// Check that an error is reported when trying to bind the same argument by name
// multiple times.
module test;
class B;
function new(integer a, integer b);
$display("FAILED");
endfunction
endclass
class C extends B;
function new;
super.new(.a(1), .a(2)); // This should fail. `a` is provided twice as a
// named argument.
endfunction
endclass
initial begin
C c;
c = new;
end
endmodule

View File

@ -0,0 +1,24 @@
// Check that an error is reported when trying to bind an argument by name that
// is also provided as a positional argument.
module test;
class B;
function new(integer a, integer b);
$display("FAILED");
endfunction
endclass
class C extends B;
function new;
super.new(1, .a(2)); // This should fail. `a` is provided both as a
// positional and named argument.
endfunction
endclass
initial begin
C c;
c = new;
end
endmodule

View File

@ -0,0 +1,24 @@
// Check that an error is reported trying to provide a positional argument to a
// function after a named argument.
module test;
class B;
function new(integer a, integer b);
$display("FAILED");
endfunction
endclass
class C extends B;
function new;
super.new(.a(2), 1); // This should fail. Positional arguments must
// precede named arguments.
endfunction
endclass
initial begin
C c;
c = new;
end
endmodule

View File

@ -0,0 +1,23 @@
// Check that an error is reported when binding an empty value to an argument by
// name and the argument does not have a default value.
module test;
class B;
function new(integer a);
$display("FAILED");
endfunction
endclass
class C extends B;
function new;
super.new(.a()); // This should fail. `a` has no default value.
endfunction
endclass
initial begin
C c;
c = new;
end
endmodule

View File

@ -0,0 +1,19 @@
// Check that binding task arguments by name is supported.
module test;
function integer f(integer a, integer b);
return a + b * 10;
endfunction
initial begin
integer x;
x = f(.b(2), .a(1));
if (x == 21) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,20 @@
// Check that binding task arguments by name is supported and that a mix of
// positional and named arguments is supported.
module test;
function integer f(integer a, integer b, integer c);
return a + b * 10 + c * 100;
endfunction
initial begin
integer x;
x = f(1, .c(3), .b(2));
if (x == 321) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,21 @@
// Check that binding task arguments by name is supported and that an empty
// value can be bound to the name, in which case the default argument value
// should be used.
module test;
function integer f(integer a, integer b = 2);
return a + b * 10;
endfunction
initial begin
integer x;
x = f(.a(1), .b());
if (x == 21) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,15 @@
// Check that an error is reported when trying to bind an argument by nae that
// does not exist
module test;
function f(integer a, integer b);
$display("FAILED");
endfunction
initial begin
integer x;
x = f(.b(2), .c(1)); // This should fail. `c` is not an arugment of `f`.
end
endmodule

View File

@ -0,0 +1,16 @@
// Check that an error is reported when trying to bind the same argument by name
// multiple times.
module test;
function f(integer a, integer b);
$display("FAILED");
endfunction
initial begin
integer x;
x = f(.a(1), .a(2)); // This should fail. `a` is provided twice as a named
// argument.
end
endmodule

View File

@ -0,0 +1,16 @@
// Check that an error is reported when trying to bind an argument by name that
// is also provided as a positional argument.
module test;
function f(integer a, integer b);
$display("FAILED");
endfunction
initial begin
integer x;
x = f(1, .a(2)); // This should fail. `a` is provided both as a positional
// and named argument.
end
endmodule

View File

@ -0,0 +1,16 @@
// Check that an error is reported trying to provide a positional argument to a
// function after a named argument.
module test;
function f(integer a, integer b);
$display("FAILED");
endfunction
initial begin
integer x;
x = f(.a(2), 1); // This should fail. Positional arguments must precede
// named arguments.
end
endmodule

View File

@ -0,0 +1,15 @@
// Check that an error is reported when binding an empty value to an argument by
// name and the argument does not have a default value.
module test;
function f(integer a);
$display("FAILED");
endfunction
initial begin
integer x;
x = f(.a()); // This should fail. `a` has no default value.
end
endmodule

View File

@ -0,0 +1,22 @@
// Check that binding task arguments by name is supported.
module test;
class C;
integer val;
function new(integer a, integer b);
val = a + b * 10;
endfunction
endclass
initial begin
C c;
c = new(.b(2), .a(1));
if (c.val == 21) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,23 @@
// Check that binding task arguments by name is supported and that a mix of
// positional and named arguments is supported.
module test;
class C;
integer val;
function new(integer a, integer b, integer c);
val = a + b * 10 + c * 100;
endfunction
endclass
initial begin
C c;
c = new(1, .c(3), .b(2));
if (c.val == 321) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,24 @@
// Check that binding task arguments by name is supported and that an empty
// value can be bound to the name, in which case the default argument value
// should be used.
module test;
class C;
integer val;
function new(integer a, integer b = 2);
val = a + b * 10;
endfunction
endclass
initial begin
C c;
c = new(.a(1), .b());
if (c.val == 21) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,18 @@
// Check that an error is reported when trying to bind an argument by nae that
// does not exist
module test;
class C;
function new(integer a, integer b);
$display("FAILED");
endfunction
endclass
initial begin
C c;
c = new(.b(2), .c(1)); // This should fail. `c` is not an arugment of the
// constructor.
end
endmodule

View File

@ -0,0 +1,18 @@
// Check that an error is reported when trying to bind the same argument by name
// multiple times.
module test;
class C;
function new(integer a, integer b);
$display("FAILED");
endfunction
endclass
initial begin
C c;
c = new(.a(1), .a(2)); // This should fail. `a` is provided twice as a named
// argument.
end
endmodule

View File

@ -0,0 +1,18 @@
// Check that an error is reported when trying to bind an argument by name that
// is also provided as a positional argument.
module test;
class C;
function new(integer a, integer b);
$display("FAILED");
endfunction
endclass
initial begin
C c;
c = new(1, .a(2)); // This should fail. `a` is provided both as a positional
// and named argument.
end
endmodule

View File

@ -0,0 +1,18 @@
// Check that an error is reported trying to provide a positional argument to a
// function after a named argument.
module test;
class C;
function new(integer a, integer b);
$display("FAILED");
endfunction
endclass
initial begin
C c;
c = new(.a(2), 1); // This should fail. Positional arguments must precede
// named arguments.
end
endmodule

View File

@ -0,0 +1,17 @@
// Check that an error is reported when binding an empty value to an argument by
// name and the argument does not have a default value.
module test;
class C;
function new(integer a);
$display("FAILED");
endfunction
endclass
initial begin
C c;
c = new(.a()); // This should fail. `a` has no default value.
end
endmodule

View File

@ -0,0 +1,17 @@
// Check that binding task arguments by name is supported.
module test;
task t(integer a, integer b);
if (a == 1 && b == 2) begin
$display("PASSED");
end else begin
$display("FAILED");
end
endtask
initial begin
t(.b(2), .a(1));
end
endmodule

View File

@ -0,0 +1,18 @@
// Check that binding task arguments by name is supported and that a mix of
// positional and named arguments is supported.
module test;
task t(integer a, integer b, integer c);
if (a == 1 && b == 2 && c == 3) begin
$display("PASSED");
end else begin
$display("FAILED");
end
endtask
initial begin
t(1, .c(3), .b(2));
end
endmodule

View File

@ -0,0 +1,19 @@
// Check that binding task arguments by name is supported and that an empty
// value can be bound to the name, in which case the default argument value
// should be used.
module test;
task t(integer a, integer b = 2);
if (a == 1 && b == 2) begin
$display("PASSED");
end else begin
$display("FAILED");
end
endtask
initial begin
t(.a(1), .b());
end
endmodule

View File

@ -0,0 +1,14 @@
// Check that an error is reported when trying to bind an argument by nae that
// does not exist
module test;
task t(integer a, integer b);
$display("FAILED");
endtask
initial begin
t(.b(2), .c(1));
end
endmodule

View File

@ -0,0 +1,14 @@
// Check that an error is reported when trying to bind the same argument by name
// multiple times.
module test;
task t(integer a, integer b);
$display("FAILED");
endtask
initial begin
t(.a(1), .a(2));
end
endmodule

View File

@ -0,0 +1,14 @@
// Check that an error is reported when trying to bind an argument by name that
// is also provided as a positional argument.
module test;
task t(integer a, integer b);
$display("FAILED");
endtask
initial begin
t(1, .a(2));
end
endmodule

View File

@ -0,0 +1,15 @@
// Check that an error is reported trying to provide a positional argument to a
// task after a named argument.
module test;
task t(integer a, integer b);
$display("FAILED");
endtask
initial begin
t(.a(2), 1); // This should fail. Positional arguments must precede
// named arguments.
end
endmodule

View File

@ -0,0 +1,14 @@
// Check that an error is reported when binding an empty value to an argument by
// name and the argument does not have a default value.
module test;
task t(integer a);
$display("FAILED");
endtask
initial begin
t(.a()); // This should fail. `a` has no default value.
end
endmodule

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_named_arg_base1.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_named_arg_base2.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_named_arg_base3.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_base_fail1.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_base_fail2.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_base_fail3.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_base_fail4.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_base_fail5.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_named_arg_chained1.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_named_arg_chained2.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_named_arg_chained3.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_chained_fail1.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_chained_fail2.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_chained_fail3.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_chained_fail4.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_chained_fail5.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_named_arg_func1.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_named_arg_func2.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_named_arg_func3.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_func_fail1.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_func_fail2.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_func_fail3.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_func_fail4.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_func_fail5.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_named_arg_new1.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_named_arg_new2.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_named_arg_new3.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_new_fail1.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_new_fail2.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_new_fail3.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_new_fail4.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_new_fail5.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_named_arg_task1.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_named_arg_task2.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "normal",
"source" : "sv_named_arg_task3.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_task_fail1.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_task_fail2.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_task_fail3.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_task_fail4.v",
"iverilog-args" : [ "-g2005-sv" ]
}

View File

@ -0,0 +1,5 @@
{
"type" : "CE",
"source" : "sv_named_arg_task_fail5.v",
"iverilog-args" : [ "-g2005-sv" ]
}

75
map_named_args.cc Normal file
View File

@ -0,0 +1,75 @@
// SPDX-FileCopyrightText: 2023 Lars-Peter Clausen <lars@metafoo.de>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "PExpr.h"
#include "ivl_assert.h"
#include "map_named_args.h"
#include "netlist.h"
#include <iostream>
std::vector<PExpr*> map_named_args(Design *des,
const std::vector<perm_string> &names,
const std::vector<named_pexpr_t> &parms)
{
std::vector<PExpr*> args(names.size());
bool has_named = false;
for (size_t i = 0; i < parms.size(); i++) {
if (parms[i].name.nil()) {
if (!parms[i].parm)
continue;
if (has_named) {
std::cerr << parms[i].get_fileline() << ": error: "
<< "Positional argument must preceded "
<< "named arguments."
<< std::endl;
} else if (i < args.size()) {
args[i] = parms[i].parm;
}
continue;
}
has_named = true;
bool found = false;
for (size_t j = 0; j < names.size(); j++) {
if (names[j] == parms[i].name) {
if (args[j]) {
std::cerr << parms[i].get_fileline() << ": error: "
<< "Argument `"
<< parms[i].name
<< "` has already been specified."
<< std::endl;
des->errors++;
} else {
args[j] = parms[i].parm;
}
found = true;
break;
}
}
if (!found) {
std::cerr << parms[i].get_fileline() << ": error: "
<< "No argument called `"
<< parms[i].name << "`."
<< std::endl;
des->errors++;
}
}
return args;
}
std::vector<PExpr*> map_named_args(Design *des, NetBaseDef *def,
const std::vector<named_pexpr_t> &parms,
unsigned int off)
{
std::vector<perm_string> names;
for (size_t j = off; j < def->port_count(); j++)
names.push_back(def->port(j)->name());
return map_named_args(des, names, parms);
}

22
map_named_args.h Normal file
View File

@ -0,0 +1,22 @@
// SPDX-FileCopyrightText: 2023 Lars-Peter Clausen <lars@metafoo.de>
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef MAP_NAMED_ARGS_H
#define MAP_NAMED_ARGS_H
#include <vector>
#include "pform_types.h"
class PExpr;
class Design;
class NetBaseDef;
std::vector<PExpr*> map_named_args(Design *des,
const std::vector<perm_string> &names,
const std::vector<named_pexpr_t> &parms);
std::vector<PExpr*> map_named_args(Design *des, NetBaseDef *def,
const std::vector<named_pexpr_t> &parms,
unsigned int off);
#endif

View File

@ -20,13 +20,14 @@
*/
# include "StringHeap.h"
# include "libmisc/LineInfo.h"
/*
* There are lots of places where names are attached to objects. This
* simple template expresses the lot.
*/
template <class T> struct named {
template <class T> struct named : public LineInfo {
perm_string name;
T parm;
};

View File

@ -579,16 +579,10 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
: NetObj(s, n, calculate_count(unpacked)),
type_(t), port_type_(NOT_A_PORT),
local_flag_(false), net_type_(use_net_type),
discipline_(0), unpacked_dims_(unpacked.size()),
discipline_(0), unpacked_dims_(unpacked.begin(), unpacked.end()),
eref_count_(0), lref_count_(0)
{
calculate_slice_widths_from_packed_dims_();
size_t idx = 0;
for (list<netrange_t>::const_iterator cur = unpacked.begin()
; cur != unpacked.end() ; ++cur, idx += 1) {
unpacked_dims_[idx] = *cur;
}
ivl_assert(*this, idx == unpacked_dims_.size());
ivl_assert(*this, s);
if (pin_count() == 0) {

View File

@ -1046,6 +1046,9 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name,
unsigned arg_idx, PExpr*pe, bool need_const)
{
if (!pe)
return nullptr;
PExpr::width_mode_t mode = PExpr::SIZED;
pe->test_width(des, scope, mode);

167
parse.y
View File

@ -172,9 +172,9 @@ template <class T> void append(vector<T>&out, const std::vector<T>&in)
* The parser parses an empty argument list as an argument list with an single
* empty argument. Fix this up here and replace it with an empty list.
*/
static void argument_list_fixup(list<PExpr*>*lst)
static void argument_list_fixup(list<named_pexpr_t> *lst)
{
if (lst->size() == 1 && !lst->front())
if (lst->size() == 1 && lst->front().name.nil() && !lst->front().parm)
lst->clear();
}
@ -184,22 +184,28 @@ static void argument_list_fixup(list<PExpr*>*lst)
*/
static PECallFunction*make_call_function(perm_string tn, PExpr*arg)
{
std::vector<PExpr*> parms(1);
parms[0] = arg;
std::vector<named_pexpr_t> parms(1);
parms[0].parm = arg;
parms[0].set_line(*arg);
PECallFunction*tmp = new PECallFunction(tn, parms);
return tmp;
}
static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
{
std::vector<PExpr*> parms(2);
parms[0] = arg1;
parms[1] = arg2;
std::vector<named_pexpr_t> parms(2);
parms[0].parm = arg1;
parms[0].set_line(*arg1);
parms[1].parm = arg2;
parms[1].set_line(*arg2);
PECallFunction*tmp = new PECallFunction(tn, parms);
return tmp;
}
static std::list<named_pexpr_t>* make_named_numbers(perm_string name, long first, long last, PExpr*val =0)
static std::list<named_pexpr_t>* make_named_numbers(const struct vlltype &loc,
perm_string name,
long first, long last,
PExpr *val = nullptr)
{
std::list<named_pexpr_t>*lst = new std::list<named_pexpr_t>;
named_pexpr_t tmp;
@ -210,6 +216,7 @@ static std::list<named_pexpr_t>* make_named_numbers(perm_string name, long first
buf << name.str() << idx << ends;
tmp.name = lex_strings.make(buf.str());
tmp.parm = val;
FILE_NAME(&tmp, loc);
val = 0;
lst->push_back(tmp);
}
@ -220,6 +227,7 @@ static std::list<named_pexpr_t>* make_named_numbers(perm_string name, long first
buf << name.str() << idx << ends;
tmp.name = lex_strings.make(buf.str());
tmp.parm = val;
FILE_NAME(&tmp, loc);
val = 0;
lst->push_back(tmp);
}
@ -227,12 +235,15 @@ static std::list<named_pexpr_t>* make_named_numbers(perm_string name, long first
return lst;
}
static std::list<named_pexpr_t>* make_named_number(perm_string name, PExpr*val =0)
static std::list<named_pexpr_t>* make_named_number(const struct vlltype &loc,
perm_string name,
PExpr *val = nullptr)
{
std::list<named_pexpr_t>*lst = new std::list<named_pexpr_t>;
named_pexpr_t tmp;
tmp.name = name;
tmp.parm = val;
FILE_NAME(&tmp, loc);
lst->push_back(tmp);
return lst;
}
@ -455,9 +466,6 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id,
std::list<PLet::let_port_t*>*let_port_lst;
PLet::let_port_t*let_port_itm;
named_number_t* named_number;
std::list<named_number_t>* named_numbers;
named_pexpr_t*named_pexpr;
std::list<named_pexpr_t>*named_pexprs;
struct parmvalue_t*parmvalue;
@ -505,7 +513,7 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id,
struct {
data_type_t*type;
std::list<PExpr*>*exprs;
std::list<named_pexpr_t> *args;
} class_declaration_extends;
struct {
@ -678,13 +686,17 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id,
%type <tf_ports> tf_port_declaration tf_port_item tf_port_item_list
%type <tf_ports> tf_port_list tf_port_list_opt tf_port_list_parens_opt
%type <named_pexpr> modport_simple_port port_name parameter_value_byname
%type <named_pexpr> named_expression named_expression_opt port_name
%type <named_pexprs> port_name_list parameter_value_byname_list
%type <exprs> port_conn_expression_list_with_nuls
%type <named_pexpr> attribute
%type <named_pexprs> attribute_list attribute_instance_list attribute_list_opt
%type <named_pexpr> argument
%type <named_pexprs> argument_list
%type <named_pexprs> argument_list_parens argument_list_parens_opt
%type <citem> case_item
%type <citems> case_items
@ -712,7 +724,6 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id,
%type <expr> delay_value delay_value_simple
%type <exprs> delay1 delay3 delay3_opt delay_value_list
%type <exprs> expression_list_with_nuls expression_list_proper
%type <exprs> argument_list_parens argument_list_parens_opt
%type <exprs> cont_assign cont_assign_list
%type <decl_assignment> variable_decl_assignment
@ -884,7 +895,7 @@ class_declaration /* IEEE1800-2005: A.1.2 */
class_type_t *class_type= new class_type_t(name);
FILE_NAME(class_type, @4);
pform_set_typedef(@4, name, class_type, nullptr);
pform_start_class_declaration(@2, class_type, $5.type, $5.exprs, $1);
pform_start_class_declaration(@2, class_type, $5.type, $5.args, $1);
}
class_items_opt K_endclass
{ // Process a class.
@ -927,11 +938,12 @@ class_declaration_endlabel_opt
class_declaration_extends_opt /* IEEE1800-2005: A.1.2 */
: K_extends ps_type_identifier argument_list_parens_opt
{ $$.type = $2;
$$.exprs = $3;
{ $$.type = $2;
$$.args = $3;
}
|
{ $$.type = 0; $$.exprs = 0; }
{ $$ = {nullptr, nullptr};
}
;
/* The class_items_opt and class_items rules together implement the
@ -1978,7 +1990,7 @@ modport_item
modport_ports_list
: modport_ports_declaration
| modport_ports_list ',' modport_ports_declaration
| modport_ports_list ',' modport_simple_port
| modport_ports_list ',' named_expression
{ if (last_modport_port.type == MP_SIMPLE) {
pform_add_modport_port(@3, last_modport_port.direction,
$3->name, $3->parm);
@ -2012,7 +2024,7 @@ modport_ports_declaration
delete[] $3;
delete $1;
}
| attribute_list_opt port_direction modport_simple_port
| attribute_list_opt port_direction named_expression
{ last_modport_port.type = MP_SIMPLE;
last_modport_port.direction = $2;
pform_add_modport_port(@3, $2, $3->name, $3->parm);
@ -2041,16 +2053,6 @@ modport_ports_declaration
}
;
modport_simple_port
: '.' IDENTIFIER '(' expression ')'
{ named_pexpr_t*tmp = new named_pexpr_t;
tmp->name = lex_strings.make($2);
tmp->parm = $4;
delete[]$2;
$$ = tmp;
}
;
modport_tf_port
: K_task IDENTIFIER tf_port_list_parens_opt
| K_function data_type_or_implicit_or_void IDENTIFIER tf_port_list_parens_opt
@ -2256,7 +2258,7 @@ simple_immediate_assertion_statement /* IEEE1800-2012 A.6.10 */
: assert_or_assume '(' expression ')' statement_or_null %prec less_than_K_else
{
if (gn_supported_assertions_flag) {
std::list<PExpr*>arg_list;
std::list<named_pexpr_t> arg_list;
PCallTask*tmp1 = new PCallTask(lex_strings.make("$error"), arg_list);
FILE_NAME(tmp1, @1);
PCondit*tmp2 = new PCondit($3, $5, tmp1);
@ -2713,6 +2715,7 @@ attribute_list
attribute
: IDENTIFIER initializer_opt
{ named_pexpr_t*tmp = new named_pexpr_t;
FILE_NAME(tmp, @$);
tmp->name = lex_strings.make($1);
tmp->parm = $2;
delete[]$1;
@ -2907,19 +2910,19 @@ enum_name
: IDENTIFIER initializer_opt
{ perm_string name = lex_strings.make($1);
delete[]$1;
$$ = make_named_number(name, $2);
$$ = make_named_number(@$, name, $2);
}
| IDENTIFIER '[' pos_neg_number ']' initializer_opt
{ perm_string name = lex_strings.make($1);
long count = check_enum_seq_value(@1, $3, false);
$$ = make_named_numbers(name, 0, count-1, $5);
$$ = make_named_numbers(@$, name, 0, count-1, $5);
delete[]$1;
delete $3;
}
| IDENTIFIER '[' pos_neg_number ':' pos_neg_number ']' initializer_opt
{ perm_string name = lex_strings.make($1);
$$ = make_named_numbers(name, check_enum_seq_value(@1, $3, true),
check_enum_seq_value(@1, $5, true), $7);
$$ = make_named_numbers(@$, name, check_enum_seq_value(@1, $3, true),
check_enum_seq_value(@1, $5, true), $7);
delete[]$1;
delete $3;
delete $5;
@ -3718,12 +3721,45 @@ expression_list_with_nuls
}
;
argument
: expression
{ named_pexpr_t *tmp = new named_pexpr_t;
FILE_NAME(tmp, @$);
tmp->name = perm_string();
tmp->parm = $1;
$$ = tmp;
}
| named_expression_opt
{ $$ = $1;
}
|
{ named_pexpr_t *tmp = new named_pexpr_t;
tmp->name = perm_string();
tmp->parm = nullptr;
$$ = tmp;
}
;
argument_list
: argument
{ std::list<named_pexpr_t> *expr = new std::list<named_pexpr_t>;
expr->push_back(*$1);
delete $1;
$$ = expr;
}
| argument_list ',' argument
{ $1->push_back(*$3);
delete $3;
$$ = $1;
}
;
/* An argument list enclosed in parenthesis. The parser will parse '()' as a
* argument list with an single empty item. We fix this up once the list
* parsing is done by replacing it with the empty list.
*/
argument_list_parens
: '(' expression_list_with_nuls ')'
: '(' argument_list ')'
{ argument_list_fixup($2);
$$ = $2; }
;
@ -3735,7 +3771,8 @@ argument_list_parens_opt
: argument_list_parens
{ $$ = $1; }
|
{ $$ = new std::list<PExpr*>; }
{ $$ = new std::list<named_pexpr_t>; }
;
expression_list_proper
: expression_list_proper ',' expression
@ -3878,12 +3915,14 @@ expr_primary
delete $2;
$$ = tmp;
}
| SYSTEM_IDENTIFIER '(' expression_list_proper ')'
| SYSTEM_IDENTIFIER argument_list_parens
{ perm_string tn = lex_strings.make($1);
PECallFunction*tmp = new PECallFunction(tn, *$3);
PECallFunction *tmp = new PECallFunction(tn, *$2);
if ($2->empty())
pform_requires_sv(@1, "Empty function argument list");
FILE_NAME(tmp, @1);
delete[]$1;
delete $3;
delete $2;
$$ = tmp;
}
| package_scope hierarchy_identifier { lex_in_package_scope(0); } argument_list_parens
@ -3893,16 +3932,6 @@ expr_primary
delete $4;
$$ = tmp;
}
| SYSTEM_IDENTIFIER '(' ')'
{ perm_string tn = lex_strings.make($1);
const std::vector<PExpr*>empty;
PECallFunction*tmp = new PECallFunction(tn, empty);
FILE_NAME(tmp, @1);
delete[]$1;
$$ = tmp;
pform_requires_sv(@1, "Empty function argument list");
}
| K_this
{ PEIdent*tmp = new PEIdent(perm_string::literal(THIS_TOKEN));
FILE_NAME(tmp,@1);
@ -5553,16 +5582,21 @@ parameter_value_opt
{ $$ = 0; }
;
parameter_value_byname
named_expression
: '.' IDENTIFIER '(' expression ')'
{ named_pexpr_t*tmp = new named_pexpr_t;
FILE_NAME(tmp, @$);
tmp->name = lex_strings.make($2);
tmp->parm = $4;
delete[]$2;
$$ = tmp;
}
named_expression_opt
: named_expression
| '.' IDENTIFIER '(' ')'
{ named_pexpr_t*tmp = new named_pexpr_t;
FILE_NAME(tmp, @$);
tmp->name = lex_strings.make($2);
tmp->parm = 0;
delete[]$2;
@ -5571,13 +5605,13 @@ parameter_value_byname
;
parameter_value_byname_list
: parameter_value_byname
: named_expression_opt
{ std::list<named_pexpr_t>*tmp = new std::list<named_pexpr_t>;
tmp->push_back(*$1);
delete $1;
$$ = tmp;
}
| parameter_value_byname_list ',' parameter_value_byname
| parameter_value_byname_list ',' named_expression_opt
{ std::list<named_pexpr_t>*tmp = $1;
tmp->push_back(*$3);
delete $3;
@ -5646,25 +5680,14 @@ port_opt
looking for the ports of a module declaration. */
port_name
: attribute_list_opt '.' IDENTIFIER '(' expression ')'
{ named_pexpr_t*tmp = new named_pexpr_t;
tmp->name = lex_strings.make($3);
tmp->parm = $5;
delete[]$3;
delete $1;
$$ = tmp;
: attribute_list_opt named_expression_opt
{ delete $1;
$$ = $2;
}
| attribute_list_opt '.' IDENTIFIER '(' error ')'
{ yyerror(@3, "error: Invalid port connection expression.");
named_pexpr_t*tmp = new named_pexpr_t;
tmp->name = lex_strings.make($3);
tmp->parm = 0;
delete[]$3;
delete $1;
$$ = tmp;
}
| attribute_list_opt '.' IDENTIFIER '(' ')'
{ named_pexpr_t*tmp = new named_pexpr_t;
FILE_NAME(tmp, @$);
tmp->name = lex_strings.make($3);
tmp->parm = 0;
delete[]$3;
@ -5674,6 +5697,7 @@ port_name
| attribute_list_opt '.' IDENTIFIER
{ pform_requires_sv(@3, "Implicit named port connections");
named_pexpr_t*tmp = new named_pexpr_t;
FILE_NAME(tmp, @$);
tmp->name = lex_strings.make($3);
tmp->parm = new PEIdent(lex_strings.make($3), true);
FILE_NAME(tmp->parm, @3);
@ -5683,6 +5707,7 @@ port_name
}
| K_DOTSTAR
{ named_pexpr_t*tmp = new named_pexpr_t;
FILE_NAME(tmp, @$);
tmp->name = lex_strings.make("*");
tmp->parm = 0;
$$ = tmp;
@ -6559,7 +6584,7 @@ subroutine_call
}
| hierarchy_identifier '(' error ')'
{ yyerror(@3, "error: Syntax error in task arguments.");
list<PExpr*>pt;
std::list<named_pexpr_t> pt;
PCallTask*tmp = pform_make_call_task(@1, *$1, pt);
delete $1;
$$ = tmp;
@ -6936,7 +6961,7 @@ statement_item /* This is roughly statement_item in the LRM */
} else {
yyerror(@2, "error: Constraint block can only be applied to randomize method.");
}
list<PExpr*>pt;
list<named_pexpr_t> pt;
PCallTask*tmp = new PCallTask(*$1, pt);
FILE_NAME(tmp, @1);
delete $1;

Some files were not shown because too many files have changed in this diff Show More