This commit is contained in:
muhammadjawadkhan 2026-04-30 19:43:09 +00:00 committed by GitHub
commit f1b86be9ac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
108 changed files with 7433 additions and 313 deletions

1
.gitignore vendored
View File

@ -43,6 +43,7 @@ stamp-*-h
/version_tag.h
# Directories
/devel/
autom4te.cache
dep

View File

@ -261,12 +261,37 @@ PECallFunction::PECallFunction(perm_string n, const list<named_pexpr_t> &parms)
{
}
PECallFunction::PECallFunction(PExpr* chain_prefix, const pform_name_t &method,
const vector<named_pexpr_t> &parms)
: path_(method), parms_(parms), chain_prefix_(chain_prefix), is_overridden_(false)
{
}
PECallFunction::PECallFunction(PExpr* chain_prefix, const pform_name_t &method,
const list<named_pexpr_t> &parms)
: path_(method), parms_(parms.begin(), parms.end()),
chain_prefix_(chain_prefix), is_overridden_(false)
{
}
void PECallFunction::set_with_clause(PExpr* with_expr)
{
delete with_expr_;
with_expr_ = with_expr;
}
PECallFunction::~PECallFunction()
{
delete chain_prefix_;
delete with_expr_;
}
void PECallFunction::declare_implicit_nets(LexicalScope*scope, NetNet::Type type)
{
if (chain_prefix_)
chain_prefix_->declare_implicit_nets(scope, type);
if (with_expr_)
with_expr_->declare_implicit_nets(scope, type);
for (const auto &parm : parms_) {
if (parm.parm)
parm.parm->declare_implicit_nets(scope, type);
@ -275,12 +300,15 @@ void PECallFunction::declare_implicit_nets(LexicalScope*scope, NetNet::Type type
bool PECallFunction::has_aa_term(Design*des, NetScope*scope) const
{
bool flag = false;
if (chain_prefix_ && chain_prefix_->has_aa_term(des, scope))
return true;
if (with_expr_ && with_expr_->has_aa_term(des, scope))
return true;
for (const auto &parm : parms_) {
if (parm.parm)
flag |= parm.parm->has_aa_term(des, scope);
if (parm.parm && parm.parm->has_aa_term(des, scope))
return true;
}
return flag;
return false;
}
PEConcat::PEConcat(const list<PExpr*>&p, PExpr*r)

39
PExpr.h
View File

@ -37,6 +37,7 @@ class NetExpr;
class NetScope;
class PPackage;
struct symbol_search_results;
class netclass_t;
/*
* The PExpr class hierarchy supports the description of
@ -924,8 +925,22 @@ class PECallFunction : public PExpr {
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);
// SystemVerilog: prefix().method(args) — prefix elaborates to a class handle.
explicit PECallFunction(PExpr* chain_prefix, const pform_name_t &method,
const std::vector<named_pexpr_t> &parms);
explicit PECallFunction(PExpr* chain_prefix, const pform_name_t &method,
const std::list<named_pexpr_t> &parms);
// SystemVerilog: q.find with (expr) — iterator "item"/"index" in expr.
void set_with_clause(PExpr* with_expr);
const PExpr* peek_with_clause(void) const { return with_expr_; }
~PECallFunction() override;
// For chained-call resolution (path is only the final method name).
const pform_scoped_name_t& peek_path(void) const { return path_; }
const PExpr* peek_chain_prefix(void) const { return chain_prefix_; }
virtual void dump(std::ostream &) const override;
virtual void declare_implicit_nets(LexicalScope*scope, NetNet::Type type) override;
@ -944,6 +959,9 @@ class PECallFunction : public PExpr {
private:
pform_scoped_name_t path_;
std::vector<named_pexpr_t> parms_;
// If non-null, this call is prefix().tail_name(...) (SV method chain).
PExpr* chain_prefix_ = nullptr;
PExpr* with_expr_ = nullptr;
// For system functions.
bool is_overridden_;
@ -981,7 +999,26 @@ class PECallFunction : public PExpr {
unsigned elaborate_arguments_(Design*des, NetScope*scope,
const NetFuncDef*def, bool need_const,
std::vector<NetExpr*>&parms,
unsigned parm_off) const;
unsigned parm_off,
const std::vector<named_pexpr_t>*src_parms = nullptr) const;
NetExpr* elaborate_class_method_net_(Design*des, NetScope*scope,
NetNet*net, const netclass_t*class_type,
perm_string method_name,
const std::vector<named_pexpr_t>*src_parms) const;
NetExpr* elaborate_class_method_net_this_(Design*des, NetScope*scope,
NetExpr* this_expr,
const netclass_t*class_type,
perm_string method_name,
const std::vector<named_pexpr_t>*src_parms) const;
NetExpr* elaborate_expr_method_chained_(Design*des, NetScope*scope,
symbol_search_results&search_results) const;
NetExpr* elaborate_expr_chain_(Design*des, NetScope*scope, unsigned flags) const;
unsigned test_width_chain_(Design*des, NetScope*scope, width_mode_t&mode);
};
/*

View File

@ -257,17 +257,17 @@ class PCallTask : public Statement {
NetProc*elaborate_build_call_(Design*des, NetScope*scope,
NetScope*task, NetExpr*use_this) const;
NetProc*elaborate_sys_task_method_(Design*des, NetScope*scope,
NetNet*net,
NetExpr*base_expr,
perm_string method_name,
const char *sys_task_name,
const std::vector<perm_string> &parm_names = {}) const;
NetProc*elaborate_queue_method_(Design*des, NetScope*scope,
NetNet*net,
NetExpr*queue_base,
perm_string method_name,
const char *sys_task_name,
const std::vector<perm_string> &parm_names) const;
NetProc*elaborate_method_func_(NetScope*scope,
NetNet*net,
NetExpr*queue_base,
ivl_type_t type,
perm_string method_name,
const char*sys_task_name) const;

72
devel/sv_call_chain.md Normal file
View File

@ -0,0 +1,72 @@
# SystemVerilog chained calls: `a().b()`
This note describes the parser and elaboration support for **chained calls**: a
function call whose value is a class handle, followed by one or more
`.method(args)` segments (e.g. `get_c().f()`, `a().b().c()`).
## Language shape
- **Parse:** A dedicated nonterminal `call_chain_expr` in `parse.y` builds a
left-associated chain:
- `hierarchy_identifier attribute_list_opt argument_list_parens` — first call;
- `call_chain_expr '.' hierarchy_identifier attribute_list_opt argument_list_parens` — each further segment.
- **`expr_primary`** includes `call_chain_expr` **before** the bare
`hierarchy_identifier` alternative so `id (` is parsed as a call, not as an
identifier plus a stray `(`.
## Parse tree (`PExpr`)
- **`PECallFunction`** (`PExpr.h` / `PExpr.cc`):
- Optional **`chain_prefix_`**: inner `PExpr` for the prefix (another
`PECallFunction` for longer chains).
- Constructors and accessors: `peek_path()`, `peek_chain_prefix()`.
- **`pform_make_chained_call_function`** (`pform.cc`) — requires SystemVerilog;
builds `PECallFunction(prefix, method_name, args)`.
## Elaboration (`elab_expr.cc`)
- **`PECallFunction::elaborate_expr_`** delegates to **`elaborate_expr_chain_`**
when `chain_prefix_` is set.
- **`elaborate_class_method_net_this_`** passes the elaborated prefix as the
implicit `this` argument (first parameter slot), including nested `NetEUFunc`
for inner calls — not only `NetESignal(net)`.
- **`resolve_call_chain_prefix_class`** (static helper) resolves the **class
type** of the prefix for multi-hop chains (e.g. width checks), walking the
chain prefix recursively instead of searching only the tail name.
## Dump / debug
- **`pform_dump.cc`** prints chained calls with a `prefix.` prefix before the
method path.
## Regression
- **`ivtest/ivltests/sv_call_chain_method1.v`**
- **`ivtest/vvp_tests/sv_call_chain_method1.json`** (`-g2012`)
- Listed in **`ivtest/regress-vvp.list`** as `sv_call_chain_method1`.
## Using a locally built `iverilog`
`iverilog` invokes the installed compiler under your prefix, typically
`$PREFIX/lib/ivl/ivl`, not the `ivl` binary in the build tree. After changing
the parser, **reinstall** or copy the new `ivl` into that lib directory so
`iverilog` picks up the change; otherwise chained-call syntax may still fail
with a **syntax error** while a direct `./ivl -C...` test from the build tree
succeeds.
```bash
# Example after building in-tree
make install
# or copy only the compiler binary to your existing install
cp ivl "$PREFIX/lib/ivl/ivl"
```
## Related files (non-exhaustive)
| Area | Files |
|------------|--------|
| Grammar | `parse.y` (`call_chain_expr`, `expr_primary`) |
| Parse form | `pform.cc`, `pform.h` |
| AST | `PExpr.h`, `PExpr.cc` |
| Elab | `elab_expr.cc` |
| Dump | `pform_dump.cc` |

View File

@ -235,7 +235,9 @@ NetESelect* NetESelect::dup_expr() const
NetESFunc* NetESFunc::dup_expr() const
{
NetESFunc*tmp = new NetESFunc(name_, type_, expr_width(), nparms(), is_overridden_);
NetESFunc*tmp = net_type()
? new NetESFunc(name_, net_type(), nparms())
: new NetESFunc(name_, type_, expr_width(), nparms(), is_overridden_);
ivl_assert(*this, tmp);
tmp->cast_signed(has_sign());

File diff suppressed because it is too large Load Diff

View File

@ -397,11 +397,6 @@ void netclass_t::elaborate_sig(Design*des, PClass*pclass)
<< " type=" << *use_type << endl;
}
if (dynamic_cast<const netqueue_t *> (use_type)) {
cerr << cur->second.get_fileline() << ": sorry: "
<< "Queues inside classes are not yet supported." << endl;
des->errors++;
}
set_property(cur->first, cur->second.qual, use_type);
if (! cur->second.qual.test_static())

View File

@ -47,6 +47,7 @@
# include "netenum.h"
# include "netvector.h"
# include "netdarray.h"
# include "netqueue.h"
# include "netparray.h"
# include "netscalar.h"
# include "netclass.h"
@ -3683,22 +3684,30 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
* sys_task_name is the internal system-task name to use.
*/
NetProc* PCallTask::elaborate_sys_task_method_(Design*des, NetScope*scope,
NetNet*net,
NetExpr*base_expr,
perm_string method_name,
const char *sys_task_name,
const std::vector<perm_string> &parm_names) const
{
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
base_expr->set_line(*this);
unsigned nparms = parms_.size();
vector<NetExpr*>argv (1 + nparms);
argv[0] = sig;
argv[0] = base_expr;
if (method_name == "delete") {
// The queue delete method takes an optional element.
if (net->queue_type()) {
bool is_queue = false;
if (const NetESignal*ns = dynamic_cast<const NetESignal*>(base_expr)) {
is_queue = ns->sig()->queue_type() != 0;
} else if (const NetEProperty*np = dynamic_cast<const NetEProperty*>(base_expr)) {
const netclass_t*ct = dynamic_cast<const netclass_t*>(np->get_sig()->net_type());
ivl_assert(*this, ct);
ivl_type_t pt = ct->get_prop_type(np->property_idx());
is_queue = pt && pt->base_type() == IVL_VT_QUEUE;
}
if (is_queue) {
if (nparms > 1) {
cerr << get_fileline() << ": error: queue delete() "
<< "method takes zero or one argument." << endl;
@ -3732,13 +3741,25 @@ NetProc* PCallTask::elaborate_sys_task_method_(Design*des, NetScope*scope,
* sys_task_name is the internal system-task name to use.
*/
NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope,
NetNet*net,
NetExpr*queue_base,
perm_string method_name,
const char *sys_task_name,
const std::vector<perm_string> &parm_names) const
{
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
queue_base->set_line(*this);
const netdarray_t*use_darray = 0;
if (const NetESignal*ns = dynamic_cast<const NetESignal*>(queue_base)) {
use_darray = ns->sig()->darray_type();
} else if (const NetEProperty*np = dynamic_cast<const NetEProperty*>(queue_base)) {
const netclass_t*ct = dynamic_cast<const netclass_t*>(np->get_sig()->net_type());
ivl_assert(*this, ct);
ivl_type_t pt = ct->get_prop_type(np->property_idx());
use_darray = dynamic_cast<const netdarray_t*>(pt);
ivl_assert(*this, use_darray);
} else {
ivl_assert(*this, 0);
}
unsigned nparms = parms_.size();
// insert() requires two arguments.
@ -3755,19 +3776,19 @@ NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope,
}
// Get the context width if this is a logic type.
ivl_variable_type_t base_type = net->darray_type()->element_base_type();
ivl_variable_type_t base_type = use_darray->element_base_type();
int context_width = -1;
switch (base_type) {
case IVL_VT_BOOL:
case IVL_VT_LOGIC:
context_width = net->darray_type()->element_width();
context_width = use_darray->element_width();
break;
default:
break;
}
vector<NetExpr*>argv (nparms+1);
argv[0] = sig;
argv[0] = queue_base;
auto args = map_named_args(des, parm_names, parms_);
if (method_name != "insert") {
@ -3811,7 +3832,7 @@ NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope,
* This is used for array/queue function methods called as tasks.
*/
NetProc* PCallTask::elaborate_method_func_(NetScope*scope,
NetNet*net,
NetExpr*queue_base,
ivl_type_t type,
perm_string method_name,
const char*sys_task_name) const
@ -3824,9 +3845,8 @@ NetProc* PCallTask::elaborate_method_func_(NetScope*scope,
// Generate the function.
NetESFunc*sys_expr = new NetESFunc(sys_task_name, type, 1);
sys_expr->set_line(*this);
NetESignal*arg = new NetESignal(net);
arg->set_line(*net);
sys_expr->parm(0, arg);
queue_base->set_line(*this);
sys_expr->parm(0, queue_base);
// Create a L-value that matches the function return type.
NetNet*tmp;
tmp = new NetNet(scope, scope->local_symbol(), NetNet::REG, type);
@ -3886,46 +3906,179 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
<< net->name() << ".data_type() --> " << net->data_type() << endl;
}
// Class handle with one path_tail component: queue/darray property method
// e.g. c.q.push_back(x) => sr.path_tail = {q}, method_name = push_back
if (sr.path_tail.size() == 1) {
const netclass_t*cls = dynamic_cast<const netclass_t*>(sr.type);
if (!cls && net->net_type())
cls = dynamic_cast<const netclass_t*>(net->net_type());
if (cls) {
perm_string prop_name = sr.path_tail.front().name;
int pidx = cls->property_idx_from_name(prop_name);
if (pidx >= 0) {
ivl_type_t ptype = cls->get_prop_type(pidx);
if (ptype && dynamic_cast<const netqueue_t*>(ptype)) {
NetEProperty*prop = new NetEProperty(net, pidx, 0);
prop->set_line(*this);
const netdarray_t*use_darray = dynamic_cast<const netdarray_t*>(ptype);
ivl_assert(*this, use_darray);
if (method_name == "push_back") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("item")
};
return elaborate_queue_method_(des, scope, prop, method_name,
"$ivl_queue_method$push_back",
parm_names);
}
if (method_name == "push_front") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("item")
};
return elaborate_queue_method_(des, scope, prop, method_name,
"$ivl_queue_method$push_front",
parm_names);
}
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, prop, method_name,
"$ivl_queue_method$insert",
parm_names);
}
if (method_name == "pop_front") {
return elaborate_method_func_(scope, prop,
use_darray->element_type(),
method_name,
"$ivl_queue_method$pop_front");
}
if (method_name == "pop_back") {
return elaborate_method_func_(scope, prop,
use_darray->element_type(),
method_name,
"$ivl_queue_method$pop_back");
}
if (method_name == "size") {
return elaborate_method_func_(scope, prop,
&netvector_t::atom2s32,
method_name, "$size");
}
if (method_name == "reverse") {
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_method_(des, scope, prop, method_name,
"$ivl_darray_method$reverse",
parm_names);
}
if (method_name == "sort") {
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_method_(des, scope, prop, method_name,
"$ivl_darray_method$sort",
parm_names);
}
if (method_name == "rsort") {
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_method_(des, scope, prop, method_name,
"$ivl_darray_method$rsort",
parm_names);
}
if (method_name == "shuffle") {
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_method_(des, scope, prop, method_name,
"$ivl_darray_method$shuffle",
parm_names);
}
} else if (ptype && ptype->base_type() == IVL_VT_DARRAY) {
NetEProperty*prop = new NetEProperty(net, pidx, 0);
prop->set_line(*this);
if (method_name == "delete") {
static const std::vector<perm_string> parm_names = {
perm_string::literal("index")
};
return elaborate_sys_task_method_(des, scope, prop, method_name,
"$ivl_darray_method$delete",
parm_names);
}
if (method_name == "size") {
return elaborate_method_func_(scope, prop,
&netvector_t::atom2s32,
method_name, "$size");
}
if (method_name == "reverse") {
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_method_(des, scope, prop, method_name,
"$ivl_darray_method$reverse",
parm_names);
}
if (method_name == "sort") {
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_method_(des, scope, prop, method_name,
"$ivl_darray_method$sort",
parm_names);
}
if (method_name == "rsort") {
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_method_(des, scope, prop, method_name,
"$ivl_darray_method$rsort",
parm_names);
}
if (method_name == "shuffle") {
static const std::vector<perm_string> parm_names;
return elaborate_sys_task_method_(des, scope, prop, method_name,
"$ivl_darray_method$shuffle",
parm_names);
}
}
}
}
}
// Is this a method of a "string" type?
if (dynamic_cast<const netstring_t*>(net->net_type())) {
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,
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
return elaborate_sys_task_method_(des, scope, sig, method_name,
"$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,
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
return elaborate_sys_task_method_(des, scope, sig, method_name,
"$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,
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
return elaborate_sys_task_method_(des, scope, sig, method_name,
"$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,
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
return elaborate_sys_task_method_(des, scope, sig, method_name,
"$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,
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
return elaborate_sys_task_method_(des, scope, sig, method_name,
"$ivl_string_method$realtoa",
parm_names);
}
@ -3937,50 +4090,59 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
static const std::vector<perm_string> parm_names = {
perm_string::literal("index")
};
return elaborate_sys_task_method_(des, scope, net, method_name,
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
return elaborate_sys_task_method_(des, scope, sig, method_name,
"$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,
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
return elaborate_method_func_(scope, sig,
&netvector_t::atom2s32,
method_name, "$size");
} else if (method_name == "reverse") {
cerr << get_fileline() << ": sorry: 'reverse()' "
"array sorting method is not currently supported."
<< endl;
des->errors += 1;
return 0;
} else if (method_name=="sort") {
cerr << get_fileline() << ": sorry: 'sort()' "
"array sorting method is not currently supported."
<< endl;
des->errors += 1;
return 0;
} else if (method_name=="rsort") {
cerr << get_fileline() << ": sorry: 'rsort()' "
"array sorting method is not currently supported."
<< endl;
des->errors += 1;
return 0;
} else if (method_name=="shuffle") {
cerr << get_fileline() << ": sorry: 'shuffle()' "
"array sorting method is not currently supported."
<< endl;
des->errors += 1;
return 0;
static const std::vector<perm_string> parm_names;
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
return elaborate_sys_task_method_(des, scope, sig, method_name,
"$ivl_darray_method$reverse",
parm_names);
} else if (method_name == "sort") {
static const std::vector<perm_string> parm_names;
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
return elaborate_sys_task_method_(des, scope, sig, method_name,
"$ivl_darray_method$sort",
parm_names);
} else if (method_name == "rsort") {
static const std::vector<perm_string> parm_names;
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
return elaborate_sys_task_method_(des, scope, sig, method_name,
"$ivl_darray_method$rsort",
parm_names);
} else if (method_name == "shuffle") {
static const std::vector<perm_string> parm_names;
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
return elaborate_sys_task_method_(des, scope, sig, method_name,
"$ivl_darray_method$shuffle",
parm_names);
}
}
if (net->queue_type()) {
const netdarray_t*use_darray = net->darray_type();
NetESignal*qs = new NetESignal(net);
qs->set_line(*this);
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,
return elaborate_queue_method_(des, scope, qs, method_name,
"$ivl_queue_method$push_back",
parm_names);
} else if (method_name == "push_front") {
@ -3988,7 +4150,7 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
perm_string::literal("item")
};
return elaborate_queue_method_(des, scope, net, method_name,
return elaborate_queue_method_(des, scope, qs, method_name,
"$ivl_queue_method$push_front",
parm_names);
} else if (method_name == "insert") {
@ -3997,16 +4159,16 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
perm_string::literal("item")
};
return elaborate_queue_method_(des, scope, net, method_name,
return elaborate_queue_method_(des, scope, qs, method_name,
"$ivl_queue_method$insert",
parm_names);
} else if (method_name == "pop_front") {
return elaborate_method_func_(scope, net,
return elaborate_method_func_(scope, qs,
use_darray->element_type(),
method_name,
"$ivl_queue_method$pop_front");
} else if (method_name == "pop_back") {
return elaborate_method_func_(scope, net,
return elaborate_method_func_(scope, qs,
use_darray->element_type(),
method_name,
"$ivl_queue_method$pop_back");

View File

@ -26,6 +26,7 @@
# include <cmath>
# include "netlist.h"
# include "netclass.h"
# include "ivl_assert.h"
# include "netmisc.h"
@ -2182,6 +2183,27 @@ static bool get_array_info(const NetExpr*arg, long dim,
left = range.get_msb();
right = range.get_lsb();
return false;
}
/* Class property (e.g. queue field): size is dynamic; defer to runtime
* instead of folding to all-X in evaluate_array_funcs_. */
if (const NetEProperty*prop = dynamic_cast<const NetEProperty*>(arg)) {
const NetNet*obj = prop->get_sig();
const netclass_t*cls = dynamic_cast<const netclass_t*>(obj->net_type());
if (cls == 0)
return true;
ivl_type_t ptype = cls->get_prop_type(prop->property_idx());
if (ptype == 0)
return true;
switch (ptype->base_type()) {
case IVL_VT_DARRAY:
case IVL_VT_QUEUE:
case IVL_VT_STRING:
defer = true;
return true;
default:
break;
}
return true;
}
/* The argument must be a signal that has enough dimensions. */
const NetESignal*esig = dynamic_cast<const NetESignal*>(arg);

View File

@ -2400,6 +2400,10 @@ extern int ivl_type_properties(ivl_type_t net);
extern const char* ivl_type_prop_name(ivl_type_t net, int idx);
extern ivl_type_t ivl_type_prop_type(ivl_type_t net, int idx);
/* Maximum element count for a queue type (0 = unbounded). Only valid
* when ivl_type_base(net) == IVL_VT_QUEUE. */
extern unsigned ivl_type_queue_max(ivl_type_t net);
#if defined(__MINGW32__) || defined (__CYGWIN__)
# define DLLEXPORT __declspec(dllexport)

View File

@ -23,7 +23,7 @@
./ivltests/always_comb_warn.v:32: warning: A for statement step must be a simple binary +/- to be synthesized in an always_comb process.
./ivltests/always_comb_warn.v:32: warning: System task ($display) cannot be synthesized in an always_comb process.
./ivltests/always_comb_warn.v:33: warning: System task ($display) cannot be synthesized in an always_comb process.
./ivltests/always_comb_warn.v:34: warning: Dynamic array delete method cannot be synthesized in an always_comb process.
./ivltests/always_comb_warn.v:34: warning: Dynamic array ordering/delete method cannot be synthesized in an always_comb process.
./ivltests/always_comb_warn.v:35: warning: System task ($display) cannot be synthesized in an always_comb process.
./ivltests/always_comb_warn.v:14: warning: An event (tevt) cannot be synthesized in an always_comb process.
./ivltests/always_comb_warn.v:13: warning: A non-integral variable (trl) cannot be synthesized in an always_comb process.

View File

@ -21,7 +21,7 @@
./ivltests/always_ff_warn.v:33: warning: A for statement step must be a simple binary +/- to be synthesized in an always_ff process.
./ivltests/always_ff_warn.v:33: warning: System task ($display) cannot be synthesized in an always_ff process.
./ivltests/always_ff_warn.v:34: warning: System task ($display) cannot be synthesized in an always_ff process.
./ivltests/always_ff_warn.v:35: warning: Dynamic array delete method cannot be synthesized in an always_ff process.
./ivltests/always_ff_warn.v:35: warning: Dynamic array ordering/delete method cannot be synthesized in an always_ff process.
./ivltests/always_ff_warn.v:36: warning: System task ($display) cannot be synthesized in an always_ff process.
./ivltests/always_ff_warn.v:15: warning: An event (tevt) cannot be synthesized in an always_ff process.
./ivltests/always_ff_warn.v:14: warning: A non-integral variable (trl) cannot be synthesized in an always_ff process.

View File

@ -21,7 +21,7 @@
./ivltests/always_latch_warn.v:32: warning: A for statement step must be a simple binary +/- to be synthesized in an always_latch process.
./ivltests/always_latch_warn.v:32: warning: System task ($display) cannot be synthesized in an always_latch process.
./ivltests/always_latch_warn.v:33: warning: System task ($display) cannot be synthesized in an always_latch process.
./ivltests/always_latch_warn.v:34: warning: Dynamic array delete method cannot be synthesized in an always_latch process.
./ivltests/always_latch_warn.v:34: warning: Dynamic array ordering/delete method cannot be synthesized in an always_latch process.
./ivltests/always_latch_warn.v:35: warning: System task ($display) cannot be synthesized in an always_latch process.
./ivltests/always_latch_warn.v:14: warning: An event (tevt) cannot be synthesized in an always_latch process.
./ivltests/always_latch_warn.v:13: warning: A non-integral variable (trl) cannot be synthesized in an always_latch process.

View File

@ -1,18 +1,5 @@
./ivltests/br1005.v:2: sorry: Queues inside classes are not yet supported.
./ivltests/br1005.v:15: error: Enable of unknown task ``a.q.push_back''.
./ivltests/br1005.v:16: error: Enable of unknown task ``a.q.push_back''.
./ivltests/br1005.v:17: error: Enable of unknown task ``a.q.push_back''.
./ivltests/br1005.v:18: error: Enable of unknown task ``a.q.push_back''.
./ivltests/br1005.v:19: sorry: Method name nesting is not supported yet.
./ivltests/br1005.v:19: : method path: q.pop_front
./ivltests/br1005.v:19: error: Object test.a has no method "q.pop_front(...)".
./ivltests/br1005.v:22: sorry: Method name nesting is not supported yet.
./ivltests/br1005.v:22: : method path: q.pop_front
./ivltests/br1005.v:22: error: Object test.a has no method "q.pop_front(...)".
./ivltests/br1005.v:25: sorry: Method name nesting is not supported yet.
./ivltests/br1005.v:25: : method path: q.pop_front
./ivltests/br1005.v:25: error: Object test.a has no method "q.pop_front(...)".
./ivltests/br1005.v:28: sorry: Method name nesting is not supported yet.
./ivltests/br1005.v:28: : method path: q.pop_front
./ivltests/br1005.v:28: error: Object test.a has no method "q.pop_front(...)".
9 error(s) during elaboration.
1
2
3
4
PASSED

View File

@ -0,0 +1,88 @@
SystemVerilog array locator methods (queues and dynamic arrays)
================================================================
This directory includes regression tests for IEEE 1800 locator methods
on unpacked queues (int q[$]) and dynamic arrays (int da[]):
find, find_index, find_first, find_first_index, find_last,
find_last_index, min, max, unique, unique_index,
sum/product (integral), reverse (ordering), sort/rsort/shuffle (ordering)
Behavior notes (LRM-oriented):
* Methods may use a value argument, e.g. q.find(2), or a predicate with
`with`, e.g. q.find() with (item == 2). A `with` clause must not be
combined with a method value argument.
* find_first, find_last, find_first_index, and find_last_index return a
queue with zero or one element; no match yields an empty queue (not a
scalar sentinel).
* min() and max() return queues containing all elements equal to the
selected extrema.
* sum() returns the scalar reduction sum of elements (integral vector types);
empty arrays/queues yield 0. `sum() with (expr)` reduces the expression
result for each item.
* product() returns the scalar reduction product of elements (integral
vector types).
`product() with (expr)` reduces the expression result for each item.
* reverse() reverses the order of elements in place for queues and dynamic
arrays (integral, vector, real, string, and class-handle elements as stored
by Icarus).
* sort() and rsort() order elements in ascending or descending order. Packed
vector elements use the same unsigned relational rules as min()/max().
Class-handle arrays use a stable implementation-defined order
(sort_order_key on vvp_object_t).
* shuffle() permutes elements randomly (std::mt19937); order is not portable
across runs.
* For dynamic arrays, runtime support treats storage as vvp_darray (including
atom-backed integral arrays), not only vvp_queue_vec4. See vvp/vthread.cc:
get_queue_or_darray_vec4_from_net() and the %queue/* opcodes used for
size, word read, find, and unique.
Compiler / codegen touchpoints (typical):
* Elaboration: elab_expr.cc — NetESFunc $ivl_queue_method$* and with-predicate
lowering.
* Code generation: tgt-vvp/eval_object.c — eval_queue_method_find,
eval_queue_method_find_with; eval_vec4.c for non-with find*;
tgt-vvp/vvp_process.c — ordering/delete as system tasks (`%sort/obj`, …).
* VVP: vvp/vthread.cc — opcode implementations; vvp/vvp_darray.{h,cc} —
sort_elems(), shuffle_elems(), reverse_elems(); vvp/compile.cc — opcode tables.
Regression tests (see ivtest/vvp_tests/*.json and regress-vvp.list):
sv_queue_find.v Value-argument find* (equality), empty cases.
sv_queue_find_with.v find* with `with` (item, index).
sv_queue_find_locators_ext.v Longer queue, compound predicates.
sv_queue_unique.v unique / unique_index.
sv_darray_find_locators.v Same locator patterns on int[] dynamic array.
sv_darray_unique.v unique() and unique_index() on int[] dynamic array.
sv_queue_min_max.v min() and max() on queue values.
sv_darray_min_max.v min() and max() on dynamic array values.
sv_queue_min_max_with.v min()/max() with predicate on queue values.
sv_darray_min_max_with.v min()/max() with predicate on dynamic arrays.
sv_class_darray_prop_locators.v locator methods on class dynamic-array properties
(including sum/product with expression).
sv_queue_unique_with.v unique()/unique_index() with predicate on queues.
sv_darray_unique_with.v unique()/unique_index() with predicate on dynamic arrays.
sv_class_queue_prop_locators.v locator methods on class queue properties
(including sum/product with expression).
sv_queue_product.v integral product() reduction on queues.
sv_darray_product.v integral product() reduction on dynamic arrays.
sv_queue_product_with.v product() with expression on queues.
sv_darray_product_with.v product() with expression on dynamic arrays.
sv_darray_reverse.v reverse() ordering on dynamic arrays.
sv_darray_sort.v sort(), rsort(), shuffle() on dynamic arrays.
sv_queue_reverse.v reverse() ordering on queues.
sv_queue_sort.v sort(), rsort(), shuffle() on queues.
sv_queue_sum.v integral sum() reduction on queues.
sv_darray_sum.v integral sum() reduction on dynamic arrays.
sv_queue_sum_with.v sum() with expression on queues.
sv_darray_sum_with.v sum() with expression on dynamic arrays.

View File

@ -0,0 +1,25 @@
// Chained call: function returns class handle, then method on result (a().b()).
module test;
class C;
function int f;
f = 7;
endfunction
endclass
function C get_c;
get_c = new;
endfunction
initial begin
int x;
x = get_c().f();
if (x !== 7) begin
$display("FAILED");
end else begin
$display("PASSED");
end
end
endmodule

View File

@ -0,0 +1,80 @@
// Regression: class dynamic-array property locator methods.
module test;
bit failed = 1'b0;
`define check(val, exp) do if ((val) !== (exp)) begin $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); failed = 1'b1; end while(0)
class C;
int d[];
endclass
C c;
int r[$];
initial begin
c = new;
c.d = '{4, 7, 2, 5, 7, 1, 6, 3, 1};
r = c.d.find() with (item > 3);
`check(r.size, 5);
`check(r[0], 4);
`check(r[4], 6);
r = c.d.find_first() with (item > 6);
`check(r.size, 1);
`check(r[0], 7);
r = c.d.find_last_index() with (item < 3);
`check(r.size, 1);
`check(r[0], 8);
r = c.d.unique();
`check(r.size, 7);
`check(r[0], 4);
r = c.d.unique_index();
`check(r.size, 7);
`check(r[0], 0);
r = c.d.unique() with (item > 2);
`check(r.size, 5);
`check(r[0], 4);
`check(r[4], 3);
r = c.d.unique_index() with (item > 2);
`check(r.size, 6);
`check(r[0], 0);
`check(r[5], 7);
r = c.d.min();
`check(r.size, 2);
`check(r[0], 1);
`check(r[1], 1);
r = c.d.max() with (item < 7);
`check(r.size, 1);
`check(r[0], 6);
c.d = '{2, 3, 4};
`check(c.d.product(), 24);
`check(c.d.sum() with (item + 1), 12);
`check(c.d.product() with (item + 1), 60);
c.d = '{1, 2, 3};
c.d.reverse();
`check(c.d[0], 3);
`check(c.d[1], 2);
`check(c.d[2], 1);
c.d = '{3, 1, 2};
c.d.sort();
`check(c.d[0], 1);
`check(c.d[1], 2);
`check(c.d[2], 3);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,72 @@
// Regression: class queue property locator methods.
module test;
bit failed = 1'b0;
`define check(val, exp) do if ((val) !== (exp)) begin $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); failed = 1'b1; end while (0)
class C;
int q[$];
endclass
C c;
int r[$];
initial begin
c = new;
c.q = '{4, 7, 2, 5, 7, 1, 6, 3, 1};
r = c.q.find() with (item > 3);
`check(r.size, 5);
`check(r[0], 4);
`check(r[4], 6);
r = c.q.find_last_index() with (item < 3);
`check(r.size, 1);
`check(r[0], 8);
r = c.q.unique() with (item > 2);
`check(r.size, 5);
`check(r[0], 4);
`check(r[4], 3);
r = c.q.unique_index() with (item > 2);
`check(r.size, 6);
`check(r[0], 0);
`check(r[5], 7);
r = c.q.min();
`check(r.size, 2);
`check(r[0], 1);
`check(r[1], 1);
r = c.q.max() with (item < 7);
`check(r.size, 1);
`check(r[0], 6);
r = c.q.max();
`check(r.size, 2);
`check(r[0], 7);
c.q = '{2, 3, 4};
`check(c.q.product(), 24);
`check(c.q.sum() with (item + 1), 12);
`check(c.q.product() with (item + 1), 60);
c.q = '{1, 2, 3};
c.q.reverse();
`check(c.q[0], 3);
`check(c.q[1], 2);
`check(c.q[2], 1);
c.q = '{3, 1, 2};
c.q.sort();
`check(c.q[0], 1);
`check(c.q[1], 2);
`check(c.q[2], 3);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,39 @@
// Regression: queue-typed class properties push_front/push_back and
// pop_front/pop_back. (VVP asm must recognize %store/prop/qf/* and
// %qpop/prop/*; opcode_table must stay lexicographically sorted.)
module test;
bit failed = 1'b0;
`define check(val, exp) do \
if (val !== exp) begin \
$display("FAILED(%0d). expected %0d, got %0d", `__LINE__, exp, val); \
failed = 1'b1; \
end \
while(0)
class C;
int q[$];
endclass
C c;
int t;
initial begin
c = new;
c.q.push_back(1);
c.q.push_front(0);
c.q.push_back(2);
t = c.q.pop_back();
`check(t, 32'd2);
`check(c.q.size(), 32'd2);
t = c.q.pop_front();
`check(t, 32'd0);
`check(c.q[0], 32'd1);
if (!failed) begin
$display("PASSED");
end
end
endmodule

View File

@ -0,0 +1,48 @@
// Regression: dynamic array locator methods (find* with predicate); results are queues.
module top;
bit failed = 0;
`define CHK(cond) \
if (!(cond)) begin \
$display("FAILED line %0d", `__LINE__); \
failed = 1; \
end
int array[] = '{4, 7, 2, 5, 7, 1, 6, 3, 1};
int res[$];
initial begin
res = array.find() with (item > 3);
`CHK(res.size == 5);
`CHK(res[0] == 4);
`CHK(res[1] == 7);
`CHK(res[2] == 5);
`CHK(res[3] == 7);
`CHK(res[4] == 6);
res = array.find_index() with (item == 4);
`CHK(res.size == 1);
`CHK(res[0] == 0);
res = array.find_first() with (item < 5 && item >= 3);
`CHK(res.size == 1);
`CHK(res[0] == 4);
res = array.find_first_index() with (item > 5);
`CHK(res.size == 1);
`CHK(res[0] == 1);
res = array.find_last() with (item <= 7 && item > 3);
`CHK(res.size == 1);
`CHK(res[0] == 6);
res = array.find_last_index() with (item < 3);
`CHK(res.size == 1);
`CHK(res[0] == 8);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,36 @@
// Regression: dynamic array min() and max() locator methods return queues.
module top;
bit failed = 0;
`define CHK(cond) \
if (!(cond)) begin \
$display("FAILED line %0d", `__LINE__); \
failed = 1; \
end
int a[] = '{4, 7, 2, 5, 7, 1, 6, 3, 1};
int empty[];
int r[$];
initial begin
r = a.min();
`CHK(r.size == 2);
`CHK(r[0] == 1);
`CHK(r[1] == 1);
r = a.max();
`CHK(r.size == 2);
`CHK(r[0] == 7);
`CHK(r[1] == 7);
r = empty.min();
`CHK(r.size == 0);
r = empty.max();
`CHK(r.size == 0);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,30 @@
// Regression: dynamic array min/max with(predicate) locator methods.
module top;
bit failed = 0;
`define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end
int a[] = '{4, 7, 2, 5, 7, 1, 6, 3, 1};
int r[$];
initial begin
r = a.min() with (item > 3);
`CHK(r.size == 1);
`CHK(r[0] == 4);
r = a.max() with (item < 7);
`CHK(r.size == 1);
`CHK(r[0] == 6);
r = a.min() with (item > 99);
`CHK(r.size == 0);
r = a.max() with (item > 99);
`CHK(r.size == 0);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,24 @@
// Regression: dynamic array product() reduction (integral).
module top;
bit failed = 0;
`define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end
int a[];
int p;
initial begin
a = '{2, 3, 4};
p = a.product();
`CHK(p === 24);
a = '{-2, 3, 5};
p = a.product();
`CHK(p === -30);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,24 @@
// Regression: dynamic array product() reduction with expression.
module top;
bit failed = 0;
`define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end
int a[];
int p;
initial begin
a = '{10, -3, 5};
p = a.product() with (item > 0);
`CHK(p === 0);
p = a.product() with (item + 1);
`CHK(p === -132);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,32 @@
// Regression: dynamic array reverse() ordering method.
module top;
bit failed = 0;
`define CHK(cond) \
if (!(cond)) begin \
$display("FAILED line %0d", `__LINE__); \
failed = 1; \
end
int a[];
initial begin
a = '{1, 2, 3, 4};
a.reverse();
`CHK(a[0] === 4 && a[1] === 3 && a[2] === 2 && a[3] === 1);
a = new [1];
a[0] = 42;
a.reverse();
`CHK(a[0] === 42);
a = new [0];
a.reverse();
`CHK(a.size() === 0);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,33 @@
// Regression: dynamic array sort(), rsort(), shuffle().
module top;
bit failed = 0;
`define CHK(cond) \
if (!(cond)) begin \
$display("FAILED line %0d", `__LINE__); \
failed = 1; \
end
int a[];
int sum0;
initial begin
a = '{3, 1, 4, 1, 5};
a.sort();
`CHK(a[0] === 1 && a[1] === 1 && a[2] === 3 && a[3] === 4 && a[4] === 5);
a = '{3, 1, 4};
a.rsort();
`CHK(a[0] === 4 && a[1] === 3 && a[2] === 1);
a = '{10, -2, 7};
sum0 = a.sum();
a.shuffle();
`CHK(a.sum() === sum0);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,28 @@
// Regression: dynamic array sum() reduction (integral).
module top;
bit failed = 0;
`define CHK(cond) \
if (!(cond)) begin \
$display("FAILED line %0d", `__LINE__); \
failed = 1; \
end
int a[];
int s;
initial begin
a = new[0];
s = a.sum();
`CHK(s === 0);
a = '{10, -3, 5};
s = a.sum();
`CHK(s === 12);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,24 @@
// Regression: dynamic array sum() reduction with expression.
module top;
bit failed = 0;
`define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end
int a[];
int s;
initial begin
a = '{10, -3, 5};
s = a.sum() with (item > 0);
`CHK(s === 2);
s = a.sum() with (item + 1);
`CHK(s === 15);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,29 @@
// Regression: dynamic array unique() and unique_index().
module top;
bit failed = 0;
`define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end
int a[] = '{1, 2, 1, 3, 2};
int u[$];
int ix[$];
initial begin
u = a.unique();
`CHK(u.size == 3);
`CHK(u[0] == 1);
`CHK(u[1] == 2);
`CHK(u[2] == 3);
ix = a.unique_index();
`CHK(ix.size == 3);
`CHK(ix[0] == 0);
`CHK(ix[1] == 1);
`CHK(ix[2] == 3);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,33 @@
// Regression: dynamic array unique()/unique_index() with predicate.
module top;
bit failed = 0;
`define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end
int a[] = '{4, 7, 2, 5, 7, 1, 6, 3, 1};
int r[$];
initial begin
r = a.unique() with (item > 2);
`CHK(r.size == 5);
`CHK(r[0] == 4);
`CHK(r[1] == 7);
`CHK(r[2] == 5);
`CHK(r[3] == 6);
`CHK(r[4] == 3);
r = a.unique_index() with (item > 2);
`CHK(r.size == 6);
`CHK(r[0] == 0);
`CHK(r[1] == 1);
`CHK(r[2] == 3);
`CHK(r[3] == 4);
`CHK(r[4] == 6);
`CHK(r[5] == 7);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,60 @@
// Regression: queue find* locator methods (one argument: value matched with ==).
module top;
bit failed = 0;
`define CHK(cond) \
if (!(cond)) begin \
$display("FAILED line %0d", `__LINE__); \
failed = 1; \
end
int q[$];
int f[$];
int ix[$];
int ff[$];
int fi[$];
int lf[$];
int li[$];
initial begin
q.delete();
q.push_back(2);
q.push_back(1);
q.push_back(2);
q.push_back(3);
f = q.find(2);
`CHK(f.size == 2);
`CHK(f[0] == 2);
`CHK(f[1] == 2);
ix = q.find_index(2);
`CHK(ix.size == 2);
`CHK(ix[0] == 0);
`CHK(ix[1] == 2);
ff = q.find_first(3);
`CHK(ff.size == 1);
`CHK(ff[0] == 3);
fi = q.find_first_index(3);
`CHK(fi.size == 1);
`CHK(fi[0] == 3);
lf = q.find_last(2);
`CHK(lf.size == 1);
`CHK(lf[0] == 2);
li = q.find_last_index(2);
`CHK(li.size == 1);
`CHK(li[0] == 2);
ff = q.find_first(99);
`CHK(ff.size == 0);
fi = q.find_first_index(99);
`CHK(fi.size == 0);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,59 @@
// Regression: queue locator methods with `with` compound predicates and longer sequences.
module top;
bit failed = 0;
`define CHK(cond) \
if (!(cond)) begin \
$display("FAILED line %0d", `__LINE__); \
failed = 1; \
end
int q[$];
int res[$];
initial begin
q.delete();
q.push_back(4);
q.push_back(7);
q.push_back(2);
q.push_back(5);
q.push_back(7);
q.push_back(1);
q.push_back(6);
q.push_back(3);
q.push_back(1);
res = q.find() with (item > 3);
`CHK(res.size == 5);
`CHK(res[0] == 4);
`CHK(res[1] == 7);
`CHK(res[2] == 5);
`CHK(res[3] == 7);
`CHK(res[4] == 6);
res = q.find_index() with (item == 4);
`CHK(res.size == 1);
`CHK(res[0] == 0);
res = q.find_first() with (item < 5 && item >= 3);
`CHK(res.size == 1);
`CHK(res[0] == 4);
res = q.find_first_index() with (item > 5);
`CHK(res.size == 1);
`CHK(res[0] == 1);
res = q.find_last() with (item <= 7 && item > 3);
`CHK(res.size == 1);
`CHK(res[0] == 6);
res = q.find_last_index() with (item < 3);
`CHK(res.size == 1);
`CHK(res[0] == 8);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,66 @@
// Regression: queue find* locator methods with `with (predicate)` (item, index).
module top;
bit failed = 0;
`define CHK(cond) \
if (!(cond)) begin \
$display("FAILED line %0d", `__LINE__); \
failed = 1; \
end
int q[$];
int f[$];
int ix[$];
int ff[$];
int fi[$];
int lf[$];
int li[$];
initial begin
q.delete();
q.push_back(2);
q.push_back(1);
q.push_back(2);
q.push_back(3);
f = q.find() with (item == 2);
`CHK(f.size == 2);
`CHK(f[0] == 2);
`CHK(f[1] == 2);
ix = q.find_index() with (item == 2);
`CHK(ix.size == 2);
`CHK(ix[0] == 0);
`CHK(ix[1] == 2);
ix = q.find_index() with (index > 0);
`CHK(ix.size == 3);
`CHK(ix[0] == 1);
`CHK(ix[1] == 2);
`CHK(ix[2] == 3);
ff = q.find_first() with (item == 3);
`CHK(ff.size == 1);
`CHK(ff[0] == 3);
fi = q.find_first_index() with (item == 2 && index > 0);
`CHK(fi.size == 1);
`CHK(fi[0] == 2);
lf = q.find_last() with (item < 3);
`CHK(lf.size == 1);
`CHK(lf[0] == 2);
li = q.find_last_index() with (item == 2);
`CHK(li.size == 1);
`CHK(li[0] == 2);
ff = q.find_first() with (item == 99);
`CHK(ff.size == 0);
fi = q.find_first_index() with (item == 99);
`CHK(fi.size == 0);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,47 @@
// Regression: queue min() and max() locator methods return queues.
module top;
bit failed = 0;
`define CHK(cond) \
if (!(cond)) begin \
$display("FAILED line %0d", `__LINE__); \
failed = 1; \
end
int q[$];
int e[$];
int r[$];
initial begin
q.delete();
q.push_back(4);
q.push_back(7);
q.push_back(2);
q.push_back(5);
q.push_back(7);
q.push_back(1);
q.push_back(6);
q.push_back(3);
q.push_back(1);
r = q.min();
`CHK(r.size == 2);
`CHK(r[0] == 1);
`CHK(r[1] == 1);
r = q.max();
`CHK(r.size == 2);
`CHK(r[0] == 7);
`CHK(r[1] == 7);
r = e.min();
`CHK(r.size == 0);
r = e.max();
`CHK(r.size == 0);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,41 @@
// Regression: queue min/max with(predicate) locator methods.
module top;
bit failed = 0;
`define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end
int q[$];
int r[$];
initial begin
q.delete();
q.push_back(4);
q.push_back(7);
q.push_back(2);
q.push_back(5);
q.push_back(7);
q.push_back(1);
q.push_back(6);
q.push_back(3);
q.push_back(1);
r = q.min() with (item > 3);
`CHK(r.size == 1);
`CHK(r[0] == 4);
r = q.max() with (item < 7);
`CHK(r.size == 1);
`CHK(r[0] == 6);
r = q.min() with (item > 99);
`CHK(r.size == 0);
r = q.max() with (item > 99);
`CHK(r.size == 0);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,24 @@
// Regression: queue product() reduction (integral).
module top;
bit failed = 0;
`define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end
int q[$];
int p;
initial begin
q = '{2, 3, 4};
p = q.product();
`CHK(p === 24);
q = '{-2, 3, 5};
p = q.product();
`CHK(p === -30);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,24 @@
// Regression: queue product() reduction with expression.
module top;
bit failed = 0;
`define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end
int q[$];
int p;
initial begin
q = '{4, 7, 2};
p = q.product() with (item > 3);
`CHK(p === 0);
p = q.product() with (item + 1);
`CHK(p === 120);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,31 @@
// Regression: queue reverse() ordering method.
module top;
bit failed = 0;
`define CHK(cond) \
if (!(cond)) begin \
$display("FAILED line %0d", `__LINE__); \
failed = 1; \
end
int q[$];
initial begin
q = '{1, 2, 3, 4};
q.reverse();
`CHK(q[0] === 4 && q[1] === 3 && q[2] === 2 && q[3] === 1);
q = '{99};
q.reverse();
`CHK(q[0] === 99);
q.delete();
q.reverse();
`CHK(q.size() === 0);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,33 @@
// Regression: queue sort(), rsort(), shuffle().
module top;
bit failed = 0;
`define CHK(cond) \
if (!(cond)) begin \
$display("FAILED line %0d", `__LINE__); \
failed = 1; \
end
int q[$];
int sum0;
initial begin
q = '{3, 1, 4, 1, 5};
q.sort();
`CHK(q[0] === 1 && q[1] === 1 && q[2] === 3 && q[3] === 4 && q[4] === 5);
q = '{3, 1, 4};
q.rsort();
`CHK(q[0] === 4 && q[1] === 3 && q[2] === 1);
q = '{10, -2, 7};
sum0 = q.sum();
q.shuffle();
`CHK(q.sum() === sum0);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,28 @@
// Regression: queue sum() reduction (integral).
module top;
bit failed = 0;
`define CHK(cond) \
if (!(cond)) begin \
$display("FAILED line %0d", `__LINE__); \
failed = 1; \
end
int q[$];
int s;
initial begin
q = '{};
s = q.sum();
`CHK(s === 0);
q = '{4, 7, 2};
s = q.sum();
`CHK(s === 13);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,24 @@
// Regression: queue sum() reduction with expression.
module top;
bit failed = 0;
`define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end
int q[$];
int s;
initial begin
q = '{4, 7, 2, 5};
s = q.sum() with (item > 3);
`CHK(s === 3);
s = q.sum() with (item * 2);
`CHK(s === 36);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,40 @@
// Regression: queue unique() and unique_index() for integral packed queues.
module top;
bit failed = 0;
`define CHK(cond) \
if (!(cond)) begin \
$display("FAILED line %0d", `__LINE__); \
failed = 1; \
end
int q[$];
int u[$];
int ix[$];
initial begin
q.delete();
q.push_back(1);
q.push_back(2);
q.push_back(1);
q.push_back(3);
q.push_back(2);
u = q.unique();
`CHK(u.size == 3);
`CHK(u[0] == 1);
`CHK(u[1] == 2);
`CHK(u[2] == 3);
ix = q.unique_index();
`CHK(ix.size == 3);
`CHK(ix[0] == 0);
`CHK(ix[1] == 1);
`CHK(ix[2] == 3);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,35 @@
// Regression: queue unique()/unique_index() with predicate.
module top;
bit failed = 0;
`define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end
int q[$];
int r[$];
initial begin
q = '{4, 7, 2, 5, 7, 1, 6, 3, 1};
r = q.unique() with (item > 2);
`CHK(r.size == 5);
`CHK(r[0] == 4);
`CHK(r[1] == 7);
`CHK(r[2] == 5);
`CHK(r[3] == 6);
`CHK(r[4] == 3);
r = q.unique_index() with (item > 2);
`CHK(r.size == 6);
`CHK(r[0] == 0);
`CHK(r[1] == 1);
`CHK(r[2] == 3);
`CHK(r[3] == 4);
`CHK(r[4] == 6);
`CHK(r[5] == 7);
if (!failed)
$display("PASSED");
end
endmodule

View File

@ -274,7 +274,6 @@ array_lval_select3a CE ivltests
br605a EF ivltests
br605b EF ivltests
br971 EF ivltests
br1005 CE,-g2009 ivltests
br1015b CE,-g2009 ivltests
br_ml20150315b CE,-g2009 ivltests
sv_deferred_assert1 CE,-g2009 ivltests gold=sv_deferred_assert1.gold

View File

@ -360,6 +360,7 @@ unp_array_typedef CE,-g2009,-pallowsigned=1 ivltests # Also string
br959 CE,-g2009 ivltests
br1003a CE,-g2009 ivltests
br1004 CE,-g2009 ivltests
br1005 CE,-g2009 ivltests
br_gh104a CE,-g2009 ivltests
br_gh167a CE,-g2009 ivltests
br_gh167b CE,-g2009 ivltests

View File

@ -224,6 +224,7 @@ sv_array_cassign6 vvp_tests/sv_array_cassign6.json
sv_array_cassign7 vvp_tests/sv_array_cassign7.json
sv_array_cassign8 vvp_tests/sv_array_cassign8.json
sv_automatic_2state vvp_tests/sv_automatic_2state.json
sv_call_chain_method1 vvp_tests/sv_call_chain_method1.json
sv_chained_constructor1 vvp_tests/sv_chained_constructor1.json
sv_chained_constructor2 vvp_tests/sv_chained_constructor2.json
sv_chained_constructor3 vvp_tests/sv_chained_constructor3.json
@ -232,11 +233,14 @@ sv_chained_constructor5 vvp_tests/sv_chained_constructor5.json
sv_class_prop_assign_op1 vvp_tests/sv_class_prop_assign_op1.json
sv_class_prop_assign_op2 vvp_tests/sv_class_prop_assign_op2.json
sv_class_prop_logic vvp_tests/sv_class_prop_logic.json
sv_class_darray_prop_locators vvp_tests/sv_class_darray_prop_locators.json
sv_class_queue_prop_locators vvp_tests/sv_class_queue_prop_locators.json
sv_class_prop_nest_darray1 vvp_tests/sv_class_prop_nest_darray1.json
sv_class_prop_nest_obj1 vvp_tests/sv_class_prop_nest_obj1.json
sv_class_prop_nest_real1 vvp_tests/sv_class_prop_nest_str1.json
sv_class_prop_nest_str1 vvp_tests/sv_class_prop_nest_real1.json
sv_class_prop_nest_vec1 vvp_tests/sv_class_prop_nest_vec1.json
sv_class_queue_prop_methods vvp_tests/sv_class_queue_prop_methods.json
sv_const1 vvp_tests/sv_const1.json
sv_const2 vvp_tests/sv_const2.json
sv_const3 vvp_tests/sv_const3.json
@ -252,6 +256,17 @@ sv_const_fail7 vvp_tests/sv_const_fail7.json
sv_const_fail8 vvp_tests/sv_const_fail8.json
sv_const_fail9 vvp_tests/sv_const_fail9.json
sv_darray_assign_op vvp_tests/sv_darray_assign_op.json
sv_darray_find_locators vvp_tests/sv_darray_find_locators.json
sv_darray_min_max vvp_tests/sv_darray_min_max.json
sv_darray_min_max_with vvp_tests/sv_darray_min_max_with.json
sv_darray_product vvp_tests/sv_darray_product.json
sv_darray_product_with vvp_tests/sv_darray_product_with.json
sv_darray_reverse vvp_tests/sv_darray_reverse.json
sv_darray_sort vvp_tests/sv_darray_sort.json
sv_darray_sum vvp_tests/sv_darray_sum.json
sv_darray_sum_with vvp_tests/sv_darray_sum_with.json
sv_darray_unique vvp_tests/sv_darray_unique.json
sv_darray_unique_with vvp_tests/sv_darray_unique_with.json
sv_default_port_value1 vvp_tests/sv_default_port_value1.json
sv_default_port_value2 vvp_tests/sv_default_port_value2.json
sv_default_port_value3 vvp_tests/sv_default_port_value3.json
@ -271,6 +286,18 @@ sv_module_port3 vvp_tests/sv_module_port3.json
sv_module_port4 vvp_tests/sv_module_port4.json
sv_parameter_type vvp_tests/sv_parameter_type.json
sv_queue_assign_op vvp_tests/sv_queue_assign_op.json
sv_queue_unique vvp_tests/sv_queue_unique.json
sv_queue_find vvp_tests/sv_queue_find.json
sv_queue_find_locators_ext vvp_tests/sv_queue_find_locators_ext.json
sv_queue_find_with vvp_tests/sv_queue_find_with.json
sv_queue_min_max vvp_tests/sv_queue_min_max.json
sv_queue_min_max_with vvp_tests/sv_queue_min_max_with.json
sv_queue_product vvp_tests/sv_queue_product.json
sv_queue_product_with vvp_tests/sv_queue_product_with.json
sv_queue_reverse vvp_tests/sv_queue_reverse.json
sv_queue_sort vvp_tests/sv_queue_sort.json
sv_queue_sum vvp_tests/sv_queue_sum.json
sv_queue_sum_with vvp_tests/sv_queue_sum_with.json
sv_wildcard_import8 vvp_tests/sv_wildcard_import8.json
sdf_header vvp_tests/sdf_header.json
task_return1 vvp_tests/task_return1.json

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_call_chain_method1.v",
"iverilog-args" : [ "-g2012" ],
"vlog95" : {
"__comment" : "Classes are not supported",
"type" : "CE"
}
}

View File

@ -0,0 +1,10 @@
{
"type" : "normal",
"source" : "sv_class_darray_prop_locators.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "Classes/dynamic arrays are not supported",
"type" : "CE",
"iverilog-args" : [ "-pallowsigned=1" ]
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_class_queue_prop_locators.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog class queue property locator methods",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_class_queue_prop_methods.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "Classes are not supported",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_darray_find_locators.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog dynamic array locator methods",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_darray_min_max.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog dynamic array min/max locator methods",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_darray_min_max_with.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog dynamic array min/max with predicate",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_darray_product.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog dynamic array product() reduction",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_darray_product_with.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog dynamic array product() with expression",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_darray_reverse.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog dynamic array reverse()",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_darray_sort.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog dynamic array sort/rsort/shuffle",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_darray_sum.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog dynamic array sum() reduction",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_darray_sum_with.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog dynamic array sum() with expression",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_darray_unique.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog dynamic array unique methods",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_darray_unique_with.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog darray unique with predicate",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_queue_find.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog queues",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_queue_find_locators_ext.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog queue locator methods",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_queue_find_with.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog queues",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_queue_min_max.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog queue min/max locator methods",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_queue_min_max_with.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog queue min/max with predicate",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_queue_product.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog queue product() reduction",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_queue_product_with.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog queue product() with expression",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_queue_reverse.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog queue reverse()",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_queue_sort.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog queue sort/rsort/shuffle",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_queue_sum.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog queue sum() reduction",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_queue_sum_with.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog queue sum() with expression",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_queue_unique.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog queues",
"type" : "CE"
}
}

View File

@ -0,0 +1,9 @@
{
"type" : "normal",
"source" : "sv_queue_unique_with.v",
"iverilog-args" : [ "-g2005-sv" ],
"vlog95" : {
"__comment" : "SystemVerilog queue unique with predicate",
"type" : "CE"
}
}

View File

@ -39,11 +39,22 @@ ivl_variable_type_t netdarray_t::base_type(void) const
bool netdarray_t::test_equivalence(ivl_type_t that) const
{
// Queues and dynamic arrays are not equivalent, so check for the base
// type to make sure both are either dynamic array or queue.
if (base_type() != that->base_type())
const netdarray_t* that_da = dynamic_cast<const netdarray_t*>(that);
if (!that_da)
return false;
/* Queue vs unpacked dynamic array: same element type is assignable
* (e.g. int[$] = array.find_first(...), locator return is a queue). */
if (base_type() != that->base_type()) {
if ((base_type() == IVL_VT_QUEUE &&
that->base_type() == IVL_VT_DARRAY) ||
(base_type() == IVL_VT_DARRAY &&
that->base_type() == IVL_VT_QUEUE)) {
return element_type()->type_equivalent(that_da->element_type());
}
return false;
}
return test_compatibility(that);
}

View File

@ -3454,9 +3454,13 @@ bool NetScope::check_synth(ivl_process_type_t pr_type,
bool NetSTask::check_synth(ivl_process_type_t pr_type,
const NetScope* /* scope */) const
{
if (strcmp(name(), "$ivl_darray_method$delete") == 0) {
if (strcmp(name(), "$ivl_darray_method$delete") == 0 ||
strcmp(name(), "$ivl_darray_method$reverse") == 0 ||
strcmp(name(), "$ivl_darray_method$sort") == 0 ||
strcmp(name(), "$ivl_darray_method$rsort") == 0 ||
strcmp(name(), "$ivl_darray_method$shuffle") == 0) {
cerr << get_fileline() << ": warning: Dynamic array "
"delete method cannot be synthesized "
"ordering/delete method cannot be synthesized "
<< get_process_type_as_string(pr_type) << endl;
} else {
cerr << get_fileline() << ": warning: System task ("

View File

@ -890,32 +890,38 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
if (tmp == 0) return 0;
if ((cast_type != IVL_VT_NO_TYPE) && (cast_type != tmp->expr_type())) {
switch (tmp->expr_type()) {
case IVL_VT_BOOL:
case IVL_VT_LOGIC:
case IVL_VT_REAL:
break;
default:
cerr << tmp->get_fileline() << ": error: "
"The expression '" << *pe << "' cannot be implicitly "
"cast to the target type." << endl;
des->errors += 1;
delete tmp;
return 0;
}
switch (cast_type) {
case IVL_VT_REAL:
tmp = cast_to_real(tmp);
break;
case IVL_VT_BOOL:
tmp = cast_to_int2(tmp, pos_context_width);
break;
case IVL_VT_LOGIC:
tmp = cast_to_int4(tmp, pos_context_width);
break;
default:
break;
}
bool qdar_mix =
(cast_type == IVL_VT_QUEUE || cast_type == IVL_VT_DARRAY) &&
(tmp->expr_type() == IVL_VT_QUEUE ||
tmp->expr_type() == IVL_VT_DARRAY);
if (!qdar_mix) {
switch (tmp->expr_type()) {
case IVL_VT_BOOL:
case IVL_VT_LOGIC:
case IVL_VT_REAL:
break;
default:
cerr << tmp->get_fileline() << ": error: "
"The expression '" << *pe << "' cannot be implicitly "
"cast to the target type." << endl;
des->errors += 1;
delete tmp;
return 0;
}
switch (cast_type) {
case IVL_VT_REAL:
tmp = cast_to_real(tmp);
break;
case IVL_VT_BOOL:
tmp = cast_to_int2(tmp, pos_context_width);
break;
case IVL_VT_LOGIC:
tmp = cast_to_int4(tmp, pos_context_width);
break;
default:
break;
}
}
}
eval_expr(tmp, context_width);
@ -958,12 +964,23 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
compatible = lv_net_type->type_compatible(tmp->net_type());
else
compatible = false;
} else if ((cast_type == IVL_VT_QUEUE || cast_type == IVL_VT_DARRAY) &&
(expr_type == IVL_VT_QUEUE || expr_type == IVL_VT_DARRAY)) {
if (tmp->net_type())
compatible = lv_net_type->type_compatible(tmp->net_type());
else
compatible = cast_type == expr_type;
} else if (cast_type == IVL_VT_NO_TYPE) {
compatible = true;
} else {
compatible = cast_type == expr_type;
}
/* R-value may report a coarse expr_type while net_type matches (e.g.
* queue locators); prefer structural compatibility when available. */
if (!compatible && tmp->net_type())
compatible = lv_net_type->type_compatible(tmp->net_type());
if (!compatible) {
// Catch some special cases.
switch (cast_type) {

73
parse.y
View File

@ -756,7 +756,7 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id,
%type <spec_optional_args> timeskew_fullskew_opt_remain_active_flag
%type <expr> assignment_pattern expression expression_opt expr_mintypmax
%type <expr> expr_primary_or_typename expr_primary
%type <expr> expr_primary_or_typename expr_primary call_chain_expr
%type <expr> class_new dynamic_array_new
%type <expr> var_decl_initializer_opt initializer_opt
%type <expr> inc_or_dec_expression inside_expression lpvalue
@ -3869,6 +3869,41 @@ expr_primary_or_typename
;
/* SystemVerilog: a().b() — call a function, then invoke a method on the
returned class handle. Extends with further ".id(args)" as needed. */
call_chain_expr
: hierarchy_identifier attribute_list_opt argument_list_parens
{ PECallFunction*tmp = pform_make_call_function(@1, *$1, *$3);
delete $1;
delete $2;
delete $3;
$$ = tmp;
}
| call_chain_expr '.' hierarchy_identifier attribute_list_opt argument_list_parens
{ PECallFunction*tmp = pform_make_chained_call_function(@2, $1, *$3, *$5);
delete $3;
delete $4;
delete $5;
$$ = tmp;
}
| call_chain_expr K_with '(' expression ')'
{ PECallFunction* cf = dynamic_cast<PECallFunction*>($1);
if (cf == 0) {
if (gn_system_verilog())
yyerror(@2, "Error: `with` clause must follow a method call.");
else
yyerror(@2, "Error: Enable SystemVerilog for `with` clause on method calls.");
delete $1;
delete $4;
$$ = 0;
} else {
cf->set_with_clause($4);
$$ = cf;
}
}
;
expr_primary
: number
{ assert($1);
@ -3928,6 +3963,20 @@ expr_primary
/* The hierarchy_identifier rule matches simple identifiers as well as
indexed arrays and part selects */
/* SV call chains get_c1().f() — must come before bare hierarchy_identifier
so `id (` is not reduced as PEIdent + error. */
| call_chain_expr
{ $$ = $1;
}
/* SV: q.find with (item == 1) — iterator names item, index */
| hierarchy_identifier K_with '(' expression ')'
{ std::vector<named_pexpr_t> empty;
PECallFunction* tmp = new PECallFunction(*$1, empty);
FILE_NAME(tmp, @1);
tmp->set_with_clause($4);
delete $1;
$$ = tmp;
}
| hierarchy_identifier
{ PEIdent*tmp = pform_new_ident(@1, *$1);
FILE_NAME(tmp, @1);
@ -3951,14 +4000,6 @@ expr_primary
$$ = tmp;
delete nm;
}
| hierarchy_identifier '.' K_unique
{ pform_name_t * nm = $1;
nm->push_back(name_component_t(lex_strings.make("unique")));
PEIdent*tmp = pform_new_ident(@1, *nm);
FILE_NAME(tmp, @1);
$$ = tmp;
delete nm;
}
| hierarchy_identifier '.' K_xor
{ pform_name_t * nm = $1;
nm->push_back(name_component_t(lex_strings.make("xor")));
@ -3967,7 +4008,6 @@ expr_primary
$$ = tmp;
delete nm;
}
| package_scope hierarchy_identifier
{ lex_in_package_scope(0);
$$ = pform_package_ident(@2, $1, $2);
@ -3978,13 +4018,6 @@ expr_primary
function call. If a system identifier, then a system function
call. It can also be a call to a class method (function). */
| hierarchy_identifier attribute_list_opt argument_list_parens
{ PECallFunction*tmp = pform_make_call_function(@1, *$1, *$3);
delete $1;
delete $2;
delete $3;
$$ = tmp;
}
| class_hierarchy_identifier argument_list_parens
{ PECallFunction*tmp = pform_make_call_function(@1, *$1, *$2);
delete $1;
@ -4474,6 +4507,12 @@ hierarchy_identifier
delete[]$3;
$$ = tmp;
}
/* "unique" is a keyword (K_unique) but also a queue/array method name. */
| hierarchy_identifier '.' K_unique
{ pform_name_t * tmp = $1;
tmp->push_back(name_component_t(lex_strings.make("unique")));
$$ = tmp;
}
| hierarchy_identifier '[' expression ']'
{ pform_name_t * tmp = $1;
name_component_t&tail = tmp->back();

View File

@ -938,6 +938,24 @@ PECallFunction* pform_make_call_function(const struct vlltype&loc,
return tmp;
}
PECallFunction* pform_make_chained_call_function(const struct vlltype&loc,
PExpr*prefix,
const pform_name_t&method,
const list<named_pexpr_t> &parms)
{
if (!gn_system_verilog()) {
pform_requires_sv(loc, "Chained calls like a().b()");
delete prefix;
return new PECallFunction(method, parms);
}
check_potential_imports(loc, method.front().name, true);
PECallFunction*tmp = new PECallFunction(prefix, method, parms);
FILE_NAME(tmp, loc);
return tmp;
}
PCallTask* pform_make_call_task(const struct vlltype&loc,
const pform_name_t&name,
const list<named_pexpr_t> &parms)

View File

@ -324,6 +324,10 @@ extern void pform_set_type_referenced(const struct vlltype&loc, const char*name)
extern PECallFunction* pform_make_call_function(const struct vlltype&loc,
const pform_name_t&name,
const std::list<named_pexpr_t> &parms);
extern PECallFunction* pform_make_chained_call_function(const struct vlltype&loc,
PExpr*prefix,
const pform_name_t&method,
const std::list<named_pexpr_t> &parms);
extern PCallTask* pform_make_call_task(const struct vlltype&loc,
const pform_name_t&name,
const std::list<named_pexpr_t> &parms);

View File

@ -421,7 +421,13 @@ void PEConcat::dump(ostream&out) const
void PECallFunction::dump(ostream &out) const
{
if (peek_chain_prefix()) {
peek_chain_prefix()->dump(out);
out << ".";
}
out << path_ << "(" << parms_ << ")";
if (peek_with_clause())
out << " with (" << *peek_with_clause() << ")";
}
void PECastSize::dump(ostream &out) const

View File

@ -25,6 +25,7 @@
# include "discipline.h"
# include "netclass.h"
# include "netdarray.h"
# include "netqueue.h"
# include "netenum.h"
# include "netvector.h"
# include <cstdlib>
@ -3308,6 +3309,19 @@ extern "C" ivl_type_t ivl_type_prop_type(ivl_type_t net, int idx)
return class_type->get_prop_type(idx);
}
extern "C" unsigned ivl_type_queue_max(ivl_type_t net)
{
if (net == 0)
return 0;
if (const netqueue_t*que = dynamic_cast<const netqueue_t*>(net)) {
long max_idx = que->max_idx();
if (max_idx < 0)
return 0;
return (unsigned)(max_idx + 1);
}
return 0;
}
extern "C" int ivl_type_signed(ivl_type_t net)
{
assert(net);

View File

@ -63,6 +63,7 @@ static void show_prop_type(ivl_type_t ptype)
show_prop_type_vector(ptype);
break;
case IVL_VT_DARRAY:
case IVL_VT_QUEUE:
case IVL_VT_CLASS:
fprintf(vvp_out, "\"o\"");
if (packed_dimensions > 0) {

View File

@ -375,6 +375,20 @@ static void draw_vpi_taskfunc_args(const char*call_string,
}
break;
case IVL_EX_PROPERTY:
if (ivl_expr_oper1(expr) == 0 &&
(ivl_expr_value(expr) == IVL_VT_QUEUE ||
ivl_expr_value(expr) == IVL_VT_DARRAY)) {
ivl_signal_t clas = ivl_expr_signal(expr);
unsigned pidx = ivl_expr_property_idx(expr);
unsigned isq = ivl_expr_value(expr) == IVL_VT_QUEUE ? 1U : 0U;
snprintf(buffer, sizeof buffer, "&PQ<v%p_0,%u,%u>",
clas, pidx, isq);
args[idx].text = strdup(buffer);
continue;
}
break;
case IVL_EX_SIGNAL:
case IVL_EX_SELECT:
args[idx].stack = vec4_stack_need;
@ -402,6 +416,10 @@ static void draw_vpi_taskfunc_args(const char*call_string,
switch (ivl_expr_value(expr)) {
case IVL_VT_LOGIC:
case IVL_VT_BOOL:
case IVL_VT_QUEUE:
case IVL_VT_DARRAY:
/* Queue/darray element selects may still carry the
* container ivl_expr_value; evaluate as vec4 like logic. */
draw_eval_vec4(expr);
args[idx].vec_flag = ivl_expr_signed(expr)? 's' : 'u';
args[idx].str_flag = 0;
@ -433,6 +451,20 @@ static void draw_vpi_taskfunc_args(const char*call_string,
buffer[0] = 0;
break;
default:
/* See eval_vec4.c:draw_eval_vec4 — indexed selects sometimes
* carry an unexpected ivl_expr_value (e.g. NO_TYPE). */
if (ivl_expr_type(expr) == IVL_EX_SELECT &&
ivl_expr_oper2(expr) != 0) {
draw_eval_vec4(expr);
args[idx].vec_flag = ivl_expr_signed(expr)? 's' : 'u';
args[idx].str_flag = 0;
args[idx].real_flag = 0;
args[idx].stack = vec4_stack_need;
args[idx].vec_wid = ivl_expr_width(expr);
vec4_stack_need += 1;
buffer[0] = 0;
break;
}
fprintf(stderr, "%s:%u: Sorry, cannot generate code for argument %u.\n",
ivl_expr_file(expr), ivl_expr_lineno(expr), idx+1);
fprintf(vvp_out, "\nXXXX Unexpected argument: call_string=<%s>, arg=%u, type=%d\n",

View File

@ -173,6 +173,92 @@ static int eval_darray_new(ivl_expr_t ex)
return errors;
}
/* Build a queue/dynamic-array object value from an array pattern expression. */
static int eval_array_pattern_object(ivl_expr_t ex)
{
int errors = 0;
ivl_type_t net_type = ivl_expr_net_type(ex);
if (!net_type)
return 1;
ivl_variable_type_t base_type = ivl_type_base(net_type);
if (base_type != IVL_VT_DARRAY && base_type != IVL_VT_QUEUE)
return 1;
ivl_type_t element_type = ivl_type_element(net_type);
if (!element_type)
return 1;
unsigned max_elems = ivl_expr_parms(ex);
if (base_type == IVL_VT_QUEUE) {
unsigned max_size = ivl_type_queue_max(net_type);
if (max_size != 0 && max_elems > max_size) {
fprintf(stderr, "%s:%u: Warning: Array pattern assignment has more "
"elements (%u) than bounded queue supports (%u).\n"
" Only using first %u elements.\n",
ivl_expr_file(ex), ivl_expr_lineno(ex), max_elems, max_size, max_size);
max_elems = max_size;
}
fprintf(vvp_out, " %%queue/new_empty/v;\n");
} else {
unsigned size_reg = allocate_word();
fprintf(vvp_out, " %%ix/load %u, %u, 0;\n", size_reg, max_elems);
fprintf(vvp_out, " %%flag_set/imm 4, 0;\n");
darray_new(element_type, size_reg);
}
switch (ivl_type_base(element_type)) {
case IVL_VT_BOOL:
case IVL_VT_LOGIC:
for (unsigned idx = 0; idx < max_elems; idx += 1) {
draw_eval_vec4(ivl_expr_parm(ex, idx));
if (base_type == IVL_VT_QUEUE) {
fprintf(vvp_out, " %%queue/append_word/v %u;\n",
ivl_type_packed_width(element_type));
} else {
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx);
fprintf(vvp_out, " %%set/dar/obj/vec4 3;\n");
fprintf(vvp_out, " %%pop/vec4 1;\n");
}
}
break;
case IVL_VT_REAL:
for (unsigned idx = 0; idx < max_elems; idx += 1) {
if (base_type == IVL_VT_QUEUE) {
fprintf(vvp_out, "; ERROR: eval_array_pattern_object: queue real "
"element type not implemented\n");
errors += 1;
break;
}
draw_eval_real(ivl_expr_parm(ex, idx));
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx);
fprintf(vvp_out, " %%set/dar/obj/real 3;\n");
fprintf(vvp_out, " %%pop/real 1;\n");
}
break;
case IVL_VT_STRING:
for (unsigned idx = 0; idx < max_elems; idx += 1) {
if (base_type == IVL_VT_QUEUE) {
fprintf(vvp_out, "; ERROR: eval_array_pattern_object: queue string "
"element type not implemented\n");
errors += 1;
break;
}
draw_eval_string(ivl_expr_parm(ex, idx));
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx);
fprintf(vvp_out, " %%set/dar/obj/str 3;\n");
fprintf(vvp_out, " %%pop/str 1;\n");
}
break;
default:
fprintf(vvp_out, "; ERROR: eval_array_pattern_object: unsupported "
"element type %d\n", ivl_type_base(element_type));
errors += 1;
break;
}
return errors;
}
static int eval_class_new(ivl_expr_t ex)
{
ivl_type_t class_type = ivl_expr_net_type(ex);
@ -257,6 +343,517 @@ static int eval_object_ufunc(ivl_expr_t ex)
return 0;
}
static unsigned queue_unique_src_elem_wid(ivl_expr_t arg)
{
ivl_type_t src_q = 0;
if (ivl_expr_type(arg) == IVL_EX_PROPERTY) {
ivl_signal_t cl = ivl_expr_signal(arg);
unsigned pidx = ivl_expr_property_idx(arg);
src_q = ivl_type_prop_type(ivl_signal_net_type(cl), pidx);
} else if (ivl_expr_type(arg) == IVL_EX_SIGNAL) {
src_q = ivl_signal_net_type(ivl_expr_signal(arg));
} else {
return 0;
}
if (ivl_type_base(src_q) == IVL_VT_QUEUE ||
ivl_type_base(src_q) == IVL_VT_DARRAY)
return ivl_type_packed_width(ivl_type_element(src_q));
return 0;
}
static int eval_queue_method_unique(ivl_expr_t expr)
{
const char*name = ivl_expr_name(expr);
ivl_expr_t arg = ivl_expr_parm(expr, 0);
unsigned elem_wid = queue_unique_src_elem_wid(arg);
if (elem_wid == 0)
return 1;
if (strcmp(name, "$ivl_queue_method$unique") == 0) {
if (ivl_expr_type(arg) == IVL_EX_PROPERTY) {
ivl_signal_t cl = ivl_expr_signal(arg);
unsigned pidx = ivl_expr_property_idx(arg);
fprintf(vvp_out, " %%load/obj v%p_0;\n", cl);
fprintf(vvp_out, " %%queue/unique/prop/v %u, %u;\n", pidx,
elem_wid);
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
} else {
ivl_signal_t sig = ivl_expr_signal(arg);
fprintf(vvp_out, " %%queue/unique/v v%p_0, %u;\n", sig,
elem_wid);
}
return 0;
}
if (strcmp(name, "$ivl_queue_method$unique_index") == 0) {
if (ivl_expr_type(arg) == IVL_EX_PROPERTY) {
ivl_signal_t cl = ivl_expr_signal(arg);
unsigned pidx = ivl_expr_property_idx(arg);
fprintf(vvp_out, " %%load/obj v%p_0;\n", cl);
fprintf(vvp_out, " %%queue/unique/index/prop/v %u, %u;\n",
pidx, elem_wid);
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
} else {
ivl_signal_t sig = ivl_expr_signal(arg);
fprintf(vvp_out, " %%queue/unique/index/v v%p_0, %u;\n",
sig, elem_wid);
}
return 0;
}
if (strcmp(name, "$ivl_queue_method$min") == 0 ||
strcmp(name, "$ivl_queue_method$max") == 0) {
const char* opname = strcmp(name, "$ivl_queue_method$min") == 0
? "min"
: "max";
if (ivl_expr_type(arg) == IVL_EX_PROPERTY) {
ivl_signal_t cl = ivl_expr_signal(arg);
unsigned pidx = ivl_expr_property_idx(arg);
fprintf(vvp_out, " %%load/obj v%p_0;\n", cl);
fprintf(vvp_out, " %%queue/%s/prop/v %u, %u;\n", opname, pidx,
elem_wid);
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
} else {
ivl_signal_t sig = ivl_expr_signal(arg);
fprintf(vvp_out, " %%queue/%s/v v%p_0, %u;\n", opname, sig,
elem_wid);
}
return 0;
}
return 1;
}
/*
* Array locator methods with `with (predicate)` parms:
* 0: queue, 1: predicate, 2: item ivl_signal, 3: index ivl_signal
*/
static int eval_queue_method_find_with(ivl_expr_t expr)
{
const char* name = ivl_expr_name(expr);
if (ivl_expr_parms(expr) != 4)
return 1;
if (strncmp(name, "$ivl_queue_method$", sizeof("$ivl_queue_method$") - 1) != 0)
return 1;
if (strstr(name, "_with") == 0)
return 1;
ivl_expr_t qarg = ivl_expr_parm(expr, 0);
ivl_expr_t pred = ivl_expr_parm(expr, 1);
ivl_signal_t item_sig = ivl_expr_signal(ivl_expr_parm(expr, 2));
ivl_signal_t idx_sig = ivl_expr_signal(ivl_expr_parm(expr, 3));
unsigned elem_wid = queue_unique_src_elem_wid(qarg);
if (elem_wid == 0)
return 1;
int mode = -1;
if (strcmp(name, "$ivl_queue_method$find_with") == 0)
mode = 0;
else if (strcmp(name, "$ivl_queue_method$find_index_with") == 0)
mode = 1;
else if (strcmp(name, "$ivl_queue_method$find_first_with") == 0)
mode = 2;
else if (strcmp(name, "$ivl_queue_method$find_first_index_with") == 0)
mode = 3;
else if (strcmp(name, "$ivl_queue_method$find_last_with") == 0)
mode = 4;
else if (strcmp(name, "$ivl_queue_method$find_last_index_with") == 0)
mode = 5;
else if (strcmp(name, "$ivl_queue_method$min_with") == 0)
mode = 6;
else if (strcmp(name, "$ivl_queue_method$max_with") == 0)
mode = 7;
else if (strcmp(name, "$ivl_queue_method$unique_with") == 0)
mode = 8;
else if (strcmp(name, "$ivl_queue_method$unique_index_with") == 0)
mode = 9;
else if (strcmp(name, "$ivl_queue_method$sum_with") == 0)
mode = 10;
else if (strcmp(name, "$ivl_queue_method$product_with") == 0)
mode = 11;
else
return 1;
int i_reg = allocate_word();
int n_reg = allocate_word();
unsigned lab_top = local_count++;
unsigned lab_loop_end = local_count++;
unsigned lab_nom = local_count++;
unsigned lab_found = local_count++;
unsigned lab_end = local_count++;
int reverse = (mode == 4 || mode == 5);
unsigned append_wid = (mode == 1) ? 32 : elem_wid;
if (ivl_expr_type(qarg) == IVL_EX_PROPERTY) {
ivl_signal_t cl = ivl_expr_signal(qarg);
unsigned pidx = ivl_expr_property_idx(qarg);
fprintf(vvp_out, " %%load/obj v%p_0;\n", cl);
fprintf(vvp_out, " %%prop/queue/size %u;\n", pidx);
fprintf(vvp_out, " %%ix/vec4/s %u;\n", n_reg);
if (mode == 0 || mode == 1 || mode == 6 || mode == 7 ||
mode == 8 || mode == 9 || mode == 10 || mode == 11) {
fprintf(vvp_out, " %%queue/new_empty/v;\n");
}
if (!reverse) {
fprintf(vvp_out, " %%ix/load %u, 0, 0;\n", i_reg);
fprintf(vvp_out, " %%flag_set/imm 4, 0;\n");
} else {
fprintf(vvp_out, " %%ix/load %u, 0, 0;\n", i_reg);
fprintf(vvp_out, " %%ix/mov %u, %u;\n", i_reg, n_reg);
fprintf(vvp_out, " %%ix/sub %u, 1, 0;\n", i_reg);
}
fprintf(vvp_out, "T_%u.%u ; queue with loop\n", thread_count, lab_top);
if (!reverse) {
fprintf(vvp_out, " %%cmpix/ltu %u, %u;\n", i_reg, n_reg);
fprintf(vvp_out, " %%jmp/0 T_%u.%u, 4;\n", thread_count,
lab_loop_end);
} else {
fprintf(vvp_out, " %%cmpix/slt0 %u;\n", i_reg);
fprintf(vvp_out, " %%jmp/1 T_%u.%u, 4;\n", thread_count,
lab_loop_end);
}
/* cmpix leaves flag 4 set; %queue/word* uses flag 4 for X push */
fprintf(vvp_out, " %%flag_set/imm 4, 0;\n");
fprintf(vvp_out, " %%queue/word/prop/v %u, %u, %u;\n", pidx,
elem_wid, i_reg);
fprintf(vvp_out, " %%store/vec4 v%p_0, 0, %u;\n", item_sig,
elem_wid);
fprintf(vvp_out, " %%push/ix/vec4 %u, 32, 1;\n", i_reg);
fprintf(vvp_out, " %%store/vec4 v%p_0, 0, 32;\n", idx_sig);
if (mode == 10 || mode == 11) {
draw_eval_vec4(pred);
fprintf(vvp_out, " %%queue/append_word/v %u;\n", elem_wid);
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
} else {
int pf = draw_eval_condition(pred);
fprintf(vvp_out, " %%jmp/0 T_%u.%u, %d;\n", thread_count,
lab_nom, pf);
clr_flag(pf);
}
if (mode == 0) {
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig);
fprintf(vvp_out, " %%queue/append_word/v %u;\n", append_wid);
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
} else if (mode == 1) {
fprintf(vvp_out, " %%push/ix/vec4 %u, 32, 1;\n", i_reg);
fprintf(vvp_out, " %%queue/append_word/v 32;\n");
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
} else if (mode == 6 || mode == 7) {
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig);
fprintf(vvp_out, " %%queue/append_word/v %u;\n", elem_wid);
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
} else if (mode == 8) {
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig);
fprintf(vvp_out, " %%queue/append_word/v %u;\n", elem_wid);
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
} else if (mode == 9) {
fprintf(vvp_out, " %%push/ix/vec4 %u, 32, 1;\n", i_reg);
fprintf(vvp_out, " %%queue/append_word/v 32;\n");
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
} else if (mode == 10 || mode == 11) {
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
} else if (mode == 2) {
fprintf(vvp_out, " %%queue/new_empty/v;\n");
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig);
fprintf(vvp_out, " %%queue/append_word/v %u;\n", elem_wid);
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_found);
} else if (mode == 3) {
fprintf(vvp_out, " %%queue/new_empty/v;\n");
fprintf(vvp_out, " %%push/ix/vec4 %u, 32, 1;\n", i_reg);
fprintf(vvp_out, " %%queue/append_word/v 32;\n");
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_found);
} else if (mode == 4) {
fprintf(vvp_out, " %%queue/new_empty/v;\n");
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig);
fprintf(vvp_out, " %%queue/append_word/v %u;\n", elem_wid);
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_found);
} else {
fprintf(vvp_out, " %%queue/new_empty/v;\n");
fprintf(vvp_out, " %%push/ix/vec4 %u, 32, 1;\n", i_reg);
fprintf(vvp_out, " %%queue/append_word/v 32;\n");
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_found);
}
fprintf(vvp_out, "T_%u.%u ; nomatch\n", thread_count, lab_nom);
if (!reverse) {
fprintf(vvp_out, " %%ix/add %u, 1, 0;\n", i_reg);
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_top);
} else {
fprintf(vvp_out, " %%ix/sub %u, 1, 0;\n", i_reg);
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_top);
}
fprintf(vvp_out, "T_%u.%u ; found (queue prop)\n", thread_count,
lab_found);
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_end);
fprintf(vvp_out, "T_%u.%u ; loop end (prop)\n", thread_count,
lab_loop_end);
if (mode == 0 || mode == 1) {
/* Keep result queue object, drop class object beneath it. */
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
} else if (mode == 10) {
fprintf(vvp_out, " %%queue/sum/obj/v %u;\n", elem_wid);
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
} else if (mode == 11) {
fprintf(vvp_out, " %%queue/product/obj/v %u;\n", elem_wid);
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
} else if (mode == 8 || mode == 9) {
fprintf(vvp_out, " %%queue/unique/obj/v %u;\n",
mode == 9 ? 32 : elem_wid);
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
} else if (mode == 6 || mode == 7) {
fprintf(vvp_out, " %%queue/%s/obj/v %u;\n",
mode == 6 ? "min" : "max", elem_wid);
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
} else {
fprintf(vvp_out, " %%queue/new_empty/v;\n");
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
}
fprintf(vvp_out, "T_%u.%u ; with end (prop)\n", thread_count, lab_end);
} else {
ivl_signal_t sig = ivl_expr_signal(qarg);
fprintf(vvp_out, " %%queue/size/v v%p_0;\n", sig);
fprintf(vvp_out, " %%ix/vec4/s %u;\n", n_reg);
if (mode == 0 || mode == 1 || mode == 6 || mode == 7 ||
mode == 8 || mode == 9 || mode == 10 || mode == 11) {
fprintf(vvp_out, " %%queue/new_empty/v;\n");
}
if (!reverse) {
fprintf(vvp_out, " %%ix/load %u, 0, 0;\n", i_reg);
fprintf(vvp_out, " %%flag_set/imm 4, 0;\n");
} else {
fprintf(vvp_out, " %%ix/load %u, 0, 0;\n", i_reg);
fprintf(vvp_out, " %%ix/mov %u, %u;\n", i_reg, n_reg);
fprintf(vvp_out, " %%ix/sub %u, 1, 0;\n", i_reg);
}
fprintf(vvp_out, "T_%u.%u ; queue with loop (var)\n", thread_count,
lab_top);
if (!reverse) {
fprintf(vvp_out, " %%cmpix/ltu %u, %u;\n", i_reg, n_reg);
fprintf(vvp_out, " %%jmp/0 T_%u.%u, 4;\n", thread_count,
lab_loop_end);
} else {
fprintf(vvp_out, " %%cmpix/slt0 %u;\n", i_reg);
fprintf(vvp_out, " %%jmp/1 T_%u.%u, 4;\n", thread_count,
lab_loop_end);
}
fprintf(vvp_out, " %%flag_set/imm 4, 0;\n");
fprintf(vvp_out, " %%queue/word/v v%p_0, %u, %u;\n", sig, elem_wid,
i_reg);
fprintf(vvp_out, " %%store/vec4 v%p_0, 0, %u;\n", item_sig,
elem_wid);
fprintf(vvp_out, " %%push/ix/vec4 %u, 32, 1;\n", i_reg);
fprintf(vvp_out, " %%store/vec4 v%p_0, 0, 32;\n", idx_sig);
if (mode == 10 || mode == 11) {
draw_eval_vec4(pred);
fprintf(vvp_out, " %%queue/append_word/v %u;\n", elem_wid);
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
} else {
int pf = draw_eval_condition(pred);
fprintf(vvp_out, " %%jmp/0 T_%u.%u, %d;\n", thread_count,
lab_nom, pf);
clr_flag(pf);
}
if (mode == 0) {
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig);
fprintf(vvp_out, " %%queue/append_word/v %u;\n", append_wid);
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
} else if (mode == 1) {
fprintf(vvp_out, " %%push/ix/vec4 %u, 32, 1;\n", i_reg);
fprintf(vvp_out, " %%queue/append_word/v 32;\n");
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
} else if (mode == 6 || mode == 7) {
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig);
fprintf(vvp_out, " %%queue/append_word/v %u;\n", elem_wid);
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
} else if (mode == 8) {
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig);
fprintf(vvp_out, " %%queue/append_word/v %u;\n", elem_wid);
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
} else if (mode == 9) {
fprintf(vvp_out, " %%push/ix/vec4 %u, 32, 1;\n", i_reg);
fprintf(vvp_out, " %%queue/append_word/v 32;\n");
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
} else if (mode == 10 || mode == 11) {
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
} else if (mode == 2) {
fprintf(vvp_out, " %%queue/new_empty/v;\n");
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig);
fprintf(vvp_out, " %%queue/append_word/v %u;\n", elem_wid);
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_end);
} else if (mode == 3) {
fprintf(vvp_out, " %%queue/new_empty/v;\n");
fprintf(vvp_out, " %%push/ix/vec4 %u, 32, 1;\n", i_reg);
fprintf(vvp_out, " %%queue/append_word/v 32;\n");
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_end);
} else if (mode == 4) {
fprintf(vvp_out, " %%queue/new_empty/v;\n");
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig);
fprintf(vvp_out, " %%queue/append_word/v %u;\n", elem_wid);
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_end);
} else {
fprintf(vvp_out, " %%queue/new_empty/v;\n");
fprintf(vvp_out, " %%push/ix/vec4 %u, 32, 1;\n", i_reg);
fprintf(vvp_out, " %%queue/append_word/v 32;\n");
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_end);
}
fprintf(vvp_out, "T_%u.%u ; nomatch (var)\n", thread_count, lab_nom);
if (!reverse) {
fprintf(vvp_out, " %%ix/add %u, 1, 0;\n", i_reg);
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_top);
} else {
fprintf(vvp_out, " %%ix/sub %u, 1, 0;\n", i_reg);
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_top);
}
fprintf(vvp_out, "T_%u.%u ; loop end (var)\n", thread_count,
lab_loop_end);
if (mode == 10) {
fprintf(vvp_out, " %%queue/sum/obj/v %u;\n", elem_wid);
} else if (mode == 11) {
fprintf(vvp_out, " %%queue/product/obj/v %u;\n", elem_wid);
} else if (mode == 8 || mode == 9) {
fprintf(vvp_out, " %%queue/unique/obj/v %u;\n",
mode == 9 ? 32 : elem_wid);
} else if (mode == 6 || mode == 7) {
fprintf(vvp_out, " %%queue/%s/obj/v %u;\n",
mode == 6 ? "min" : "max", elem_wid);
} else if (mode >= 2) {
fprintf(vvp_out, " %%queue/new_empty/v;\n");
}
fprintf(vvp_out, "T_%u.%u ; with end (var)\n", thread_count, lab_end);
}
clr_word(i_reg);
clr_word(n_reg);
return 0;
}
static int eval_queue_method_find(ivl_expr_t expr)
{
const char*name = ivl_expr_name(expr);
if (ivl_expr_parms(expr) == 4 &&
strstr(ivl_expr_name(expr), "_with") != 0)
return eval_queue_method_find_with(expr);
ivl_expr_t qarg = ivl_expr_parm(expr, 0);
ivl_expr_t carg = ivl_expr_parm(expr, 1);
unsigned elem_wid = queue_unique_src_elem_wid(qarg);
if (elem_wid == 0)
return 1;
draw_eval_vec4(carg);
if (strcmp(name, "$ivl_queue_method$find") == 0) {
if (ivl_expr_type(qarg) == IVL_EX_PROPERTY) {
ivl_signal_t cl = ivl_expr_signal(qarg);
unsigned pidx = ivl_expr_property_idx(qarg);
fprintf(vvp_out, " %%load/obj v%p_0;\n", cl);
fprintf(vvp_out, " %%queue/find/prop/v %u, %u;\n", pidx,
elem_wid);
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
} else {
ivl_signal_t sig = ivl_expr_signal(qarg);
fprintf(vvp_out, " %%queue/find/v v%p_0, %u;\n", sig,
elem_wid);
}
return 0;
}
if (strcmp(name, "$ivl_queue_method$find_index") == 0) {
if (ivl_expr_type(qarg) == IVL_EX_PROPERTY) {
ivl_signal_t cl = ivl_expr_signal(qarg);
unsigned pidx = ivl_expr_property_idx(qarg);
fprintf(vvp_out, " %%load/obj v%p_0;\n", cl);
fprintf(vvp_out, " %%queue/find/index/prop/v %u, %u;\n",
pidx, elem_wid);
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
} else {
ivl_signal_t sig = ivl_expr_signal(qarg);
fprintf(vvp_out, " %%queue/find/index/v v%p_0, %u;\n",
sig, elem_wid);
}
return 0;
}
if (strcmp(name, "$ivl_queue_method$find_first") == 0) {
if (ivl_expr_type(qarg) == IVL_EX_PROPERTY) {
ivl_signal_t cl = ivl_expr_signal(qarg);
unsigned pidx = ivl_expr_property_idx(qarg);
fprintf(vvp_out, " %%load/obj v%p_0;\n", cl);
fprintf(vvp_out, " %%queue/find_first/prop/v %u, %u;\n", pidx,
elem_wid);
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
} else {
ivl_signal_t sig = ivl_expr_signal(qarg);
fprintf(vvp_out, " %%queue/find_first/v v%p_0, %u;\n", sig,
elem_wid);
}
return 0;
}
if (strcmp(name, "$ivl_queue_method$find_first_index") == 0) {
if (ivl_expr_type(qarg) == IVL_EX_PROPERTY) {
ivl_signal_t cl = ivl_expr_signal(qarg);
unsigned pidx = ivl_expr_property_idx(qarg);
fprintf(vvp_out, " %%load/obj v%p_0;\n", cl);
fprintf(vvp_out, " %%queue/find_first/index/prop/v %u, %u;\n",
pidx, elem_wid);
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
} else {
ivl_signal_t sig = ivl_expr_signal(qarg);
fprintf(vvp_out, " %%queue/find_first/index/v v%p_0, %u;\n",
sig, elem_wid);
}
return 0;
}
if (strcmp(name, "$ivl_queue_method$find_last") == 0) {
if (ivl_expr_type(qarg) == IVL_EX_PROPERTY) {
ivl_signal_t cl = ivl_expr_signal(qarg);
unsigned pidx = ivl_expr_property_idx(qarg);
fprintf(vvp_out, " %%load/obj v%p_0;\n", cl);
fprintf(vvp_out, " %%queue/find_last/prop/v %u, %u;\n", pidx,
elem_wid);
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
} else {
ivl_signal_t sig = ivl_expr_signal(qarg);
fprintf(vvp_out, " %%queue/find_last/v v%p_0, %u;\n", sig,
elem_wid);
}
return 0;
}
if (strcmp(name, "$ivl_queue_method$find_last_index") == 0) {
if (ivl_expr_type(qarg) == IVL_EX_PROPERTY) {
ivl_signal_t cl = ivl_expr_signal(qarg);
unsigned pidx = ivl_expr_property_idx(qarg);
fprintf(vvp_out, " %%load/obj v%p_0;\n", cl);
fprintf(vvp_out, " %%queue/find_last/index/prop/v %u, %u;\n",
pidx, elem_wid);
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
} else {
ivl_signal_t sig = ivl_expr_signal(qarg);
fprintf(vvp_out, " %%queue/find_last/index/v v%p_0, %u;\n",
sig, elem_wid);
}
return 0;
}
return 1;
}
int draw_queue_method_find_sfunc(ivl_expr_t expr)
{
return eval_queue_method_find(expr);
}
int draw_eval_object(ivl_expr_t ex)
{
switch (ivl_expr_type(ex)) {
@ -288,6 +885,29 @@ int draw_eval_object(ivl_expr_t ex)
case IVL_EX_UFUNC:
return eval_object_ufunc(ex);
case IVL_EX_ARRAY_PATTERN:
return eval_array_pattern_object(ex);
case IVL_EX_SFUNC:
/* Queue locator `with` may report IVL_VT_DARRAY in ivl; handle by name. */
if (ivl_expr_parms(ex) == 4 &&
strncmp(ivl_expr_name(ex), "$ivl_queue_method$",
sizeof("$ivl_queue_method$") - 1) == 0 &&
strstr(ivl_expr_name(ex), "_with") != 0) {
if (draw_queue_method_find_sfunc(ex) == 0)
return 0;
}
if (ivl_expr_value(ex) == IVL_VT_QUEUE ||
ivl_expr_value(ex) == IVL_VT_DARRAY) {
if (eval_queue_method_unique(ex) == 0)
return 0;
if (eval_queue_method_find(ex) == 0)
return 0;
}
fprintf(vvp_out, "; ERROR: draw_eval_object: unsupported IVL_EX_SFUNC "
"for object context\n");
return 1;
default:
fprintf(vvp_out, "; ERROR: draw_eval_object: Invalid expression type %d\n", ivl_expr_type(ex));
return 1;

View File

@ -277,6 +277,15 @@ static void real_ex_pop(ivl_expr_t expr)
fb = "f";
arg = ivl_expr_parm(expr, 0);
if (ivl_expr_type(arg) == IVL_EX_PROPERTY) {
ivl_signal_t clas = ivl_expr_signal(arg);
unsigned pidx = ivl_expr_property_idx(arg);
fprintf(vvp_out, " %%load/obj v%p_0;\n", clas);
fprintf(vvp_out, " %%qpop/prop/%s/r %u;\n", fb, pidx);
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
return;
}
assert(ivl_expr_type(arg) == IVL_EX_SIGNAL);
fprintf(vvp_out, " %%qpop/%s/real v%p_0;\n", fb, ivl_expr_signal(arg));

View File

@ -167,6 +167,15 @@ static void string_ex_pop(ivl_expr_t expr)
fb = "f";
arg = ivl_expr_parm(expr, 0);
if (ivl_expr_type(arg) == IVL_EX_PROPERTY) {
ivl_signal_t clas = ivl_expr_signal(arg);
unsigned pidx = ivl_expr_property_idx(arg);
fprintf(vvp_out, " %%load/obj v%p_0;\n", clas);
fprintf(vvp_out, " %%qpop/prop/%s/str %u;\n", fb, pidx);
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
return;
}
assert(ivl_expr_type(arg) == IVL_EX_SIGNAL);
fprintf(vvp_out, " %%qpop/%s/str v%p_0;\n", fb, ivl_expr_signal(arg));

View File

@ -917,6 +917,28 @@ static void draw_property_vec4(ivl_expr_t expr)
{
ivl_signal_t sig = ivl_expr_signal(expr);
unsigned pidx = ivl_expr_property_idx(expr);
/* Queue/dynamic-array property with index: index is oper1 (see
* dll_target::expr_property). */
ivl_expr_t index_ex = ivl_expr_oper1(expr);
if (index_ex) {
ivl_type_t cls_type = ivl_signal_net_type(sig);
ivl_type_t ptype = ivl_type_prop_type(cls_type, pidx);
if (ptype) {
ivl_variable_type_t pbase = ivl_type_base(ptype);
if (pbase == IVL_VT_QUEUE || pbase == IVL_VT_DARRAY) {
unsigned wid = ivl_expr_width(expr);
draw_eval_expr_into_integer(index_ex, 3);
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
fprintf(vvp_out, " %%load/prop/dar/vec4 %u, %u;\n",
pidx, wid);
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
if (ivl_expr_value(expr) == IVL_VT_BOOL)
fprintf(vvp_out, " %%cast2;\n");
return;
}
}
}
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
fprintf(vvp_out, " %%prop/v %u;\n", pidx);
@ -948,7 +970,30 @@ static void draw_select_vec4(ivl_expr_t expr)
return;
}
if (ivl_expr_value(subexpr)==IVL_VT_DARRAY) {
/* Class property that is a queue or dynamic array: c.q[idx] */
if (ivl_expr_type(subexpr) == IVL_EX_PROPERTY) {
ivl_signal_t clas = ivl_expr_signal(subexpr);
unsigned pidx = ivl_expr_property_idx(subexpr);
ivl_type_t cls_type = ivl_signal_net_type(clas);
ivl_type_t ptype = ivl_type_prop_type(cls_type, pidx);
if (ptype) {
ivl_variable_type_t pbase = ivl_type_base(ptype);
if (pbase == IVL_VT_QUEUE || pbase == IVL_VT_DARRAY) {
assert(base);
draw_eval_expr_into_integer(base, 3);
fprintf(vvp_out, " %%load/obj v%p_0;\n", clas);
fprintf(vvp_out, " %%load/prop/dar/vec4 %u, %u;\n",
pidx, wid);
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
if (ivl_expr_value(expr) == IVL_VT_BOOL)
fprintf(vvp_out, " %%cast2;\n");
return;
}
}
}
if (ivl_expr_value(subexpr)==IVL_VT_DARRAY ||
ivl_expr_value(subexpr)==IVL_VT_QUEUE) {
ivl_signal_t sig = ivl_expr_signal(subexpr);
assert(sig);
assert( (ivl_signal_data_type(sig)==IVL_VT_DARRAY)
@ -1001,12 +1046,6 @@ static void draw_select_pad_vec4(ivl_expr_t expr)
fprintf(vvp_out, " %%pad/u %u;\n", wid);
}
/*
* This function handles the special case of a call to the internal
* functions $ivl_queue_method$pop_back et al. The first (and only)
* argument is the signal that represents a dynamic queue. Generate a
* %qpop instruction to pop a value and push it to the vec4 stack.
*/
static void draw_darray_pop(ivl_expr_t expr)
{
const char*fb;
@ -1017,6 +1056,16 @@ static void draw_darray_pop(ivl_expr_t expr)
fb = "f";
ivl_expr_t arg = ivl_expr_parm(expr, 0);
if (ivl_expr_type(arg) == IVL_EX_PROPERTY) {
ivl_signal_t clas = ivl_expr_signal(arg);
unsigned pidx = ivl_expr_property_idx(arg);
fprintf(vvp_out, " %%load/obj v%p_0;\n", clas);
fprintf(vvp_out, " %%qpop/prop/%s/v %u, %u;\n", fb, pidx,
ivl_expr_width(expr));
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
return;
}
assert(ivl_expr_type(arg) == IVL_EX_SIGNAL);
fprintf(vvp_out, " %%qpop/%s/v v%p_0, %u;\n", fb, ivl_expr_signal(arg),
@ -1049,6 +1098,49 @@ static void draw_sfunc_vec4(ivl_expr_t expr)
return;
}
/* find*_with has four parameters and is lowered in eval_object.c */
if (parm_count == 4 &&
strncmp(ivl_expr_name(expr), "$ivl_queue_method$",
sizeof("$ivl_queue_method$") - 1) == 0 &&
strstr(ivl_expr_name(expr), "_with") != 0) {
if (draw_queue_method_find_sfunc(expr) == 0)
return;
}
if (strcmp(ivl_expr_name(expr), "$size")==0 && parm_count==1) {
ivl_expr_t arg = ivl_expr_parm(expr, 0);
if (ivl_expr_type(arg) == IVL_EX_PROPERTY) {
ivl_signal_t sig = ivl_expr_signal(arg);
unsigned pidx = ivl_expr_property_idx(arg);
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
fprintf(vvp_out, " %%prop/queue/size %u;\n", pidx);
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
return;
}
}
if ((strcmp(ivl_expr_name(expr), "$ivl_queue_method$sum") == 0 ||
strcmp(ivl_expr_name(expr), "$ivl_queue_method$product") == 0) &&
parm_count == 1) {
ivl_expr_t arg = ivl_expr_parm(expr, 0);
unsigned wid = ivl_expr_width(expr);
const char* op = strcmp(ivl_expr_name(expr), "$ivl_queue_method$product") == 0
? "product"
: "sum";
if (ivl_expr_type(arg) == IVL_EX_PROPERTY) {
ivl_signal_t clas = ivl_expr_signal(arg);
unsigned pidx = ivl_expr_property_idx(arg);
fprintf(vvp_out, " %%load/obj v%p_0;\n", clas);
fprintf(vvp_out, " %%queue/%s/prop/v %u, %u;\n", op, pidx, wid);
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
return;
}
assert(ivl_expr_type(arg) == IVL_EX_SIGNAL);
fprintf(vvp_out, " %%queue/%s/v v%p_0, %u;\n",
op, ivl_expr_signal(arg), wid);
return;
}
draw_vpi_func_call(expr);
}
@ -1357,7 +1449,9 @@ void draw_eval_vec4(ivl_expr_t expr)
}
assert(ivl_expr_value(expr) == IVL_VT_BOOL ||
ivl_expr_value(expr) == IVL_VT_VECTOR);
ivl_expr_value(expr) == IVL_VT_VECTOR ||
(ivl_expr_type(expr) == IVL_EX_SELECT && ivl_expr_oper2(expr) != 0) ||
ivl_expr_type(expr) == IVL_EX_PROPERTY);
switch (ivl_expr_type(expr)) {
case IVL_EX_BINARY:

View File

@ -1364,15 +1364,16 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net)
fprintf(vvp_out, " %%store/prop/str %d;\n", prop_idx);
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
} else if (ivl_type_base(prop_type) == IVL_VT_DARRAY) {
} else if (ivl_type_base(prop_type) == IVL_VT_DARRAY
|| ivl_type_base(prop_type) == IVL_VT_QUEUE) {
int idx = 0;
/* The property is a darray, and there is no mux
expression to the assignment is of an entire
array object. */
/* The property is a darray or queue, and there is no mux
expression so the assignment is of an entire
array/queue object. */
errors += draw_eval_object(rval);
fprintf(vvp_out, " %%store/prop/obj %d, %d; IVL_VT_DARRAY\n", prop_idx, idx);
fprintf(vvp_out, " %%store/prop/obj %d, %d; IVL_VT_DARRAY or QUEUE\n", prop_idx, idx);
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
} else if (ivl_type_base(prop_type) == IVL_VT_CLASS) {

View File

@ -228,6 +228,12 @@ extern void draw_eval_string(ivl_expr_t ex);
*/
extern int draw_eval_object(ivl_expr_t ex);
/*
* Emit vvp for $ivl_queue_method$find* / find*_with when the call appears
* as a vector SFUNC (e.g. find_first with (...) returning int).
*/
extern int draw_queue_method_find_sfunc(ivl_expr_t expr);
extern int show_stmt_assign(ivl_statement_t net);
extern void show_stmt_file_line(ivl_statement_t net, const char*desc);

View File

@ -1663,6 +1663,24 @@ static int show_delete_method(ivl_statement_t net)
return 1;
ivl_expr_t parm = ivl_stmt_parm(net, 0);
if (ivl_expr_type(parm) == IVL_EX_PROPERTY) {
ivl_signal_t clas = ivl_expr_signal(parm);
unsigned pidx = ivl_expr_property_idx(parm);
ivl_type_t sig_type = ivl_signal_net_type(clas);
ivl_type_t queue_type = ivl_type_prop_type(sig_type, pidx);
assert(ivl_type_base(queue_type) == IVL_VT_QUEUE);
fprintf(vvp_out, " %%load/obj v%p_0;\n", clas);
if (parm_count == 2) {
draw_eval_expr_into_integer(ivl_stmt_parm(net, 1), 3);
fprintf(vvp_out, " %%delete/prop/elem %u;\n", pidx);
} else {
fprintf(vvp_out, " %%delete/prop/obj %u;\n", pidx);
}
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
return 0;
}
assert(ivl_expr_type(parm) == IVL_EX_SIGNAL);
ivl_signal_t var = ivl_expr_signal(parm);
@ -1673,11 +1691,72 @@ static int show_delete_method(ivl_statement_t net)
draw_eval_expr_into_integer(ivl_stmt_parm(net, 1), 3);
fprintf(vvp_out, " %%delete/elem v%p_0;\n", var);
} else {
fprintf(vvp_out, " %%delete/obj v%p_0;\n", var);
fprintf(vvp_out, " %%delete/obj v%p_0;\n", var);
}
return 0;
}
static int show_reverse_method(ivl_statement_t net)
{
show_stmt_file_line(net, "reverse dynamic array or queue");
unsigned parm_count = ivl_stmt_parm_count(net);
if (parm_count != 1)
return 1;
ivl_expr_t parm = ivl_stmt_parm(net, 0);
if (ivl_expr_type(parm) == IVL_EX_PROPERTY) {
ivl_signal_t clas = ivl_expr_signal(parm);
unsigned pidx = ivl_expr_property_idx(parm);
ivl_type_t sig_type = ivl_signal_net_type(clas);
ivl_type_t arr_type = ivl_type_prop_type(sig_type, pidx);
ivl_variable_type_t bt = ivl_type_base(arr_type);
if (bt != IVL_VT_QUEUE && bt != IVL_VT_DARRAY)
return 1;
fprintf(vvp_out, " %%load/obj v%p_0;\n", clas);
fprintf(vvp_out, " %%reverse/prop/obj %u;\n", pidx);
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
return 0;
}
assert(ivl_expr_type(parm) == IVL_EX_SIGNAL);
ivl_signal_t var = ivl_expr_signal(parm);
fprintf(vvp_out, " %%reverse/obj v%p_0;\n", var);
return 0;
}
static int show_array_order_method(ivl_statement_t net, const char*descr,
const char*op_signal, const char*op_prop)
{
show_stmt_file_line(net, descr);
unsigned parm_count = ivl_stmt_parm_count(net);
if (parm_count != 1)
return 1;
ivl_expr_t parm = ivl_stmt_parm(net, 0);
if (ivl_expr_type(parm) == IVL_EX_PROPERTY) {
ivl_signal_t clas = ivl_expr_signal(parm);
unsigned pidx = ivl_expr_property_idx(parm);
ivl_type_t sig_type = ivl_signal_net_type(clas);
ivl_type_t arr_type = ivl_type_prop_type(sig_type, pidx);
ivl_variable_type_t bt = ivl_type_base(arr_type);
if (bt != IVL_VT_QUEUE && bt != IVL_VT_DARRAY)
return 1;
fprintf(vvp_out, " %%load/obj v%p_0;\n", clas);
fprintf(vvp_out, " %s %u;\n", op_prop, pidx);
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
return 0;
}
assert(ivl_expr_type(parm) == IVL_EX_SIGNAL);
ivl_signal_t var = ivl_expr_signal(parm);
fprintf(vvp_out, " %s v%p_0;\n", op_signal, var);
return 0;
}
static int show_insert_method(ivl_statement_t net)
{
show_stmt_file_line(net, "queue: insert");
@ -1687,6 +1766,47 @@ static int show_insert_method(ivl_statement_t net)
return 1;
ivl_expr_t parm0 = ivl_stmt_parm(net,0);
if (ivl_expr_type(parm0) == IVL_EX_PROPERTY) {
ivl_signal_t clas = ivl_expr_signal(parm0);
unsigned pidx = ivl_expr_property_idx(parm0);
ivl_type_t sig_type = ivl_signal_net_type(clas);
ivl_type_t var_type = ivl_type_prop_type(sig_type, pidx);
assert(ivl_type_base(var_type) == IVL_VT_QUEUE);
int idx = allocate_word();
assert(idx >= 0);
fprintf(vvp_out, " %%load/obj v%p_0;\n", clas);
fprintf(vvp_out, " %%ix/load %d, %u, 0;\n", idx,
ivl_type_queue_max(var_type));
ivl_type_t element_type = ivl_type_element(var_type);
ivl_expr_t parm1 = ivl_stmt_parm(net,1);
draw_eval_expr_into_integer(parm1, 3);
ivl_expr_t parm2 = ivl_stmt_parm(net,2);
switch (ivl_type_base(element_type)) {
case IVL_VT_REAL:
draw_eval_real(parm2);
fprintf(vvp_out, " %%qinsert/prop/r %u, %d;\n",
pidx, idx);
break;
case IVL_VT_STRING:
draw_eval_string(parm2);
fprintf(vvp_out, " %%qinsert/prop/str %u, %d;\n",
pidx, idx);
break;
default:
draw_eval_vec4(parm2);
fprintf(vvp_out, " %%qinsert/prop/v %u, %d, %u;\n",
pidx, idx,
ivl_type_packed_width(element_type));
break;
}
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
clr_word(idx);
return 0;
}
assert(ivl_expr_type(parm0) == IVL_EX_SIGNAL);
ivl_signal_t var = ivl_expr_signal(parm0);
ivl_type_t var_type = ivl_signal_net_type(var);
@ -1740,6 +1860,45 @@ static int show_push_frontback_method(ivl_statement_t net, bool is_front)
return 1;
ivl_expr_t parm0 = ivl_stmt_parm(net,0);
if (ivl_expr_type(parm0) == IVL_EX_PROPERTY) {
ivl_signal_t clas = ivl_expr_signal(parm0);
unsigned pidx = ivl_expr_property_idx(parm0);
ivl_type_t sig_type = ivl_signal_net_type(clas);
ivl_type_t var_type = ivl_type_prop_type(sig_type, pidx);
assert(ivl_type_base(var_type) == IVL_VT_QUEUE);
int idx = allocate_word();
assert(idx >= 0);
fprintf(vvp_out, " %%load/obj v%p_0;\n", clas);
fprintf(vvp_out, " %%ix/load %d, %u, 0;\n", idx,
ivl_type_queue_max(var_type));
ivl_type_t element_type = ivl_type_element(var_type);
ivl_expr_t parm1 = ivl_stmt_parm(net,1);
switch (ivl_type_base(element_type)) {
case IVL_VT_REAL:
draw_eval_real(parm1);
fprintf(vvp_out, " %%store/prop/%s/r %u, %d;\n",
type_code, pidx, idx);
break;
case IVL_VT_STRING:
draw_eval_string(parm1);
fprintf(vvp_out, " %%store/prop/%s/str %u, %d;\n",
type_code, pidx, idx);
break;
default:
draw_eval_vec4(parm1);
fprintf(vvp_out, " %%store/prop/%s/v %u, %d, %u;\n",
type_code, pidx, idx,
ivl_type_packed_width(element_type));
break;
}
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
clr_word(idx);
return 0;
}
assert(ivl_expr_type(parm0) == IVL_EX_SIGNAL);
ivl_signal_t var = ivl_expr_signal(parm0);
ivl_type_t var_type = ivl_signal_net_type(var);
@ -1783,6 +1942,21 @@ static int show_system_task_call(ivl_statement_t net)
if (strcmp(stmt_name,"$ivl_darray_method$delete") == 0)
return show_delete_method(net);
if (strcmp(stmt_name,"$ivl_darray_method$reverse") == 0)
return show_reverse_method(net);
if (strcmp(stmt_name,"$ivl_darray_method$sort") == 0)
return show_array_order_method(net, "sort dynamic array or queue",
"%sort/obj", "%sort/prop/obj");
if (strcmp(stmt_name,"$ivl_darray_method$rsort") == 0)
return show_array_order_method(net, "rsort dynamic array or queue",
"%rsort/obj", "%rsort/prop/obj");
if (strcmp(stmt_name,"$ivl_darray_method$shuffle") == 0)
return show_array_order_method(net, "shuffle dynamic array or queue",
"%shuffle/obj", "%shuffle/prop/obj");
if (strcmp(stmt_name,"$ivl_queue_method$insert") == 0)
return show_insert_method(net);

View File

@ -286,6 +286,11 @@ void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit)
assert(vpip_routines);
vpip_routines->format_strength(str, value, bit);
}
char* vpip_format_pretty(vpiHandle ref)
{
assert(vpip_routines);
return vpip_routines->format_pretty(ref);
}
void vpip_make_systf_system_defined(vpiHandle ref)
{
assert(vpip_routines);

View File

@ -867,6 +867,35 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
* be a binary string (can contain NULLs). */
break;
case 'p':
case 'P':
*idx += 1;
if (plus != 0 || prec != -1) {
vpi_printf("WARNING: %s:%d: invalid format %s%s.\n",
info->filename, info->lineno, info->name, fmtb);
}
if (*idx >= info->nitems) {
vpi_printf("WARNING: %s:%d: missing argument for %s%s.\n",
info->filename, info->lineno, info->name, fmtb);
} else {
char *pp = vpip_format_pretty(info->items[*idx]);
if (pp == 0) {
vpi_printf("WARNING: %s:%d: incompatible value for %s%s.\n",
info->filename, info->lineno, info->name, fmtb);
} else {
char *cp = pp;
if (width == -1) width = 0;
size = strlen(cp) + 1;
if ((signed)size < (width+1)) size = width+1;
if (size > ini_size) result = realloc(result, size*sizeof(char));
if (ljust == 0) sprintf(result, "%*s", width, cp);
else sprintf(result, "%-*s", width, cp);
free(pp);
size = strlen(result) + 1;
}
}
break;
default:
vpi_printf("WARNING: %s:%d: unknown format %s%s.\n",
info->filename, info->lineno, info->name, fmtb);
@ -1215,6 +1244,7 @@ static int sys_check_args(vpiHandle callh, vpiHandle argv, const PLI_BYTE8*name,
#endif
case vpiClassVar:
case vpiSysFuncCall:
case vpiRegArray: /* dynamic arrays, queues, SV array vars */
break;
default:

View File

@ -641,6 +641,10 @@ extern DLLEXPORT void (*vlog_startup_routines[])(void);
/* Format a scalar a la %v. The str points to a 4byte character
buffer. The value must be a vpiStrengthVal. */
extern void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit);
/* Pretty-print a dynamic array or queue (including class property queues)
* for %p. Returns a malloc'd string, or NULL if the handle is not
* supported. Caller must free the returned pointer when non-NULL. */
extern char* vpip_format_pretty(vpiHandle ref);
/* Set the return value to return from the vvp run time. This is
usually 0 or 1. This is the exit code that the vvp process
returns, and in distinct from the finish_number that is an
@ -696,7 +700,7 @@ extern void vpip_count_drivers(vpiHandle ref, unsigned idx,
*/
// Increment the version number any time vpip_routines_s is changed.
static const PLI_UINT32 vpip_routines_version = 1;
static const PLI_UINT32 vpip_routines_version = 2;
typedef struct {
vpiHandle (*register_cb)(p_cb_data);
@ -737,6 +741,7 @@ typedef struct {
s_vpi_vecval(*calc_clog2)(vpiHandle);
void (*count_drivers)(vpiHandle, unsigned, unsigned [4]);
void (*format_strength)(char*, s_vpi_value*, unsigned);
char* (*format_pretty)(vpiHandle);
void (*make_systf_system_defined)(vpiHandle);
void (*mcd_rawwrite)(PLI_UINT32, const char*, size_t);
void (*set_return_value)(int);

View File

@ -150,6 +150,7 @@ extern bool of_LOAD_REAL(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_DAR_R(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_DAR_STR(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_DAR_VEC4(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_PROP_DAR_VEC4(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_OBJA(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_STR(vthread_t thr, vvp_code_t code);
@ -212,6 +213,14 @@ extern bool of_REPLICATE(vthread_t thr, vvp_code_t code);
extern bool of_RET_REAL(vthread_t thr, vvp_code_t code);
extern bool of_RET_STR(vthread_t thr, vvp_code_t code);
extern bool of_RET_VEC4(vthread_t thr, vvp_code_t code);
extern bool of_REVERSE_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_REVERSE_PROP_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_RSORT_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_RSORT_PROP_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_SHUFFLE_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_SHUFFLE_PROP_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_SORT_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_SORT_PROP_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_RETLOAD_REAL(vthread_t thr, vvp_code_t code);
extern bool of_RETLOAD_STR(vthread_t thr, vvp_code_t code);
extern bool of_RETLOAD_VEC4(vthread_t thr, vvp_code_t code);
@ -232,6 +241,62 @@ extern bool of_STORE_PROP_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_STORE_PROP_R(vthread_t thr, vvp_code_t code);
extern bool of_STORE_PROP_STR(vthread_t thr, vvp_code_t code);
extern bool of_STORE_PROP_V(vthread_t thr, vvp_code_t code);
extern bool of_STORE_PROP_QB_R(vthread_t thr, vvp_code_t code);
extern bool of_STORE_PROP_QB_STR(vthread_t thr, vvp_code_t code);
extern bool of_STORE_PROP_QB_V(vthread_t thr, vvp_code_t code);
extern bool of_STORE_PROP_QF_R(vthread_t thr, vvp_code_t code);
extern bool of_STORE_PROP_QF_STR(vthread_t thr, vvp_code_t code);
extern bool of_STORE_PROP_QF_V(vthread_t thr, vvp_code_t code);
extern bool of_QINSERT_PROP_R(vthread_t thr, vvp_code_t code);
extern bool of_QINSERT_PROP_STR(vthread_t thr, vvp_code_t code);
extern bool of_QINSERT_PROP_V(vthread_t thr, vvp_code_t code);
extern bool of_QPOP_PROP_B_REAL(vthread_t thr, vvp_code_t code);
extern bool of_QPOP_PROP_B_STR(vthread_t thr, vvp_code_t code);
extern bool of_QPOP_PROP_B_V(vthread_t thr, vvp_code_t code);
extern bool of_QPOP_PROP_F_REAL(vthread_t thr, vvp_code_t code);
extern bool of_QPOP_PROP_F_STR(vthread_t thr, vvp_code_t code);
extern bool of_QPOP_PROP_F_V(vthread_t thr, vvp_code_t code);
extern bool of_PROP_QUEUE_SIZE(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_APPEND_WORD_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_NEW_EMPTY_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_PRODUCT_PROP_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_PRODUCT_OBJ_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_PRODUCT_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_SIZE_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_SUM_OBJ_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_SUM_PROP_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_SUM_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_WORD_PROP_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_WORD_V(vthread_t thr, vvp_code_t code);
extern bool of_CMPIX_LTU(vthread_t thr, vvp_code_t code);
extern bool of_CMPIX_SLT0(vthread_t thr, vvp_code_t code);
extern bool of_PUSH_IX_VEC4(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_FIND_INDEX_PROP_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_FIND_INDEX_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_FIND_PROP_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_FIND_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_FIND_FIRST_INDEX_PROP_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_FIND_FIRST_INDEX_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_FIND_FIRST_PROP_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_FIND_FIRST_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_FIND_LAST_INDEX_PROP_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_FIND_LAST_INDEX_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_FIND_LAST_PROP_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_FIND_LAST_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_MIN_PROP_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_MIN_OBJ_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_MIN_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_MAX_PROP_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_MAX_OBJ_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_MAX_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_UNIQUE_OBJ_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_UNIQUE_INDEX_OBJ_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_UNIQUE_INDEX_PROP_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_UNIQUE_INDEX_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_UNIQUE_PROP_V(vthread_t thr, vvp_code_t code);
extern bool of_QUEUE_UNIQUE_V(vthread_t thr, vvp_code_t code);
extern bool of_DELETE_PROP_ELEM(vthread_t thr, vvp_code_t code);
extern bool of_DELETE_PROP_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_STORE_QB_R(vthread_t thr, vvp_code_t code);
extern bool of_STORE_QB_STR(vthread_t thr, vvp_code_t code);
extern bool of_STORE_QB_V(vthread_t thr, vvp_code_t code);

View File

@ -48,9 +48,13 @@ unsigned compile_errors = 0;
/*
* The opcode table lists all the code mnemonics, along with their
* opcode and operand types. The table is written sorted by mnemonic
* so that it can be searched by binary search. The opcode_compare
* function is a helper function for that lookup.
* opcode and operand types. The table must be sorted lexicographically
* by mnemonic string: compile_code() uses bsearch() on this array.
* If the order is wrong, lookup fails and the assembler reports
* "Invalid opcode" for otherwise valid instructions (e.g. class
* property queue ops must sort among all %delete/*, %qpop/*, %store/*
* names, not grouped by feature).
* The opcode_compare function is a helper for that lookup.
*/
enum operand_e {
@ -135,6 +139,8 @@ static const struct opcode_table_s opcode_table[] = {
{ "%cmpi/ne", of_CMPINE, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmpi/s", of_CMPIS, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmpi/u", of_CMPIU, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmpix/ltu", of_CMPIX_LTU, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%cmpix/slt0", of_CMPIX_SLT0, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%concat/str", of_CONCAT_STR, 0,{OA_NONE, OA_NONE, OA_NONE} },
{ "%concat/vec4", of_CONCAT_VEC4, 0,{OA_NONE, OA_NONE, OA_NONE} },
{ "%concati/str", of_CONCATI_STR, 1,{OA_STRING,OA_NONE, OA_NONE} },
@ -151,6 +157,8 @@ static const struct opcode_table_s opcode_table[] = {
{ "%delayx", of_DELAYX, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%delete/elem",of_DELETE_ELEM,1,{OA_FUNC_PTR,OA_NONE,OA_NONE} },
{ "%delete/obj",of_DELETE_OBJ,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
{ "%delete/prop/elem", of_DELETE_PROP_ELEM, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%delete/prop/obj", of_DELETE_PROP_OBJ, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%delete/tail",of_DELETE_TAIL,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
{ "%disable", of_DISABLE, 1, {OA_VPI_PTR,OA_NONE, OA_NONE} },
{ "%disable/flow", of_DISABLE_FLOW, 1, {OA_VPI_PTR,OA_NONE, OA_NONE} },
@ -204,6 +212,7 @@ static const struct opcode_table_s opcode_table[] = {
{ "%load/dar/vec4",of_LOAD_DAR_VEC4,1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%load/obj", of_LOAD_OBJ, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
{ "%load/obja", of_LOAD_OBJA, 2,{OA_ARR_PTR, OA_BIT1, OA_NONE} },
{ "%load/prop/dar/vec4", of_LOAD_PROP_DAR_VEC4, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%load/real", of_LOAD_REAL, 1,{OA_VPI_PTR, OA_NONE, OA_NONE} },
{ "%load/str", of_LOAD_STR, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
{ "%load/stra", of_LOAD_STRA, 2,{OA_ARR_PTR, OA_BIT1, OA_NONE} },
@ -241,14 +250,19 @@ static const struct opcode_table_s opcode_table[] = {
{ "%pow/s", of_POW_S, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%pow/wr", of_POW_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%prop/obj",of_PROP_OBJ,2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%prop/queue/size", of_PROP_QUEUE_SIZE, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%prop/r", of_PROP_R, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%prop/str",of_PROP_STR,1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%prop/v", of_PROP_V, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%push/ix/vec4", of_PUSH_IX_VEC4, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
{ "%pushi/real",of_PUSHI_REAL,2,{OA_BIT1, OA_BIT2, OA_NONE} },
{ "%pushi/str", of_PUSHI_STR, 1,{OA_STRING, OA_NONE, OA_NONE} },
{ "%pushi/vec4",of_PUSHI_VEC4,3,{OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%pushv/str", of_PUSHV_STR, 0,{OA_NONE, OA_NONE, OA_NONE} },
{ "%putc/str/vec4",of_PUTC_STR_VEC4,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
{ "%qinsert/prop/r", of_QINSERT_PROP_R, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%qinsert/prop/str", of_QINSERT_PROP_STR, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%qinsert/prop/v", of_QINSERT_PROP_V, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
{ "%qinsert/real",of_QINSERT_REAL,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
{ "%qinsert/str", of_QINSERT_STR, 2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
{ "%qinsert/v", of_QINSERT_V, 3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
@ -258,6 +272,47 @@ static const struct opcode_table_s opcode_table[] = {
{ "%qpop/f/real",of_QPOP_F_REAL,1,{OA_FUNC_PTR,OA_NONE,OA_NONE} },
{ "%qpop/f/str", of_QPOP_F_STR, 1,{OA_FUNC_PTR,OA_NONE,OA_NONE} },
{ "%qpop/f/v", of_QPOP_F_V, 2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
{ "%qpop/prop/b/r", of_QPOP_PROP_B_REAL, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%qpop/prop/b/str", of_QPOP_PROP_B_STR, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%qpop/prop/b/v", of_QPOP_PROP_B_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%qpop/prop/f/r", of_QPOP_PROP_F_REAL, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%qpop/prop/f/str", of_QPOP_PROP_F_STR, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%qpop/prop/f/v", of_QPOP_PROP_F_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%queue/append_word/v", of_QUEUE_APPEND_WORD_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
{ "%queue/find/index/prop/v", of_QUEUE_FIND_INDEX_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%queue/find/index/v", of_QUEUE_FIND_INDEX_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%queue/find/prop/v", of_QUEUE_FIND_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%queue/find/v", of_QUEUE_FIND_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%queue/find_first/index/prop/v", of_QUEUE_FIND_FIRST_INDEX_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%queue/find_first/index/v", of_QUEUE_FIND_FIRST_INDEX_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%queue/find_first/prop/v", of_QUEUE_FIND_FIRST_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%queue/find_first/v", of_QUEUE_FIND_FIRST_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%queue/find_last/index/prop/v", of_QUEUE_FIND_LAST_INDEX_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%queue/find_last/index/v", of_QUEUE_FIND_LAST_INDEX_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%queue/find_last/prop/v", of_QUEUE_FIND_LAST_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%queue/find_last/v", of_QUEUE_FIND_LAST_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%queue/max/obj/v", of_QUEUE_MAX_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
{ "%queue/max/prop/v", of_QUEUE_MAX_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%queue/max/v", of_QUEUE_MAX_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%queue/min/obj/v", of_QUEUE_MIN_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
{ "%queue/min/prop/v", of_QUEUE_MIN_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%queue/min/v", of_QUEUE_MIN_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%queue/new_empty/v", of_QUEUE_NEW_EMPTY_V, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%queue/product/obj/v", of_QUEUE_PRODUCT_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
{ "%queue/product/prop/v", of_QUEUE_PRODUCT_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%queue/product/v", of_QUEUE_PRODUCT_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%queue/size/v", of_QUEUE_SIZE_V, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%queue/sum/obj/v", of_QUEUE_SUM_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
{ "%queue/sum/prop/v", of_QUEUE_SUM_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%queue/sum/v", of_QUEUE_SUM_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%queue/unique/index/obj/v", of_QUEUE_UNIQUE_INDEX_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
{ "%queue/unique/index/prop/v", of_QUEUE_UNIQUE_INDEX_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%queue/unique/index/v", of_QUEUE_UNIQUE_INDEX_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%queue/unique/obj/v", of_QUEUE_UNIQUE_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
{ "%queue/unique/prop/v", of_QUEUE_UNIQUE_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%queue/unique/v", of_QUEUE_UNIQUE_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%queue/word/prop/v", of_QUEUE_WORD_PROP_V, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
{ "%queue/word/v", of_QUEUE_WORD_V, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%release/net",of_RELEASE_NET,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
{ "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
{ "%release/wr", of_RELEASE_WR, 2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
@ -268,6 +323,10 @@ static const struct opcode_table_s opcode_table[] = {
{ "%retload/real",of_RETLOAD_REAL,1,{OA_NUMBER, OA_NONE,OA_NONE} },
{ "%retload/str", of_RETLOAD_STR, 1,{OA_NUMBER, OA_NONE,OA_NONE} },
{ "%retload/vec4",of_RETLOAD_VEC4,1,{OA_NUMBER, OA_NONE,OA_NONE} },
{ "%reverse/obj", of_REVERSE_OBJ, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%reverse/prop/obj", of_REVERSE_PROP_OBJ, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%rsort/obj", of_RSORT_OBJ, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%rsort/prop/obj", of_RSORT_PROP_OBJ, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%scopy", of_SCOPY, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%set/dar/obj/real",of_SET_DAR_OBJ_REAL,1,{OA_NUMBER,OA_NONE,OA_NONE} },
{ "%set/dar/obj/str", of_SET_DAR_OBJ_STR, 1,{OA_NUMBER,OA_NONE,OA_NONE} },
@ -275,6 +334,10 @@ static const struct opcode_table_s opcode_table[] = {
{ "%shiftl", of_SHIFTL, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%shiftr", of_SHIFTR, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%shiftr/s", of_SHIFTR_S, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%shuffle/obj", of_SHUFFLE_OBJ, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%shuffle/prop/obj", of_SHUFFLE_PROP_OBJ, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%sort/obj", of_SORT_OBJ, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%sort/prop/obj", of_SORT_PROP_OBJ, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%split/vec4", of_SPLIT_VEC4, 1,{OA_NUMBER, OA_NONE, OA_NONE} },
{ "%store/dar/r", of_STORE_DAR_R, 1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%store/dar/str", of_STORE_DAR_STR, 1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
@ -282,6 +345,12 @@ static const struct opcode_table_s opcode_table[] = {
{ "%store/obj", of_STORE_OBJ, 1, {OA_FUNC_PTR,OA_NONE, OA_NONE} },
{ "%store/obja", of_STORE_OBJA, 2, {OA_ARR_PTR, OA_BIT1, OA_NONE} },
{ "%store/prop/obj",of_STORE_PROP_OBJ,2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%store/prop/qb/r", of_STORE_PROP_QB_R, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%store/prop/qb/str", of_STORE_PROP_QB_STR, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%store/prop/qb/v", of_STORE_PROP_QB_V, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
{ "%store/prop/qf/r", of_STORE_PROP_QF_R, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%store/prop/qf/str", of_STORE_PROP_QF_STR, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%store/prop/qf/v", of_STORE_PROP_QF_V, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
{ "%store/prop/r", of_STORE_PROP_R, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%store/prop/str",of_STORE_PROP_STR,1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%store/prop/v", of_STORE_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },

View File

@ -344,6 +344,9 @@ class resolv_list_s {
*/
extern void functor_ref_lookup(vvp_net_t**ref, char*lab);
extern vpiHandle vpip_make_prop_queue_ref(char* class_label, unsigned prop_idx,
unsigned is_queue_flag);
/*
* This function schedules a lookup of the labeled instruction. The
* code points to a code structure that points to the instruction

View File

@ -272,6 +272,7 @@ inline uint64_t strtouint64(const char*str, char**endptr, int base)
"&A" { return K_A; }
"&APV" { return K_APV; }
"&PQ" { return K_PQ; }
"&PV" { return K_PV; }
"%"[.$_/a-zA-Z0-9]+ {

View File

@ -93,7 +93,7 @@ static struct __vpiModPath*modpath_dst = 0;
%token K_NET K_NET_S K_NET_R K_NET_2S K_NET_2U
%token K_NET8 K_NET8_2S K_NET8_2U K_NET8_S
%token K_PARAM_STR K_PARAM_L K_PARAM_REAL K_PART K_PART_PV
%token K_PART_V K_PART_V_S K_PORT K_PORT_INFO K_PV K_REDUCE_AND K_REDUCE_OR K_REDUCE_XOR
%token K_PART_V K_PART_V_S K_PORT K_PORT_INFO K_PQ K_PV K_REDUCE_AND K_REDUCE_OR K_REDUCE_XOR
%token K_REDUCE_NAND K_REDUCE_NOR K_REDUCE_XNOR K_REPEAT
%token K_RESOLV K_RTRAN K_RTRANIF0 K_RTRANIF1
%token K_SCOPE K_SFUNC K_SFUNC_E K_SHIFTL K_SHIFTR K_SHIFTRS
@ -1122,6 +1122,8 @@ symbol_access
{ $$ = vpip_make_PV($3, $5, $7); }
| K_APV '<' T_SYMBOL ',' T_NUMBER ',' T_NUMBER ',' T_NUMBER '>'
{ $$ = vpip_make_vthr_APV($3, $5, $7, $9); }
| K_PQ '<' T_SYMBOL ',' T_NUMBER ',' T_NUMBER '>'
{ $$ = vpip_make_prop_queue_ref($3, $5, $7); }
;
/* functor operands can only be a list of symbols. */

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