Merge 96ca470f55 into 6c52271afa
This commit is contained in:
commit
f1b86be9ac
|
|
@ -43,6 +43,7 @@ stamp-*-h
|
|||
/version_tag.h
|
||||
|
||||
# Directories
|
||||
/devel/
|
||||
autom4te.cache
|
||||
dep
|
||||
|
||||
|
|
|
|||
36
PExpr.cc
36
PExpr.cc
|
|
@ -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
39
PExpr.h
|
|
@ -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);
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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` |
|
||||
|
|
@ -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());
|
||||
|
|
|
|||
2421
elab_expr.cc
2421
elab_expr.cc
File diff suppressed because it is too large
Load Diff
|
|
@ -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())
|
||||
|
|
|
|||
274
elaborate.cc
274
elaborate.cc
|
|
@ -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");
|
||||
|
|
|
|||
22
eval_tree.cc
22
eval_tree.cc
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_call_chain_method1.v",
|
||||
"iverilog-args" : [ "-g2012" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "Classes are not supported",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
|
|
@ -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" ]
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_darray_product.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "SystemVerilog dynamic array product() reduction",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_darray_reverse.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "SystemVerilog dynamic array reverse()",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_darray_sum.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "SystemVerilog dynamic array sum() reduction",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_darray_unique.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "SystemVerilog dynamic array unique methods",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_queue_find.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "SystemVerilog queues",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_queue_find_with.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "SystemVerilog queues",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_queue_product.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "SystemVerilog queue product() reduction",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_queue_reverse.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "SystemVerilog queue reverse()",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_queue_sort.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "SystemVerilog queue sort/rsort/shuffle",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_queue_sum.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "SystemVerilog queue sum() reduction",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_queue_unique.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "SystemVerilog queues",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
17
netdarray.cc
17
netdarray.cc
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ("
|
||||
|
|
|
|||
69
netmisc.cc
69
netmisc.cc
|
|
@ -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
73
parse.y
|
|
@ -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();
|
||||
|
|
|
|||
18
pform.cc
18
pform.cc
|
|
@ -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)
|
||||
|
|
|
|||
4
pform.h
4
pform.h
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
14
t-dll-api.cc
14
t-dll-api.cc
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
65
vvp/codes.h
65
vvp/codes.h
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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} },
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]+ {
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue