Merge pull request #992 from larsclausen/tf-named-ports
Add support for binding function/task arguments by name
This commit is contained in:
commit
e1f5dbcf17
|
|
@ -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 \
|
||||
|
|
|
|||
70
PExpr.cc
70
PExpr.cc
|
|
@ -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
18
PExpr.h
|
|
@ -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_;
|
||||
|
|
|
|||
4
PGate.cc
4
PGate.cc
|
|
@ -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);
|
||||
|
|
|
|||
8
PGate.h
8
PGate.h
|
|
@ -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;
|
||||
|
|
|
|||
7
PSpec.cc
7
PSpec.cc
|
|
@ -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;
|
||||
|
|
|
|||
6
PSpec.h
6
PSpec.h
|
|
@ -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;
|
||||
|
|
|
|||
3
PTask.h
3
PTask.h
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
51
Statement.cc
51
Statement.cc
|
|
@ -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()
|
||||
|
|
|
|||
21
Statement.h
21
Statement.h
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
188
elab_expr.cc
188
elab_expr.cc
|
|
@ -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.
|
||||
|
|
|
|||
13
elab_sig.cc
13
elab_sig.cc
|
|
@ -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: "
|
||||
|
|
|
|||
241
elaborate.cc
241
elaborate.cc
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_named_arg_base1.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_named_arg_base2.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_named_arg_base3.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_base_fail1.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_base_fail2.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_base_fail3.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_base_fail4.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_base_fail5.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_named_arg_chained1.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_named_arg_chained2.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_named_arg_chained3.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_chained_fail1.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_chained_fail2.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_chained_fail3.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_chained_fail4.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_chained_fail5.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_named_arg_func1.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_named_arg_func2.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_named_arg_func3.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_func_fail1.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_func_fail2.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_func_fail3.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_func_fail4.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_func_fail5.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_named_arg_new1.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_named_arg_new2.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_named_arg_new3.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_new_fail1.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_new_fail2.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_new_fail3.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_new_fail4.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_new_fail5.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_named_arg_task1.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_named_arg_task2.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_named_arg_task3.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_task_fail1.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_task_fail2.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_task_fail3.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_task_fail4.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "CE",
|
||||
"source" : "sv_named_arg_task_fail5.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
3
named.h
3
named.h
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
167
parse.y
|
|
@ -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
Loading…
Reference in New Issue